src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

input.go (4512B)


      1 package input
      2 
      3 import (
      4 	"bufio"
      5 	"context"
      6 	"fmt"
      7 	"os"
      8 	"unicode/utf8"
      9 
     10 	"code.dwrz.net/src/pkg/log"
     11 )
     12 
     13 type Event struct {
     14 	Key  Key
     15 	Rune rune
     16 }
     17 
     18 type Reader struct {
     19 	buf    *bufio.Reader
     20 	events chan *Event
     21 	log    *log.Logger
     22 }
     23 
     24 type Parameters struct {
     25 	Chan chan *Event
     26 	In   *os.File
     27 	Log  *log.Logger
     28 }
     29 
     30 func New(p Parameters) *Reader {
     31 	return &Reader{
     32 		buf:    bufio.NewReader(p.In),
     33 		events: p.Chan,
     34 		log:    p.Log,
     35 	}
     36 }
     37 
     38 // TODO: reading one rune at a time is slow, especially when pasting large
     39 // quantities of text into the active buffer. It would be nice to take more
     40 // input at once, while still being able to handle escape sequences without
     41 // too many edge cases.
     42 func (i *Reader) Run(ctx context.Context) error {
     43 	for {
     44 		select {
     45 		case <-ctx.Done():
     46 			return nil
     47 		default:
     48 			r, size, err := i.buf.ReadRune()
     49 			if err != nil {
     50 				return fmt.Errorf("failed to read: %w", err)
     51 			}
     52 			i.log.Debug.Printf(
     53 				"read rune %s %v (%d)",
     54 				string(r), []byte(string(r)), size,
     55 			)
     56 			switch r {
     57 			case utf8.RuneError:
     58 				i.log.Error.Printf(
     59 					"rune error: %s (%d)", string(r), size,
     60 				)
     61 
     62 				// Handle escape sequences.
     63 			case Escape:
     64 				if err := i.parseEscapeSequence(); err != nil {
     65 					return fmt.Errorf(
     66 						"failed to read: %w", err,
     67 					)
     68 				}
     69 
     70 			default:
     71 				i.events <- &Event{Rune: r}
     72 			}
     73 		}
     74 	}
     75 }
     76 
     77 func (i *Reader) parseEscapeSequence() error {
     78 	r1, _, err := i.buf.ReadRune()
     79 	if err != nil {
     80 		return fmt.Errorf("failed to read: %w", err)
     81 	}
     82 
     83 	// Ignore invalid escape sequences.
     84 	if r1 != '[' && r1 != 'O' {
     85 		i.events <- &Event{Rune: r1}
     86 		return nil
     87 	}
     88 
     89 	// We've received an input of Esc + [ or Esc + O.
     90 	// Determine the escape sequence.
     91 	r2, _, err := i.buf.ReadRune()
     92 	if err != nil {
     93 		return fmt.Errorf("failed to read: %w", err)
     94 
     95 	}
     96 
     97 	// Check letter escape sequences.
     98 	switch r2 {
     99 	case 'A':
    100 		i.events <- &Event{Key: Up}
    101 		return nil
    102 	case 'B':
    103 		i.events <- &Event{Key: Down}
    104 		return nil
    105 	case 'C':
    106 		i.events <- &Event{Key: Right}
    107 		return nil
    108 	case 'D':
    109 		i.events <- &Event{Key: Left}
    110 		return nil
    111 
    112 	case 'O':
    113 		r3, _, err := i.buf.ReadRune()
    114 		if err != nil {
    115 			return fmt.Errorf("failed to read: %w", err)
    116 		}
    117 		switch r3 {
    118 		case 'P': // F1
    119 			return nil
    120 		case 'Q': // F2
    121 			return nil
    122 		case 'R': // F3
    123 			return nil
    124 		case 'S': // F4
    125 			return nil
    126 		default:
    127 			// No match.
    128 			i.events <- &Event{Rune: r1}
    129 			i.events <- &Event{Rune: r2}
    130 			i.events <- &Event{Rune: r3}
    131 			return nil
    132 		}
    133 	}
    134 
    135 	// Check for single digit numerical escape sequences.
    136 	r3, _, err := i.buf.ReadRune()
    137 	if err != nil {
    138 		return fmt.Errorf("failed to read: %w", err)
    139 	}
    140 	switch {
    141 	case r2 == '1' && r3 == '~':
    142 		i.events <- &Event{Key: Home}
    143 		return nil
    144 	case r2 == '2' && r3 == '~':
    145 		i.events <- &Event{Key: Insert}
    146 		return nil
    147 	case r2 == '3' && r3 == '~':
    148 		i.events <- &Event{Rune: Delete}
    149 		return nil
    150 	case r2 == '4' && r3 == '~':
    151 		i.events <- &Event{Key: End}
    152 		return nil
    153 	case r2 == '5' && r3 == '~':
    154 		i.events <- &Event{Key: PageUp}
    155 		return nil
    156 	case r2 == '6' && r3 == '~':
    157 		i.events <- &Event{Key: PageDown}
    158 		return nil
    159 	case r2 == '7' && r3 == '~':
    160 		i.events <- &Event{Key: Home}
    161 		return nil
    162 	case r2 == '8' && r3 == '~':
    163 		i.events <- &Event{Key: End}
    164 		return nil
    165 	case r2 == '9' && r3 == '~':
    166 		i.events <- &Event{Key: End}
    167 		return nil
    168 	}
    169 
    170 	// Check for double digit numerical escape sequences.
    171 	r4, _, err := i.buf.ReadRune()
    172 	if err != nil {
    173 		return fmt.Errorf("failed to read: %w", err)
    174 	}
    175 	switch {
    176 	case r2 == '1' && r3 == '0' && r4 == '~':
    177 		return nil
    178 	case r2 == '1' && r3 == '1' && r4 == '~':
    179 		return nil
    180 	case r2 == '1' && r3 == '2' && r4 == '~':
    181 		return nil
    182 	case r2 == '1' && r3 == '3' && r4 == '~':
    183 		return nil
    184 	case r2 == '1' && r3 == '4' && r4 == '~':
    185 		return nil
    186 	case r2 == '1' && r3 == '4' && r4 == '~':
    187 		return nil
    188 	case r2 == '1' && r3 == '6' && r4 == '~':
    189 		return nil
    190 	case r2 == '1' && r3 == '7' && r4 == '~':
    191 		return nil
    192 	case r2 == '1' && r3 == '8' && r4 == '~':
    193 		return nil
    194 	case r2 == '1' && r3 == '9' && r4 == '~':
    195 		return nil
    196 	case r2 == '2' && r3 == '0' && r4 == '~':
    197 		return nil
    198 	case r2 == '2' && r3 == '1' && r4 == '~':
    199 		return nil
    200 	case r2 == '2' && r3 == '2' && r4 == '~':
    201 		return nil
    202 	case r2 == '2' && r3 == '3' && r4 == '~':
    203 		return nil
    204 	case r2 == '2' && r3 == '4' && r4 == '~':
    205 		return nil
    206 	case r4 == '~':
    207 		return nil
    208 	}
    209 
    210 	// No match.
    211 	i.events <- &Event{Rune: r1}
    212 	i.events <- &Event{Rune: r2}
    213 	i.events <- &Event{Rune: r3}
    214 	i.events <- &Event{Rune: r4}
    215 
    216 	return nil
    217 }