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 }