github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/cmds/elvish/edit/completion/complete_command.go (about) 1 package completion 2 3 import ( 4 "strings" 5 6 "github.com/u-root/u-root/cmds/elvish/edit/ui" 7 8 "github.com/u-root/u-root/cmds/elvish/eval" 9 "github.com/u-root/u-root/cmds/elvish/parse" 10 "github.com/u-root/u-root/cmds/elvish/util" 11 ) 12 13 type commandComplContext struct { 14 complContextCommon 15 } 16 17 const quotingForEmptySeed = parse.Bareword 18 19 func findCommandComplContext(n parse.Node, ev pureEvaler) complContext { 20 // Determine if we are starting a new command. There are 3 cases: 21 // 1. The whole chunk is empty (nothing entered at all): the leaf is a 22 // Chunk. 23 // 2. Just after a newline or semicolon: the leaf is a Sep and its parent is 24 // a Chunk. 25 // 3. Just after a pipe: the leaf is a Sep and its parent is a Pipeline. 26 if parse.IsChunk(n) { 27 return &commandComplContext{ 28 complContextCommon{"", parse.Bareword, n.End(), n.End()}} 29 } 30 if parse.IsSep(n) { 31 parent := n.Parent() 32 switch { 33 case parse.IsChunk(parent), parse.IsPipeline(parent): 34 return &commandComplContext{ 35 complContextCommon{"", quotingForEmptySeed, n.End(), n.End()}} 36 case parse.IsPrimary(parent): 37 ptype := parent.(*parse.Primary).Type 38 if ptype == parse.OutputCapture || ptype == parse.ExceptionCapture { 39 return &commandComplContext{ 40 complContextCommon{"", quotingForEmptySeed, n.End(), n.End()}} 41 } 42 } 43 } 44 45 if primary, ok := n.(*parse.Primary); ok { 46 if compound, seed := primaryInSimpleCompound(primary, ev); compound != nil { 47 if form, ok := compound.Parent().(*parse.Form); ok { 48 if form.Head == compound { 49 return &commandComplContext{ 50 complContextCommon{seed, primary.Type, compound.Begin(), compound.End()}} 51 } 52 } 53 } 54 } 55 return nil 56 } 57 58 func (*commandComplContext) name() string { return "command" } 59 60 func (ctx *commandComplContext) generate(env *complEnv, ch chan<- rawCandidate) error { 61 return complFormHeadInner(ctx.seed, env.evaler, ch) 62 } 63 64 func complFormHeadInner(head string, ev *eval.Evaler, rawCands chan<- rawCandidate) error { 65 if util.DontSearch(head) { 66 return complFilenameInner(head, true, rawCands) 67 } 68 69 got := func(s string) { 70 rawCands <- plainCandidate(s) 71 } 72 for special := range eval.IsBuiltinSpecial { 73 got(special) 74 } 75 explode, ns, _ := eval.ParseIncompleteVariableRef(head) 76 if !explode { 77 logger.Printf("completing commands in ns %q", ns) 78 ev.EachVariableInTop(ns, func(varname string) { 79 switch { 80 case strings.HasSuffix(varname, eval.FnSuffix): 81 got(eval.MakeVariableRef(false, ns, varname[:len(varname)-len(eval.FnSuffix)])) 82 case strings.HasSuffix(varname, eval.NsSuffix): 83 got(eval.MakeVariableRef(false, ns, varname)) 84 default: 85 name := eval.MakeVariableRef(false, ns, varname) 86 rawCands <- &complexCandidate{name, " = ", " = ", ui.Styles{}} 87 } 88 }) 89 } 90 eval.EachExternal(func(command string) { 91 got(command) 92 if strings.HasPrefix(head, "e:") { 93 got("e:" + command) 94 } 95 }) 96 return nil 97 }