github.com/NeowayLabs/nash@v0.2.2-0.20200127205349-a227041ffd50/cmd/nash/completer.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "strconv" 7 8 "github.com/madlambda/nash" 9 "github.com/madlambda/nash/sh" 10 "github.com/chzyer/readline" 11 ) 12 13 var runes = readline.Runes{} 14 15 type Completer struct { 16 op *readline.Operation 17 term *readline.Terminal 18 sh *nash.Shell 19 } 20 21 func NewCompleter(op *readline.Operation, term *readline.Terminal, sh *nash.Shell) *Completer { 22 return &Completer{op, term, sh} 23 } 24 25 func (c *Completer) Do(line []rune, pos int) ([][]rune, int) { 26 var ( 27 newLine [][]rune 28 offset int 29 lineArg = sh.NewStrObj(string(line)) 30 posArg = sh.NewStrObj(strconv.Itoa(pos)) 31 ) 32 33 defer c.op.Refresh() 34 defer c.term.PauseRead(false) 35 36 fnDef, err := c.sh.GetFn("nash_complete") 37 if err != nil { 38 // no complete available 39 return [][]rune{[]rune{'\t'}}, offset 40 } 41 42 nashFunc := fnDef.Build() 43 err = nashFunc.SetArgs([]sh.Obj{lineArg, posArg}) 44 if err != nil { 45 fmt.Fprintf(os.Stderr, "Failed to autocomplete: %s\n", err.Error()) 46 return newLine, offset 47 } 48 49 nashFunc.SetStdin(c.sh.Stdin()) 50 nashFunc.SetStdout(c.sh.Stdout()) 51 nashFunc.SetStderr(c.sh.Stderr()) 52 53 if err = nashFunc.Start(); err != nil { 54 fmt.Fprintf(os.Stderr, "Failed to autocomplete: %s\n", err.Error()) 55 return newLine, offset 56 } 57 58 if err = nashFunc.Wait(); err != nil { 59 fmt.Fprintf(os.Stderr, "Failed to autocomplete: %s\n", err.Error()) 60 return newLine, offset 61 } 62 63 ret := nashFunc.Results() 64 65 if len(ret) != 1 || ret[0].Type() != sh.ListType { 66 fmt.Fprintf(os.Stderr, "ignoring autocomplete value: %v\n", ret) 67 return newLine, offset 68 } 69 70 retval := ret[0] 71 72 retlist := retval.(*sh.ListObj) 73 74 if len(retlist.List()) != 2 { 75 return newLine, pos 76 } 77 78 newline := retlist.List()[0] 79 newpos := retlist.List()[1] 80 81 if newline.Type() != sh.StringType || newpos.Type() != sh.StringType { 82 fmt.Fprintf(os.Stderr, "ignoring autocomplete value: (%s) (%s)\n", newline, newpos) 83 return newLine, offset 84 } 85 86 objline := newline.(*sh.StrObj) 87 objpos := newpos.(*sh.StrObj) 88 89 newoffset, err := strconv.Atoi(objpos.Str()) 90 91 if err != nil { 92 fmt.Fprintf(os.Stderr, "Failed to autocomplete: %s\n", err.Error()) 93 return newLine, offset 94 } 95 96 newLine = append(newLine, []rune(objline.Str())) 97 98 return newLine, newoffset 99 }