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 }