Skip to content

Commit

Permalink
feat: completion for interactive mode
Browse files Browse the repository at this point in the history
fixes: #2708
  • Loading branch information
stuartwdouglas committed Sep 19, 2024
1 parent eb23cdd commit 8617bd7
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 5 deletions.
87 changes: 84 additions & 3 deletions frontend/cli/cmd_interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,28 @@ import (

"github.com/alecthomas/kong"
"github.com/chzyer/readline"
kongcompletion "github.com/jotaen/kong-completion"
"github.com/kballard/go-shellquote"
"github.com/posener/complete"

"github.com/TBD54566975/ftl/internal/projectconfig"
)

var _ readline.AutoCompleter = &FTLCompletion{}

type interactiveCmd struct {
}

func (i *interactiveCmd) Run(ctx context.Context, k *kong.Kong, projectConfig projectconfig.Config) error {
type FTLCompletion struct {
app *kong.Kong
}

func (i *interactiveCmd) Run(ctx context.Context, k *kong.Kong, projectConfig projectconfig.Config, app *kong.Kong) error {
l, err := readline.NewEx(&readline.Config{
Prompt: "\033[32m>\033[0m ",
InterruptPrompt: "^C",
EOFPrompt: "exit",
AutoComplete: &FTLCompletion{app: app},
})
if err != nil {
return fmt.Errorf("init readline: %w", err)
Expand All @@ -38,6 +47,9 @@ func (i *interactiveCmd) Run(ctx context.Context, k *kong.Kong, projectConfig pr
break
}
line = strings.TrimSpace(line)
if line == "" {
continue
}
args, err := shellquote.Split(line)
if err != nil {
errorf("%s", err)
Expand All @@ -48,11 +60,11 @@ func (i *interactiveCmd) Run(ctx context.Context, k *kong.Kong, projectConfig pr
errorf("%s", err)
continue
}
subctx := bindContext(ctx, kctx, projectConfig)
subctx := bindContext(ctx, kctx, projectConfig, app)

err = kctx.Run(subctx)
if err != nil {
errorf("%s", err)
errorf("error: %s", err)
continue
}
}
Expand All @@ -62,3 +74,72 @@ func (i *interactiveCmd) Run(ctx context.Context, k *kong.Kong, projectConfig pr
func errorf(format string, args ...any) {
fmt.Printf("\033[31m%s\033[0m\n", fmt.Sprintf(format, args...))
}

func (f *FTLCompletion) Do(line []rune, pos int) ([][]rune, int) {
parser := f.app
if parser == nil {
return nil, 0
}
all := []string{}
completed := []string{}
last := ""
lastCompleted := ""
lastSpace := false
// We don't care about anything past pos
// this completer can't handle completing in the middle of things
if pos < len(line) {
line = line[:pos]
}
current := 0
for i, arg := range line {
if i == pos {
break
}
if arg == ' ' {
lastWord := string(line[current:i])
all = append(all, lastWord)
completed = append(completed, lastWord)
current = i + 1
lastSpace = true
} else {
lastSpace = false
}
}
if pos > 0 {
if lastSpace {
lastCompleted = all[len(all)-1]
} else {
if current < len(line) {
last = string(line[current:])
all = append(all, last)
}
if len(all) > 0 {
lastCompleted = all[len(all)-1]
}
}
}

args := complete.Args{
Completed: completed,
All: all,
Last: last,
LastCompleted: lastCompleted,
}

command, err := kongcompletion.Command(parser)
if err != nil {
// TODO handle error
println(err.Error())
}
result := command.Predict(args)
runes := [][]rune{}
for _, s := range result {
if !strings.HasPrefix(s, last) || s == "interactive" {
continue
}
s = s[len(last):]
str := []rune(s)
runes = append(runes, str)
}
return runes, pos
}
5 changes: 3 additions & 2 deletions frontend/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,15 @@ func main() {
if err != nil && !errors.Is(err, os.ErrNotExist) {
kctx.FatalIfErrorf(err)
}
ctx = bindContext(ctx, kctx, config)
ctx = bindContext(ctx, kctx, config, app)

err = kctx.Run(ctx)
kctx.FatalIfErrorf(err)
}

func bindContext(ctx context.Context, kctx *kong.Context, projectConfig projectconfig.Config) context.Context {
func bindContext(ctx context.Context, kctx *kong.Context, projectConfig projectconfig.Config, app *kong.Kong) context.Context {
kctx.Bind(projectConfig)
kctx.Bind(app)

controllerServiceClient := rpc.Dial(ftlv1connect.NewControllerServiceClient, cli.Endpoint.String(), log.Error)
ctx = rpc.ContextWithClient(ctx, controllerServiceClient)
Expand Down

0 comments on commit 8617bd7

Please sign in to comment.