github.com/mem/u-root@v2.0.1-0.20181004165302-9b18b4636a33+incompatible/cmds/elvish/edit/completion/complete_arg.go (about)

     1  package completion
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/u-root/u-root/cmds/elvish/edit/lscolors"
    11  	"github.com/u-root/u-root/cmds/elvish/edit/ui"
    12  	"github.com/u-root/u-root/cmds/elvish/parse"
    13  )
    14  
    15  type argComplContext struct {
    16  	complContextCommon
    17  	words []string
    18  }
    19  
    20  func (*argComplContext) name() string { return "argument" }
    21  
    22  func findArgComplContext(n parse.Node, ev pureEvaler) complContext {
    23  	if sep, ok := n.(*parse.Sep); ok {
    24  		if form, ok := sep.Parent().(*parse.Form); ok && form.Head != nil {
    25  			return &argComplContext{
    26  				complContextCommon{
    27  					"", quotingForEmptySeed, n.End(), n.End()},
    28  				evalFormPure(form, "", n.End(), ev),
    29  			}
    30  		}
    31  	}
    32  	if primary, ok := n.(*parse.Primary); ok {
    33  		if compound, seed := primaryInSimpleCompound(primary, ev); compound != nil {
    34  			if form, ok := compound.Parent().(*parse.Form); ok {
    35  				if form.Head != nil && form.Head != compound {
    36  					return &argComplContext{
    37  						complContextCommon{
    38  							seed, primary.Type, compound.Begin(), compound.End()},
    39  						evalFormPure(form, seed, compound.Begin(), ev),
    40  					}
    41  				}
    42  			}
    43  		}
    44  	}
    45  	return nil
    46  }
    47  
    48  func evalFormPure(form *parse.Form, seed string, seedBegin int, ev pureEvaler) []string {
    49  	// Find out head of the form and preceding arguments.
    50  	// If form.Head is not a simple compound, head will be "", just what we want.
    51  	head, _ := ev.PurelyEvalPartialCompound(form.Head, nil)
    52  	words := []string{head}
    53  	for _, compound := range form.Args {
    54  		if compound.Begin() >= seedBegin {
    55  			break
    56  		}
    57  		if arg, err := ev.PurelyEvalCompound(compound); err == nil {
    58  			// XXX Arguments that are not simple compounds are simply ignored.
    59  			words = append(words, arg)
    60  		}
    61  	}
    62  
    63  	words = append(words, seed)
    64  	return words
    65  }
    66  
    67  // To complete an argument, delegate the actual completion work to a suitable
    68  // complContext.
    69  func (ctx *argComplContext) generate(env *complEnv, ch chan<- rawCandidate) error {
    70  	return completeArg(ctx.words, env.evaler, env.argCompleter, ch)
    71  }
    72  
    73  // TODO: getStyle does redundant stats.
    74  func complFilenameInner(head string, executableOnly bool, rawCands chan<- rawCandidate) error {
    75  	dir, fileprefix := filepath.Split(head)
    76  	dirToRead := dir
    77  	if dirToRead == "" {
    78  		dirToRead = "."
    79  	}
    80  
    81  	infos, err := ioutil.ReadDir(dirToRead)
    82  	if err != nil {
    83  		return fmt.Errorf("cannot list directory %s: %v", dirToRead, err)
    84  	}
    85  
    86  	lsColor := lscolors.GetColorist()
    87  	// Make candidates out of elements that match the file component.
    88  	for _, info := range infos {
    89  		name := info.Name()
    90  		// Show dot files iff file part of pattern starts with dot, and vice
    91  		// versa.
    92  		if dotfile(fileprefix) != dotfile(name) {
    93  			continue
    94  		}
    95  		// Only accept searchable directories and executable files if
    96  		// executableOnly is true.
    97  		if executableOnly && !(info.IsDir() || (info.Mode()&0111) != 0) {
    98  			continue
    99  		}
   100  
   101  		// Full filename for source and getStyle.
   102  		full := dir + name
   103  
   104  		suffix := " "
   105  		if info.IsDir() {
   106  			suffix = string(filepath.Separator)
   107  		} else if info.Mode()&os.ModeSymlink != 0 {
   108  			stat, err := os.Stat(full)
   109  			if err == nil && stat.IsDir() {
   110  				// Symlink to directory.
   111  				suffix = string(filepath.Separator)
   112  			}
   113  		}
   114  
   115  		rawCands <- &complexCandidate{
   116  			stem: full, codeSuffix: suffix,
   117  			style: ui.StylesFromString(lsColor.GetStyle(full)),
   118  		}
   119  	}
   120  
   121  	return nil
   122  }
   123  
   124  func dotfile(fname string) bool {
   125  	return strings.HasPrefix(fname, ".")
   126  }