diff --git a/cli/autocompleter.go b/cli/autocompleter.go new file mode 100644 index 00000000..27c59f94 --- /dev/null +++ b/cli/autocompleter.go @@ -0,0 +1,50 @@ +package cli + +import ( + "strings" + + "github.com/derekparker/trie" +) + +// AutoCompleter autocompletes queries +// into the REPL. +// Implements AutoCompleter interface from +// github.com/chzyer/readline +type AutoCompleter struct { + coreFuncs *trie.Trie +} + +func NewAutoCompleter(functions []string) *AutoCompleter { + coreFuncs := trie.New() + + for _, function := range functions { + coreFuncs.Add(function, function) + } + + return &AutoCompleter{ + coreFuncs: coreFuncs, + } +} + +// Do implements method of AutoCompleter interface +func (ac *AutoCompleter) Do(line []rune, pos int) (newLine [][]rune, length int) { + lineStr := string(line) + tokens := strings.Split(lineStr, " ") + token := tokens[len(tokens)-1] + + // if remove this check, than + // on any empty string will return + // all available functions + if token == "" { + return newLine, pos + } + + for _, fn := range ac.coreFuncs.PrefixSearch(token) { + // cuts a piece of word that is already written + // in the repl + withoutPre := []rune(fn)[len(token):] + newLine = append(newLine, withoutPre) + } + + return newLine, pos +} diff --git a/cli/repl.go b/cli/repl.go index e7f05a24..da188b16 100644 --- a/cli/repl.go +++ b/cli/repl.go @@ -3,14 +3,17 @@ package cli import ( "context" "fmt" - "github.com/MontFerret/ferret/pkg/compiler" - "github.com/MontFerret/ferret/pkg/runtime" - "github.com/MontFerret/ferret/pkg/runtime/logging" - "github.com/chzyer/readline" "os" "os/signal" "strings" "syscall" + + "github.com/MontFerret/ferret/pkg/parser/fql" + + "github.com/MontFerret/ferret/pkg/compiler" + "github.com/MontFerret/ferret/pkg/runtime" + "github.com/MontFerret/ferret/pkg/runtime/logging" + "github.com/chzyer/readline" ) func Repl(version string, opts Options) { @@ -23,6 +26,11 @@ func Repl(version string, opts Options) { Prompt: "> ", InterruptPrompt: "^C", EOFPrompt: "exit", + AutoComplete: NewAutoCompleter( + append( + fqlLiterals(), + ferret.RegisteredFunctions()..., + )), }) if err != nil { @@ -138,3 +146,13 @@ func Repl(version string, opts Options) { } } } + +func fqlLiterals() (literals []string) { + lns := fql.NewFqlLexer(nil).LiteralNames + + for _, ln := range lns { + literals = append(literals, strings.Trim(ln, "'")) + } + + return +} diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index 54100ba3..2ca68654 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -1,12 +1,13 @@ package compiler import ( + "strings" + "github.com/MontFerret/ferret/pkg/parser" "github.com/MontFerret/ferret/pkg/runtime" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/stdlib" "github.com/pkg/errors" - "strings" ) type FqlCompiler struct { @@ -104,3 +105,10 @@ func (c *FqlCompiler) MustCompile(query string) *runtime.Program { return program } + +func (c *FqlCompiler) RegisteredFunctions() (funcs []string) { + for k := range c.funcs { + funcs = append(funcs, k) + } + return +}