Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add interative console to FTL dev #2758

Merged
merged 5 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import (
"github.com/TBD54566975/ftl/backend/schema"
frontend "github.com/TBD54566975/ftl/frontend/console"
cf "github.com/TBD54566975/ftl/internal/configuration/manager"
status "github.com/TBD54566975/ftl/internal/console"
"github.com/TBD54566975/ftl/internal/cors"
ftlhttp "github.com/TBD54566975/ftl/internal/http"
"github.com/TBD54566975/ftl/internal/log"
Expand All @@ -65,7 +66,6 @@ import (
"github.com/TBD54566975/ftl/internal/rpc/headers"
"github.com/TBD54566975/ftl/internal/sha256"
"github.com/TBD54566975/ftl/internal/slices"
"github.com/TBD54566975/ftl/internal/status"
)

// CommonConfig between the production controller and development server.
Expand Down
2 changes: 1 addition & 1 deletion frontend/cli/cmd_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import (
"github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/ftlv1connect"
"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/ftl/go-runtime/ftl/reflection"
status "github.com/TBD54566975/ftl/internal/console"
"github.com/TBD54566975/ftl/internal/log"
"github.com/TBD54566975/ftl/internal/rpc"
"github.com/TBD54566975/ftl/internal/status"
)

type callCmd struct {
Expand Down
8 changes: 5 additions & 3 deletions frontend/cli/cmd_dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ import (
"fmt"
"time"

"github.com/alecthomas/kong"
"github.com/alecthomas/types/optional"
"golang.org/x/sync/errgroup"

"github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/ftlv1connect"
"github.com/TBD54566975/ftl/internal/buildengine"
"github.com/TBD54566975/ftl/internal/console"
"github.com/TBD54566975/ftl/internal/log"
"github.com/TBD54566975/ftl/internal/lsp"
"github.com/TBD54566975/ftl/internal/projectconfig"
"github.com/TBD54566975/ftl/internal/rpc"
"github.com/TBD54566975/ftl/internal/status"
)

type devCmd struct {
Expand All @@ -28,8 +29,9 @@ type devCmd struct {
Build buildCmd `embed:""`
}

func (d *devCmd) Run(ctx context.Context, projConfig projectconfig.Config) error {
func (d *devCmd) Run(ctx context.Context, k *kong.Kong, projConfig projectconfig.Config, cancel context.CancelFunc) error {

console.LaunchEmbeddedConsole(ctx, k, projConfig, bindContext, cancel)
if len(d.Build.Dirs) == 0 {
d.Build.Dirs = projConfig.AbsModuleDirs()
}
Expand All @@ -54,7 +56,7 @@ func (d *devCmd) Run(ctx context.Context, projConfig projectconfig.Config) error
fmt.Println(dsn)
return nil
}
sm := status.FromContext(ctx)
sm := console.FromContext(ctx)
starting := sm.NewStatus("\u001B[92mStarting FTL Server 🚀\u001B[39m")
// cmdServe will notify this channel when startup commands are complete and the controller is ready
controllerReady := make(chan bool, 1)
Expand Down
145 changes: 4 additions & 141 deletions frontend/cli/cmd_interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,158 +2,21 @@ package main

import (
"context"
"errors"
"fmt"
"io"
"strings"

"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/console"
"github.com/TBD54566975/ftl/internal/projectconfig"
)

var _ readline.AutoCompleter = &FTLCompletion{}
var errExitTrap = errors.New("exit trap")

type interactiveCmd struct {
}

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},
})
func (i *interactiveCmd) Run(ctx context.Context, k *kong.Kong, projectConfig projectconfig.Config, binder console.KongContextBinder, cancel context.CancelFunc) error {
err := console.RunInteractiveConsole(ctx, k, projectConfig, binder, nil, cancel)
if err != nil {
return fmt.Errorf("init readline: %w", err)
}
l.CaptureExitSignal()
// Overload the exit function to avoid exiting the process
k.Exit = func(i int) { panic(errExitTrap) }
for {
line, err := l.Readline()
if errors.Is(err, readline.ErrInterrupt) {
if len(line) == 0 {
break
}
continue
} else if errors.Is(err, io.EOF) {
break
}
line = strings.TrimSpace(line)
if line == "" {
continue
}
args, err := shellquote.Split(line)
if err != nil {
errorf("%s", err)
continue
}
func() {
defer func() {
// Catch Exit() and continue the loop
if r := recover(); r != nil {
if r == errExitTrap { //nolint:errorlint
return
}
panic(r)
}
}()
kctx, err := k.Parse(args)
if err != nil {
errorf("%s", err)
return
}
subctx := bindContext(ctx, kctx, projectConfig, app)

err = kctx.Run(subctx)
if err != nil {
errorf("error: %s", err)
return
}
}()
return fmt.Errorf("interactive console: %w", err)
}
return nil
}

func errorf(format string, args ...any) {
fmt.Printf("\033[31m%s\033[0m\n", fmt.Sprintf(format, args...))
}

type FTLCompletion struct {
app *kong.Kong
}

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
}
2 changes: 1 addition & 1 deletion frontend/cli/cmd_replay.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import (
"github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/ftlv1connect"
"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/ftl/go-runtime/ftl/reflection"
status "github.com/TBD54566975/ftl/internal/console"
"github.com/TBD54566975/ftl/internal/log"
"github.com/TBD54566975/ftl/internal/rpc"
"github.com/TBD54566975/ftl/internal/status"
)

type replayCmd struct {
Expand Down
2 changes: 1 addition & 1 deletion frontend/cli/cmd_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

ftlv1 "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1"
"github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/ftlv1connect"
console "github.com/TBD54566975/ftl/internal/status"
"github.com/TBD54566975/ftl/internal/console"
)

type statusCmd struct {
Expand Down
Loading
Loading