Skip to content

Commit 85e85fd

Browse files
committed
Merge branch 'readline_keys'
2 parents 63f291e + 8127fd5 commit 85e85fd

File tree

3 files changed

+120
-12
lines changed

3 files changed

+120
-12
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Please keep the contents of this file sorted alphabetically.
22

3+
Calum MacRae <[email protected]>
34
Mateusz Czapliński <[email protected]>
45
Rohan Verma <[email protected]>

up.go

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import (
3636
"github.com/spf13/pflag"
3737
)
3838

39-
const version = "0.3.1 (2018-10-31)"
39+
const version = "0.3.2 (2018-12-04)"
4040

4141
// TODO: in case of error, show it in red (bg?), then below show again initial normal output (see also #4)
4242
// TODO: F1 should display help, and it should be multi-line, and scrolling licensing credits
@@ -283,9 +283,10 @@ func NewEditor(prompt string) *Editor {
283283

284284
type Editor struct {
285285
// TODO: make editor multiline. Reuse gocui or something for this?
286-
prompt []rune
287-
value []rune
288-
cursor int
286+
prompt []rune
287+
value []rune
288+
killspace []rune
289+
cursor int
289290
// lastw is length of value on last Draw; we need it to know how much to erase after backspace
290291
lastw int
291292
}
@@ -326,27 +327,43 @@ func (e *Editor) HandleKey(ev *tcell.EventKey) bool {
326327
e.delete(-1)
327328
case key(tcell.KeyDelete):
328329
e.delete(0)
329-
case key(tcell.KeyLeft):
330+
case key(tcell.KeyLeft),
331+
key(tcell.KeyCtrlB),
332+
ctrlKey(tcell.KeyCtrlB):
330333
if e.cursor > 0 {
331334
e.cursor--
332335
}
333-
case key(tcell.KeyRight):
336+
case key(tcell.KeyRight),
337+
key(tcell.KeyCtrlF),
338+
ctrlKey(tcell.KeyCtrlF):
334339
if e.cursor < len(e.value) {
335340
e.cursor++
336341
}
342+
case key(tcell.KeyCtrlA),
343+
ctrlKey(tcell.KeyCtrlA):
344+
e.cursor = 0
345+
case key(tcell.KeyCtrlE),
346+
ctrlKey(tcell.KeyCtrlE):
347+
e.cursor = len(e.value)
348+
case key(tcell.KeyCtrlK),
349+
ctrlKey(tcell.KeyCtrlK):
350+
e.kill()
351+
case key(tcell.KeyCtrlY),
352+
ctrlKey(tcell.KeyCtrlY):
353+
e.insert(e.killspace...)
337354
default:
338355
// Unknown key/combination, not handled
339356
return false
340357
}
341358
return true
342359
}
343360

344-
func (e *Editor) insert(ch rune) {
345-
// Insert character into value (https://github.com/golang/go/wiki/SliceTricks#insert)
346-
e.value = append(e.value, 0)
347-
copy(e.value[e.cursor+1:], e.value[e.cursor:])
348-
e.value[e.cursor] = ch
349-
e.cursor++
361+
func (e *Editor) insert(ch ...rune) {
362+
// Based on https://github.com/golang/go/wiki/SliceTricks#insert
363+
e.value = append(e.value, ch...) // = PREFIX + SUFFIX + (filler)
364+
copy(e.value[e.cursor+len(ch):], e.value[e.cursor:]) // = PREFIX + (filler) + SUFFIX
365+
copy(e.value[e.cursor:], ch) // = PREFIX + ch + SUFFIX
366+
e.cursor += len(ch)
350367
}
351368

352369
func (e *Editor) delete(dx int) {
@@ -358,6 +375,13 @@ func (e *Editor) delete(dx int) {
358375
e.cursor = pos
359376
}
360377

378+
func (e *Editor) kill() {
379+
if e.cursor != len(e.value) {
380+
e.killspace = append(e.killspace[:0], e.value[e.cursor:]...)
381+
}
382+
e.value = e.value[:e.cursor]
383+
}
384+
361385
type BufView struct {
362386
// TODO: Wrap bool
363387
Y int // Y of the view in the Buf, for down/up scrolling

up_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package main
2+
3+
import "testing"
4+
5+
func Test_Editor_insert(test *testing.T) {
6+
cases := []struct {
7+
comment string
8+
e Editor
9+
insert []rune
10+
wantValue []rune
11+
}{
12+
{
13+
comment: "prepend ASCII char",
14+
e: Editor{
15+
value: []rune(`abc`),
16+
cursor: 0,
17+
},
18+
insert: []rune{'X'},
19+
wantValue: []rune(`Xabc`),
20+
},
21+
{
22+
comment: "prepend UTF char",
23+
e: Editor{
24+
value: []rune(`abc`),
25+
cursor: 0,
26+
},
27+
insert: []rune{'☃'},
28+
wantValue: []rune(`☃abc`),
29+
},
30+
{
31+
comment: "insert ASCII char",
32+
e: Editor{
33+
value: []rune(`abc`),
34+
cursor: 1,
35+
},
36+
insert: []rune{'X'},
37+
wantValue: []rune(`aXbc`),
38+
},
39+
{
40+
comment: "insert UTF char",
41+
e: Editor{
42+
value: []rune(`abc`),
43+
cursor: 1,
44+
},
45+
insert: []rune{'☃'},
46+
wantValue: []rune(`a☃bc`),
47+
},
48+
{
49+
comment: "append ASCII char",
50+
e: Editor{
51+
value: []rune(`abc`),
52+
cursor: 3,
53+
},
54+
insert: []rune{'X'},
55+
wantValue: []rune(`abcX`),
56+
},
57+
{
58+
comment: "append UTF char",
59+
e: Editor{
60+
value: []rune(`abc`),
61+
cursor: 3,
62+
},
63+
insert: []rune{'☃'},
64+
wantValue: []rune(`abc☃`),
65+
},
66+
{
67+
comment: "insert 2 ASCII chars",
68+
e: Editor{
69+
value: []rune(`abc`),
70+
cursor: 1,
71+
},
72+
insert: []rune{'X', 'Y'},
73+
wantValue: []rune(`aXYbc`),
74+
},
75+
}
76+
77+
for _, c := range cases {
78+
c.e.insert(c.insert...)
79+
if string(c.e.value) != string(c.wantValue) {
80+
test.Errorf("%q: bad value\nwant: %q\nhave: %q", c.comment, c.wantValue, c.e.value)
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)