package atom import ( "bufio" "io" "strconv" "time" ) func timeout() <-chan time.Time { return time.After(50 * time.Millisecond) } type input struct { buf *bufio.Reader next <-chan nchar pending []Char } func (in *input) shift() (r Char) { if len(in.pending) > 0 { r, in.pending = in.pending[0], in.pending[1:] } return } func (in *input) push(r Char) Char { in.pending = append(in.pending, r) return r } func (in *input) clear() { in.pending = in.pending[:0] } func (in *input) readRune() nchar { if r, _, err := in.buf.ReadRune(); err != nil { return ec(err) } else { return nc(r) } } func newInput(r io.Reader) *input { return &input{ buf: bufio.NewReader(r), } } func (in *input) restart() { next := make(chan nchar, 200) go func() { for { n := in.readRune() next <- n needClose := !n.IsOk() if !needClose { r, ok := n.Ok() needClose = ok && (r == Lf || r == Cr || r == C_C || r == C_D) } if needClose { close(next) return } } }() in.next = next } func (in *input) isWaiting() bool { return len(in.next) > 0 } func (in *input) nextc() (n nchar) { var ok bool select { case n, ok = <-in.next: if !ok { return ec(ErrInternal) } if r, ok := n.Ok(); ok { in.push(r) return nc(r) } } return } func (in *input) nextt() (n nchar) { var ok bool select { case n, ok = <-in.next: if !ok { return ec(ErrInternal) if r, ok := n.Ok(); ok { in.push(r) return nc(r) } } case <-timeout(): return ec(ErrTimeout) } return } func (in *input) escO() (key nkey) { key = nk(KeyNil) n := in.nextt() if err, ok := n.Err(); ok { if err == ErrTimeout { return nk(keyS(AS_O)) } return ek(err) } r, ok := n.Ok() if !ok { return } var s Sequence if r >= '0' && r < '9' { s = Sequence(r << 8) n = in.nextt() if err, ok := n.Err(); ok { if err == ErrTimeout { return } return ek(err) } r, _ = n.Ok() } s |= Sequence(r) return nk(keyS(s)) } func (in *input) escBracket() (key nkey) { key = nk(KeyNil) n := in.nextt() if err, ok := n.Err(); ok { if err == ErrTimeout { return } return ek(err) } r, ok := n.Ok() if !ok { return } var s Sequence switch r { case 'A': s = Up case 'B': s = Down case 'C': s = Right case 'D': s = Left case 'F': s = End case 'H': s = Home case 'Z': s = S_Tab case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': return in.escNumberBracket(r) default: } return nk(keyS(s)) } func (in *input) escNumberBracket(r Char) (key nkey) { key = nk(KeyNil) num := []Char{r} for { n := in.nextt() if err, ok := n.Err(); ok { if err == ErrTimeout { return } return ek(err) } r, ok := n.Ok() if !ok { return } switch r { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': num = append(num, r) case '~': return in.escTildeBracket(num) case ';': return in.escSemiColonBracket(num) default: return } } return } func (in *input) escTildeBracket(num []Char) (key nkey) { x, _ := strconv.ParseInt(string(num), 10, 32) s := Sequence(x) return nk(keyS(s)) } func (in *input) escSemiColonBracket(num []Char) (key nkey) { key = nk(KeyNil) x, _ := strconv.ParseInt(string(num), 10, 32) seqn := x != 1 var s Sequence if seqn { s = Sequence(x) } n := in.nextt() if err, ok := n.Err(); ok { if err == ErrTimeout { return } return ek(err) } r, ok := n.Ok() if !ok { return } s |= Sequence(r << 8) n = in.nextt() if err, ok := n.Err(); ok { if err == ErrTimeout { return } return ek(err) } r, ok = n.Ok() if !ok { return } if r == '~' { if !seqn { return nk(KeyNil) } } else if !seqn { s |= Sequence(r) } else { return } return nk(keyS(s)) } func (in *input) nextChar() (key nkey) { key = nk(KeyNil) if len(in.pending) > 0 { r := in.shift() return nk(keyC(r)) } n := in.nextc() if err, ok := n.Err(); ok { in.shift() return ek(err) } r, ok := n.Ok() if !ok { return } if r != Esc { in.shift() return nk(keyC(r)) } n = in.nextt() if err, ok := n.Err(); ok { if err == ErrTimeout { return } return ek(err) } r, ok = n.Ok() if !ok { return } var s Sequence switch r { case Bs: s = A_Bs case 'O': return in.escO() case '[': return in.escBracket() case 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z': s = Sequence(r << 16) default: return } in.clear() return nk(keyS(s)) }