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  }