/
complete_command.go
97 lines (86 loc) · 2.83 KB
/
complete_command.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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package completion
import (
"strings"
"github.com/u-root/u-root/cmds/core/elvish/edit/ui"
"github.com/u-root/u-root/cmds/core/elvish/eval"
"github.com/u-root/u-root/cmds/core/elvish/parse"
"github.com/u-root/u-root/cmds/core/elvish/util"
)
type commandComplContext struct {
complContextCommon
}
const quotingForEmptySeed = parse.Bareword
func findCommandComplContext(n parse.Node, ev pureEvaler) complContext {
// Determine if we are starting a new command. There are 3 cases:
// 1. The whole chunk is empty (nothing entered at all): the leaf is a
// Chunk.
// 2. Just after a newline or semicolon: the leaf is a Sep and its parent is
// a Chunk.
// 3. Just after a pipe: the leaf is a Sep and its parent is a Pipeline.
if parse.IsChunk(n) {
return &commandComplContext{
complContextCommon{"", parse.Bareword, n.End(), n.End()}}
}
if parse.IsSep(n) {
parent := n.Parent()
switch {
case parse.IsChunk(parent), parse.IsPipeline(parent):
return &commandComplContext{
complContextCommon{"", quotingForEmptySeed, n.End(), n.End()}}
case parse.IsPrimary(parent):
ptype := parent.(*parse.Primary).Type
if ptype == parse.OutputCapture || ptype == parse.ExceptionCapture {
return &commandComplContext{
complContextCommon{"", quotingForEmptySeed, n.End(), n.End()}}
}
}
}
if primary, ok := n.(*parse.Primary); ok {
if compound, seed := primaryInSimpleCompound(primary, ev); compound != nil {
if form, ok := compound.Parent().(*parse.Form); ok {
if form.Head == compound {
return &commandComplContext{
complContextCommon{seed, primary.Type, compound.Begin(), compound.End()}}
}
}
}
}
return nil
}
func (*commandComplContext) name() string { return "command" }
func (ctx *commandComplContext) generate(env *complEnv, ch chan<- rawCandidate) error {
return complFormHeadInner(ctx.seed, env.evaler, ch)
}
func complFormHeadInner(head string, ev *eval.Evaler, rawCands chan<- rawCandidate) error {
if util.DontSearch(head) {
return complFilenameInner(head, true, rawCands)
}
got := func(s string) {
rawCands <- plainCandidate(s)
}
for special := range eval.IsBuiltinSpecial {
got(special)
}
explode, ns, _ := eval.ParseIncompleteVariableRef(head)
if !explode {
logger.Printf("completing commands in ns %q", ns)
ev.EachVariableInTop(ns, func(varname string) {
switch {
case strings.HasSuffix(varname, eval.FnSuffix):
got(eval.MakeVariableRef(false, ns, varname[:len(varname)-len(eval.FnSuffix)]))
case strings.HasSuffix(varname, eval.NsSuffix):
got(eval.MakeVariableRef(false, ns, varname))
default:
name := eval.MakeVariableRef(false, ns, varname)
rawCands <- &complexCandidate{name, " = ", " = ", ui.Styles{}}
}
})
}
eval.EachExternal(func(command string) {
got(command)
if strings.HasPrefix(head, "e:") {
got("e:" + command)
}
})
return nil
}