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  }