diff --git a/cmd/dynamo-browse/main.go b/cmd/dynamo-browse/main.go index 43fec27..d1c4d08 100644 --- a/cmd/dynamo-browse/main.go +++ b/cmd/dynamo-browse/main.go @@ -170,9 +170,13 @@ func main() { exportController, keyBindingController, pasteboardProvider, + settingsController, ) - commandController := commandctrl.NewCommandController(inputHistoryService, stdCommands) + commandController, err := commandctrl.NewCommandController(inputHistoryService, stdCommands) + if err != nil { + cli.Fatalf("cannot setup command controller: %v", err) + } //commandController.AddCommandLookupExtension(scriptController) commandController.SetCommandCompletionProvider(columnsController) diff --git a/internal/common/ui/commandctrl/cmdpacks/modopt.go b/internal/common/ui/commandctrl/cmdpacks/modopt.go new file mode 100644 index 0000000..398a86b --- /dev/null +++ b/internal/common/ui/commandctrl/cmdpacks/modopt.go @@ -0,0 +1,47 @@ +package cmdpacks + +import ( + "context" + "github.com/lmika/dynamo-browse/internal/common/ui/commandctrl" + "github.com/lmika/dynamo-browse/internal/dynamo-browse/controllers" + "ucl.lmika.dev/ucl" +) + +type optModule struct { + settingsController *controllers.SettingsController +} + +func (m optModule) pbSet(ctx context.Context, args ucl.CallArgs) (any, error) { + var ( + name string + newVale string + ) + + if args.NArgs() == 1 { + if err := args.Bind(&name); err != nil { + return nil, err + } + } else { + if err := args.Bind(&name, &newVale); err != nil { + return nil, err + } + } + + commandctrl.PostMsg(ctx, m.settingsController.SetSetting(name, newVale)) + return nil, nil +} + +func moduleOpt( + settingsController *controllers.SettingsController, +) ucl.Module { + m := &optModule{ + settingsController: settingsController, + } + + return ucl.Module{ + Name: "opt", + Builtins: map[string]ucl.BuiltinHandler{ + "set": m.pbSet, + }, + } +} diff --git a/internal/common/ui/commandctrl/cmdpacks/modpb.go b/internal/common/ui/commandctrl/cmdpacks/modpb.go index 528499b..2a27d6e 100644 --- a/internal/common/ui/commandctrl/cmdpacks/modpb.go +++ b/internal/common/ui/commandctrl/cmdpacks/modpb.go @@ -2,12 +2,12 @@ package cmdpacks import ( "context" - "github.com/lmika/dynamo-browse/internal/dynamo-browse/providers/pasteboardprovider" + "github.com/lmika/dynamo-browse/internal/dynamo-browse/services" "ucl.lmika.dev/ucl" ) type pbModule struct { - pasteboardProvider *pasteboardprovider.Provider + pasteboardProvider services.PasteboardProvider } func (m pbModule) pbGet(ctx context.Context, args ucl.CallArgs) (any, error) { @@ -30,7 +30,7 @@ func (m pbModule) pbPut(ctx context.Context, args ucl.CallArgs) (any, error) { } func modulePB( - pasteboardProvider *pasteboardprovider.Provider, + pasteboardProvider services.PasteboardProvider, ) ucl.Module { m := &pbModule{ pasteboardProvider: pasteboardProvider, diff --git a/internal/common/ui/commandctrl/cmdpacks/stdcmds.go b/internal/common/ui/commandctrl/cmdpacks/stdcmds.go index 9019ec6..088c0f9 100644 --- a/internal/common/ui/commandctrl/cmdpacks/stdcmds.go +++ b/internal/common/ui/commandctrl/cmdpacks/stdcmds.go @@ -6,7 +6,7 @@ import ( "github.com/lmika/dynamo-browse/internal/common/ui/commandctrl" "github.com/lmika/dynamo-browse/internal/dynamo-browse/controllers" "github.com/lmika/dynamo-browse/internal/dynamo-browse/models" - "github.com/lmika/dynamo-browse/internal/dynamo-browse/providers/pasteboardprovider" + "github.com/lmika/dynamo-browse/internal/dynamo-browse/services" "github.com/lmika/dynamo-browse/internal/dynamo-browse/services/tables" "github.com/pkg/errors" "ucl.lmika.dev/repl" @@ -20,7 +20,8 @@ type StandardCommands struct { WriteController *controllers.TableWriteController ExportController *controllers.ExportController KeyBindingController *controllers.KeyBindingController - PBProvider *pasteboardprovider.Provider + PBProvider services.PasteboardProvider + SettingsController *controllers.SettingsController modUI ucl.Module } @@ -32,7 +33,8 @@ func NewStandardCommands( writeController *controllers.TableWriteController, exportController *controllers.ExportController, keyBindingController *controllers.KeyBindingController, - pbProvider *pasteboardprovider.Provider, + pbProvider services.PasteboardProvider, + settingsController *controllers.SettingsController, ) StandardCommands { modUI, ckbs := moduleUI(tableService, state, readController) keyBindingController.SetCustomKeyBindingSource(ckbs) @@ -45,6 +47,7 @@ func NewStandardCommands( ExportController: exportController, KeyBindingController: keyBindingController, PBProvider: pbProvider, + SettingsController: settingsController, modUI: modUI, } } @@ -394,6 +397,7 @@ func (sc StandardCommands) InstOptions() []ucl.InstOption { ucl.WithModule(moduleRS(sc.TableService, sc.State)), ucl.WithModule(sc.modUI), ucl.WithModule(modulePB(sc.PBProvider)), + ucl.WithModule(moduleOpt(sc.SettingsController)), } } @@ -402,7 +406,6 @@ func (sc StandardCommands) ConfigureUCL(ucl *ucl.Inst) { ucl.SetBuiltin("table", sc.cmdTable) ucl.SetBuiltin("export", sc.cmdExport) ucl.SetBuiltin("mark", sc.cmdMark) - // unmark --> alias for { mark none } ucl.SetBuiltin("next-page", sc.cmdNextPage) ucl.SetBuiltin("delete", sc.cmdDelete) ucl.SetBuiltin("new-item", sc.cmdNewItem) @@ -413,9 +416,18 @@ func (sc StandardCommands) ConfigureUCL(ucl *ucl.Inst) { ucl.SetBuiltin("touch", sc.cmdTouch) ucl.SetBuiltin("noisy-touch", sc.cmdNoisyTouch) ucl.SetBuiltin("rebind", sc.cmdRebind) - // set-opt --> alias to opts:set ucl.SetPseudoVar("resultset", resultSetPVar{sc.State, sc.ReadController}) ucl.SetPseudoVar("table", tablePVar{sc.State}) ucl.SetPseudoVar("item", itemPVar{sc.State}) } + +func (sc StandardCommands) RunPrelude(ctx context.Context, ucl *ucl.Inst) error { + _, err := ucl.EvalString(ctx, uclPrelude) + return err +} + +const uclPrelude = ` +ui:command unmark { mark none } +ui:command set-opt { |n k| opt:set $n $k } +` diff --git a/internal/common/ui/commandctrl/cmdpacks/stdcmds_test.go b/internal/common/ui/commandctrl/cmdpacks/stdcmds_test.go index 228c6be..55bef6e 100644 --- a/internal/common/ui/commandctrl/cmdpacks/stdcmds_test.go +++ b/internal/common/ui/commandctrl/cmdpacks/stdcmds_test.go @@ -137,9 +137,17 @@ func newService(t *testing.T, opts ...serviceOpt) *services { keyBindingService := keybindings_service.NewService(keybindings.Default()) keyBindingController := controllers.NewKeyBindingController(keyBindingService, nil) - _ = settingsController - commandController := commandctrl.NewCommandController(inputHistoryService, - cmdpacks.NewStandardCommands(service, state, readController, writeController, exportController, keyBindingController), + commandController, _ := commandctrl.NewCommandController(inputHistoryService, + cmdpacks.NewStandardCommands( + service, + state, + readController, + writeController, + exportController, + keyBindingController, + pasteboardprovider.NilProvider{}, + settingsController, + ), ) s.State = state diff --git a/internal/common/ui/commandctrl/commandctrl.go b/internal/common/ui/commandctrl/commandctrl.go index bfbe79b..9075da8 100644 --- a/internal/common/ui/commandctrl/commandctrl.go +++ b/internal/common/ui/commandctrl/commandctrl.go @@ -35,7 +35,7 @@ type CommandController struct { interactive bool } -func NewCommandController(historyProvider IterProvider, pkgs ...CommandPack) *CommandController { +func NewCommandController(historyProvider IterProvider, pkgs ...CommandPack) (*CommandController, error) { cc := &CommandController{ historyProvider: historyProvider, commandList: nil, @@ -60,9 +60,17 @@ func NewCommandController(historyProvider IterProvider, pkgs ...CommandPack) *Co pkg.ConfigureUCL(cc.uclInst) } + execCtx := execContext{ctrl: cc} + ctx := context.WithValue(context.Background(), commandCtlKey, &execCtx) + for _, pkg := range pkgs { + if err := pkg.RunPrelude(ctx, cc.uclInst); err != nil { + return nil, err + } + } + go cc.cmdLooper() - return cc + return cc, nil } func (c *CommandController) AddCommands(ctx *CommandList) { diff --git a/internal/common/ui/commandctrl/commandctrl_test.go b/internal/common/ui/commandctrl/commandctrl_test.go index b21783e..bcc112a 100644 --- a/internal/common/ui/commandctrl/commandctrl_test.go +++ b/internal/common/ui/commandctrl/commandctrl_test.go @@ -12,7 +12,8 @@ import ( func TestCommandController_Prompt(t *testing.T) { t.Run("prompt user for a command", func(t *testing.T) { - cmd := commandctrl.NewCommandController(mockIterProvider{}) + cmd, err := commandctrl.NewCommandController(mockIterProvider{}) + assert.NoError(t, err) res := cmd.Prompt() diff --git a/internal/common/ui/commandctrl/packs.go b/internal/common/ui/commandctrl/packs.go index 6f5dbc6..16df613 100644 --- a/internal/common/ui/commandctrl/packs.go +++ b/internal/common/ui/commandctrl/packs.go @@ -1,8 +1,12 @@ package commandctrl -import "ucl.lmika.dev/ucl" +import ( + "context" + "ucl.lmika.dev/ucl" +) type CommandPack interface { InstOptions() []ucl.InstOption ConfigureUCL(ucl *ucl.Inst) + RunPrelude(ctx context.Context, ucl *ucl.Inst) error } diff --git a/internal/dynamo-browse/controllers/tablewrite_test.go b/internal/dynamo-browse/controllers/tablewrite_test.go index efd0c14..a407923 100644 --- a/internal/dynamo-browse/controllers/tablewrite_test.go +++ b/internal/dynamo-browse/controllers/tablewrite_test.go @@ -636,7 +636,7 @@ func newService(t *testing.T, cfg serviceConfig) *services { exportController := controllers.NewExportController(state, service, jobsController, columnsController, pasteboardprovider.NilProvider{}) scriptController := controllers.NewScriptController(scriptService, readController, jobsController, settingsController, eventBus) - commandController := commandctrl.NewCommandController(inputHistoryService) + commandController, _ := commandctrl.NewCommandController(inputHistoryService) commandController.AddCommandLookupExtension(scriptController) if cfg.isReadOnly { diff --git a/internal/dynamo-browse/ui/model.go b/internal/dynamo-browse/ui/model.go index 90dfa0f..42f7e31 100644 --- a/internal/dynamo-browse/ui/model.go +++ b/internal/dynamo-browse/ui/model.go @@ -40,14 +40,13 @@ type Model struct { settingsController *controllers.SettingsController exportController *controllers.ExportController commandController *commandctrl.CommandController - //scriptController *controllers.ScriptController - jobController *controllers.JobsController - colSelector *colselector.Model - relSelector *relselector.Model - itemEdit *dynamoitemedit.Model - statusAndPrompt *statusandprompt.StatusAndPrompt - tableSelect *tableselect.Model - eventBus *bus.Bus + jobController *controllers.JobsController + colSelector *colselector.Model + relSelector *relselector.Model + itemEdit *dynamoitemedit.Model + statusAndPrompt *statusandprompt.StatusAndPrompt + tableSelect *tableselect.Model + eventBus *bus.Bus mainViewIndex int @@ -68,7 +67,6 @@ func NewModel( jobController *controllers.JobsController, itemRendererService *itemrenderer.Service, cc *commandctrl.CommandController, - //scriptController *controllers.ScriptController, eventBus *bus.Bus, keyBindingController *controllers.KeyBindingController, pasteboardProvider services.PasteboardProvider,