overlay.go RawHistoryFolder
1package daemon
2
3import (
4 "unicode"
5 "unicode/utf8"
6)
7
8type overlayEvents struct {
9 rune func(rune)
10 backspace func()
11 enter func()
12 tab func()
13 cancel func()
14 up func()
15 down func()
16 left func()
17 right func()
18}
19
20func routeOverlayBytes(data []byte, pending *[]byte, ev overlayEvents) {
21 if pending != nil && len(*pending) > 0 {
22 combined := make([]byte, 0, len(*pending)+len(data))
23 combined = append(combined, (*pending)...)
24 combined = append(combined, data...)
25 data = combined
26 *pending = nil
27 }
28
29 for i := 0; i < len(data); {
30 switch data[i] {
31 case 0x1b:
32 consumed, incomplete := routeOverlayEscape(data[i:], ev)
33 if incomplete {
34 if pending != nil {
35 *pending = append((*pending)[:0], data[i:]...)
36 }
37 return
38 }
39 if consumed > 0 {
40 i += consumed
41 continue
42 }
43 call(ev.cancel)
44 i++
45 case 0x03:
46 call(ev.cancel)
47 i++
48 case 0x0e:
49 call(ev.down)
50 i++
51 case 0x10:
52 call(ev.up)
53 i++
54 case '\r', '\n':
55 call(ev.enter)
56 i++
57 case 0x09:
58 call(ev.tab)
59 i++
60 case 0x7f, 0x08:
61 call(ev.backspace)
62 i++
63 default:
64 r, size := utf8.DecodeRune(data[i:])
65 if r == utf8.RuneError {
66 if !utf8.FullRune(data[i:]) {
67 if pending != nil {
68 *pending = append((*pending)[:0], data[i:]...)
69 }
70 return
71 }
72 i++
73 continue
74 }
75 if !unicode.IsControl(r) && ev.rune != nil {
76 ev.rune(r)
77 }
78 i += size
79 }
80 }
81}
82
83func routeOverlayEscape(data []byte, ev overlayEvents) (consumed int, incomplete bool) {
84 if len(data) < 2 {
85 return 0, false
86 }
87 switch data[1] {
88 case 'O':
89 if len(data) < 3 {
90 return 0, true
91 }
92 switch data[2] {
93 case 'A':
94 call(ev.up)
95 case 'B':
96 call(ev.down)
97 case 'C':
98 call(ev.right)
99 case 'D':
100 call(ev.left)
101 }
102 return 3, false
103 case '[':
104 for i := 2; i < len(data); i++ {
105 if data[i] < 0x40 || data[i] > 0x7e {
106 continue
107 }
108 if i == 2 {
109 switch data[i] {
110 case 'A':
111 call(ev.up)
112 case 'B':
113 call(ev.down)
114 case 'C':
115 call(ev.right)
116 case 'D':
117 call(ev.left)
118 }
119 }
120 return i + 1, false
121 }
122 return 0, true
123 default:
124 return 0, false
125 }
126}
127
128func call(fn func()) {
129 if fn != nil {
130 fn()
131 }
132}