@@ -5,13 +5,16 @@ import (
5
5
"path/filepath"
6
6
"slices"
7
7
"strings"
8
+ "unicode"
9
+ "unicode/utf8"
8
10
9
11
"github.com/itchyny/bed/event"
10
12
)
11
13
12
14
type completor struct {
13
15
fs fs
14
16
env env
17
+ command bool
15
18
target string
16
19
arg string
17
20
results []string
@@ -22,24 +25,24 @@ func newCompletor(fs fs, env env) *completor {
22
25
return & completor {fs : fs , env : env }
23
26
}
24
27
25
- func (c * completor ) clear () {
26
- c .target = ""
27
- c .arg = ""
28
- c .results = nil
29
- c .index = 0
30
- }
31
-
32
28
func (c * completor ) complete (cmdline string , forward bool ) string {
33
- cmd , _ , _ , prefix , arg , _ := parse (cmdline )
29
+ cmd , r , _ , name , prefix , arg , _ := parse (cmdline )
30
+ if name == "" || c .command ||
31
+ ! hasSuffixFunc (prefix , unicode .IsSpace ) && cmd .fullname != name {
32
+ cmdline = c .completeCommand (cmdline , name , prefix , r , forward )
33
+ if c .results != nil {
34
+ return cmdline
35
+ }
36
+ prefix = cmdline
37
+ }
34
38
switch cmd .eventType {
35
39
case event .Edit , event .New , event .Vnew , event .Write :
36
- return c .completeFilepaths (cmdline , prefix , arg , forward , false )
40
+ return c .completeFilepath (cmdline , prefix , arg , forward , false )
37
41
case event .Chdir :
38
- return c .completeFilepaths (cmdline , prefix , arg , forward , true )
42
+ return c .completeFilepath (cmdline , prefix , arg , forward , true )
39
43
case event .Wincmd :
40
44
return c .completeWincmd (cmdline , prefix , arg , forward )
41
45
default :
42
- c .clear ()
43
46
return cmdline
44
47
}
45
48
}
@@ -53,35 +56,45 @@ func (c *completor) completeNext(prefix string, forward bool) string {
53
56
if c .index < 0 {
54
57
return c .target
55
58
}
59
+ if len (c .results ) == 1 {
60
+ defer c .clear ()
61
+ }
56
62
return prefix + c .arg + c .results [c .index ]
57
63
}
58
64
59
- func (c * completor ) completeFilepaths (
60
- cmdline , prefix , arg string , forward , dirOnly bool ,
65
+ func (c * completor ) completeCommand (
66
+ cmdline , name , prefix string , r * event. Range , forward bool ,
61
67
) string {
62
- if ! strings .HasSuffix (prefix , " " ) {
63
- prefix += " "
68
+ prefix = prefix [:len (prefix )- len (name )]
69
+ if c .results == nil {
70
+ c .command , c .target , c .index = true , cmdline , - 1
71
+ c .arg , c .results = "" , c .listCommandNames (name , r )
64
72
}
65
- if len (c .results ) > 0 {
66
- return c .completeNext (prefix , forward )
73
+ return c .completeNext (prefix , forward )
74
+ }
75
+
76
+ func (* completor ) listCommandNames (name string , r * event.Range ) []string {
77
+ var targets []string
78
+ for _ , cmd := range commands {
79
+ if strings .HasPrefix (cmd .fullname , name ) && cmd .rangeType .allows (r ) {
80
+ targets = append (targets , cmd .fullname )
81
+ }
67
82
}
68
- c .target = cmdline
69
- c .index = 0
70
- c .arg , c .results = c .listFileNames (arg , dirOnly )
71
- if len (c .results ) == 1 {
72
- cmdline := prefix + c .arg + c .results [0 ]
73
- c .results = nil
74
- return cmdline
83
+ slices .Sort (targets )
84
+ return targets
85
+ }
86
+
87
+ func (c * completor ) completeFilepath (
88
+ cmdline , prefix , arg string , forward , dirOnly bool ,
89
+ ) string {
90
+ if ! hasSuffixFunc (prefix , unicode .IsSpace ) {
91
+ prefix += " "
75
92
}
76
- if len (c .results ) > 1 {
77
- if forward {
78
- c .index = 0
79
- return prefix + c .arg + c .results [0 ]
80
- }
81
- c .index = len (c .results ) - 1
82
- return prefix + c .arg + c .results [len (c .results )- 1 ]
93
+ if c .results == nil {
94
+ c .command , c .target , c .index = false , cmdline , - 1
95
+ c .arg , c .results = c .listFileNames (arg , dirOnly )
83
96
}
84
- return cmdline
97
+ return c . completeNext ( prefix , forward )
85
98
}
86
99
87
100
const separator = string (filepath .Separator )
@@ -224,17 +237,25 @@ func (c *completor) expandPath(path string) (string, func(string) string) {
224
237
}
225
238
226
239
func (c * completor ) completeWincmd (cmdline , prefix , arg string , forward bool ) string {
227
- if ! strings . HasSuffix (prefix , " " ) {
240
+ if ! hasSuffixFunc (prefix , unicode . IsSpace ) {
228
241
prefix += " "
229
242
}
230
- if len (c .results ) > 0 {
231
- return c .completeNext (prefix , forward )
232
- }
233
- if len (arg ) > 0 {
234
- return cmdline
243
+ if c .results == nil {
244
+ if len (arg ) > 0 {
245
+ return cmdline
246
+ }
247
+ c .command , c .target , c .arg , c .index = false , cmdline , "" , - 1
248
+ c .results = strings .Split ("nohjkltbpHJKL" , "" )
235
249
}
236
- c .target = cmdline
237
- c .results = []string {"n" , "h" , "l" , "k" , "j" , "H" , "L" , "K" , "J" , "t" , "b" , "p" }
238
- c .index = - 1
239
- return cmdline
250
+ return c .completeNext (prefix , forward )
251
+ }
252
+
253
+ func (c * completor ) clear () {
254
+ c .command , c .target , c .arg = false , "" , ""
255
+ c .results , c .index = nil , 0
256
+ }
257
+
258
+ func hasSuffixFunc (s string , f func (rune ) bool ) bool {
259
+ r , _ := utf8 .DecodeLastRuneInString (s )
260
+ return f (r )
240
261
}
0 commit comments