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