generated from rwxrob/compfoo
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
compfile.go
82 lines (69 loc) · 2 KB
/
compfile.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright 2022 Robert S. Muhlestein.
// SPDX-License-Identifier: Apache-2.0
/*
Package compfile is a completion driver for Bonzai command trees and
fulfills the bonzai.Completer. See Complete method for details.
*/
package compfile
import (
"path/filepath"
"strings"
"github.com/rwxrob/bonzai"
"github.com/rwxrob/fn/filt"
"github.com/rwxrob/fs"
"github.com/rwxrob/fs/dir"
)
// New returns a pointer to a struct that fulfills bonzai.Completer.
// This can be called from within Z.Cmd assignment:
//
// var Cmd = &Z.Cmd{
// Name: `some`,
// Comp: compfile.New(),
// }
//
func New() *comp { return new(comp) }
// comp fulfills the bonzai.Completer interface.
type comp struct{}
// Complete returns all file names for the directory and file prefix passed.
// If nothing is passed assumes the current working directory. This
// completer is roughly based on the behavior of the bash shell with
// forward slashes as separators and escaped spaces. By using this
// completer (instead of the shell) the command line interface remains
// consistent across all runtimes. Note that unlike bash completion no
// indication of the type of file is provided.
func (comp) Complete(x bonzai.Command, args ...string) []string {
if len(args) > 1 {
return []string{}
}
if args == nil || (len(args) > 0 && args[0] == "") {
return dir.EntriesWithSlash(".")
}
// catch edge cases
if len(args) == 0 {
if x != nil {
return []string{x.GetName()} // will add tailing space
}
return dir.EntriesWithSlash("")
}
first := strings.TrimRight(args[0], string(filepath.Separator))
d, pre := filepath.Split(first)
if d == "" {
list := filt.HasPrefix(dir.Entries("."), pre)
if len(list) == 1 && fs.IsDir(list[0]) {
return dir.EntriesWithSlash(list[0])
}
return dir.AddSlash(list)
}
for {
list := filt.BaseHasPrefix(dir.Entries(d), pre)
if len(list) > 1 {
return dir.AddSlash(list)
}
if fs.IsDir(list[0]) {
d = list[0]
continue
}
return dir.AddSlash(list)
}
return []string{}
}