From 82b6f8fbefcc263c99c61823987182f513584d55 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Fri, 10 Oct 2025 10:20:59 -0300 Subject: [PATCH 1/4] fix(cmds): small improvements in user commands - ESC now works - better handling of size events - properly set input's width - generic arguments input that will be used in #1209 (in fact this is extracted from #1209) - improved code a bit Signed-off-by: Carlos Alexandro Becker --- .../components/dialogs/commands/arguments.go | 160 ++++++++++-------- .../components/dialogs/commands/commands.go | 78 ++++++--- .../tui/components/dialogs/commands/keys.go | 5 + .../tui/components/dialogs/commands/loader.go | 45 +++-- internal/tui/tui.go | 17 +- 5 files changed, 197 insertions(+), 108 deletions(-) diff --git a/internal/tui/components/dialogs/commands/arguments.go b/internal/tui/components/dialogs/commands/arguments.go index 03110eeaf2b8fbb909f1f9e4fbd57344699732e3..0f46895a24ea5340d8496f00c9cf988f39d73a91 100644 --- a/internal/tui/components/dialogs/commands/arguments.go +++ b/internal/tui/components/dialogs/commands/arguments.go @@ -1,8 +1,7 @@ package commands import ( - "fmt" - "strings" + "cmp" "github.com/charmbracelet/bubbles/v2/help" "github.com/charmbracelet/bubbles/v2/key" @@ -20,9 +19,10 @@ const ( // ShowArgumentsDialogMsg is a message that is sent to show the arguments dialog. type ShowArgumentsDialogMsg struct { - CommandID string - Content string - ArgNames []string + CommandID string + Description string + ArgNames []string + OnSubmit func(args map[string]string) tea.Cmd } // CloseArgumentsDialogMsg is a message that is sent when the arguments dialog is closed. @@ -39,26 +39,39 @@ type CommandArgumentsDialog interface { } type commandArgumentsDialogCmp struct { - width int - wWidth int // Width of the terminal window - wHeight int // Height of the terminal window - - inputs []textinput.Model - focusIndex int - keys ArgumentsDialogKeyMap - commandID string - content string - argNames []string - help help.Model + wWidth, wHeight int + width, height int + + inputs []textinput.Model + focused int + keys ArgumentsDialogKeyMap + arguments []Argument + help help.Model + + id string + title string + name string + description string + + onSubmit func(args map[string]string) tea.Cmd +} + +type Argument struct { + Name, Title, Description string + Required bool } -func NewCommandArgumentsDialog(commandID, content string, argNames []string) CommandArgumentsDialog { +func NewCommandArgumentsDialog( + id, title, name, description string, + arguments []Argument, + onSubmit func(args map[string]string) tea.Cmd, +) CommandArgumentsDialog { t := styles.CurrentTheme() - inputs := make([]textinput.Model, len(argNames)) + inputs := make([]textinput.Model, len(arguments)) - for i, name := range argNames { + for i, arg := range arguments { ti := textinput.New() - ti.Placeholder = fmt.Sprintf("Enter value for %s...", name) + ti.Placeholder = cmp.Or(arg.Description, "Enter value for "+arg.Title) ti.SetWidth(40) ti.SetVirtualCursor(false) ti.Prompt = "" @@ -75,14 +88,16 @@ func NewCommandArgumentsDialog(commandID, content string, argNames []string) Com } return &commandArgumentsDialogCmp{ - inputs: inputs, - keys: DefaultArgumentsDialogKeyMap(), - commandID: commandID, - content: content, - argNames: argNames, - focusIndex: 0, - width: 60, - help: help.New(), + inputs: inputs, + keys: DefaultArgumentsDialogKeyMap(), + id: id, + name: name, + title: title, + description: description, + arguments: arguments, + width: 60, + help: help.New(), + onSubmit: onSubmit, } } @@ -97,41 +112,45 @@ func (c *commandArgumentsDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.WindowSizeMsg: c.wWidth = msg.Width c.wHeight = msg.Height + c.width = min(90, c.wWidth) + c.height = min(15, c.wHeight) + for i := range c.inputs { + c.inputs[i].SetWidth(c.width - (paddingHorizontal * 2)) + } case tea.KeyPressMsg: switch { + case key.Matches(msg, c.keys.Cancel): + return c, util.CmdHandler(dialogs.CloseDialogMsg{}) case key.Matches(msg, c.keys.Confirm): - if c.focusIndex == len(c.inputs)-1 { - content := c.content - for i, name := range c.argNames { + if c.focused == len(c.inputs)-1 { + args := make(map[string]string) + for i, arg := range c.arguments { value := c.inputs[i].Value() - placeholder := "$" + name - content = strings.ReplaceAll(content, placeholder, value) + args[arg.Name] = value } return c, tea.Sequence( util.CmdHandler(dialogs.CloseDialogMsg{}), - util.CmdHandler(CommandRunCustomMsg{ - Content: content, - }), + c.onSubmit(args), ) } // Otherwise, move to the next input - c.inputs[c.focusIndex].Blur() - c.focusIndex++ - c.inputs[c.focusIndex].Focus() + c.inputs[c.focused].Blur() + c.focused++ + c.inputs[c.focused].Focus() case key.Matches(msg, c.keys.Next): // Move to the next input - c.inputs[c.focusIndex].Blur() - c.focusIndex = (c.focusIndex + 1) % len(c.inputs) - c.inputs[c.focusIndex].Focus() + c.inputs[c.focused].Blur() + c.focused = (c.focused + 1) % len(c.inputs) + c.inputs[c.focused].Focus() case key.Matches(msg, c.keys.Previous): // Move to the previous input - c.inputs[c.focusIndex].Blur() - c.focusIndex = (c.focusIndex - 1 + len(c.inputs)) % len(c.inputs) - c.inputs[c.focusIndex].Focus() + c.inputs[c.focused].Blur() + c.focused = (c.focused - 1 + len(c.inputs)) % len(c.inputs) + c.inputs[c.focused].Focus() default: var cmd tea.Cmd - c.inputs[c.focusIndex], cmd = c.inputs[c.focusIndex].Update(msg) + c.inputs[c.focused], cmd = c.inputs[c.focused].Update(msg) return c, cmd } } @@ -147,26 +166,28 @@ func (c *commandArgumentsDialogCmp) View() string { Foreground(t.Primary). Bold(true). Padding(0, 1). - Render("Command Arguments") + Render(cmp.Or(c.title, c.name)) - explanation := t.S().Text. + promptName := t.S().Text. Padding(0, 1). - Render("This command requires arguments.") + Render(c.description) - // Create input fields for each argument inputFields := make([]string, len(c.inputs)) for i, input := range c.inputs { - // Highlight the label of the focused input - labelStyle := baseStyle. - Padding(1, 1, 0, 1) + labelStyle := baseStyle.Padding(1, 1, 0, 1) - if i == c.focusIndex { + if i == c.focused { labelStyle = labelStyle.Foreground(t.FgBase).Bold(true) } else { labelStyle = labelStyle.Foreground(t.FgMuted) } - label := labelStyle.Render(c.argNames[i] + ":") + arg := c.arguments[i] + argName := cmp.Or(arg.Title, arg.Name) + if arg.Required { + argName += "*" + } + label := labelStyle.Render(argName + ":") field := t.S().Text. Padding(0, 1). @@ -175,18 +196,14 @@ func (c *commandArgumentsDialogCmp) View() string { inputFields[i] = lipgloss.JoinVertical(lipgloss.Left, label, field) } - // Join all elements vertically - elements := []string{title, explanation} + elements := []string{title, promptName} elements = append(elements, inputFields...) c.help.ShowAll = false helpText := baseStyle.Padding(0, 1).Render(c.help.View(c.keys)) elements = append(elements, "", helpText) - content := lipgloss.JoinVertical( - lipgloss.Left, - elements..., - ) + content := lipgloss.JoinVertical(lipgloss.Left, elements...) return baseStyle.Padding(1, 1, 0, 1). Border(lipgloss.RoundedBorder()). @@ -196,26 +213,33 @@ func (c *commandArgumentsDialogCmp) View() string { } func (c *commandArgumentsDialogCmp) Cursor() *tea.Cursor { - cursor := c.inputs[c.focusIndex].Cursor() + if len(c.inputs) == 0 { + return nil + } + cursor := c.inputs[c.focused].Cursor() if cursor != nil { cursor = c.moveCursor(cursor) } return cursor } +const ( + headerHeight = 3 + itemHeight = 3 + paddingHorizontal = 3 +) + func (c *commandArgumentsDialogCmp) moveCursor(cursor *tea.Cursor) *tea.Cursor { row, col := c.Position() - offset := row + 3 + (1+c.focusIndex)*3 + offset := row + headerHeight + (1+c.focused)*itemHeight cursor.Y += offset - cursor.X = cursor.X + col + 3 + cursor.X = cursor.X + col + paddingHorizontal return cursor } func (c *commandArgumentsDialogCmp) Position() (int, int) { - row := c.wHeight / 2 - row -= c.wHeight / 2 - col := c.wWidth / 2 - col -= c.width / 2 + row := (c.wHeight / 2) - (c.height / 2) + col := (c.wWidth / 2) - (c.width / 2) return row, col } diff --git a/internal/tui/components/dialogs/commands/commands.go b/internal/tui/components/dialogs/commands/commands.go index 664158fc392a87d8a7725bfa964748f7ef4f8e67..0b662b8538db04be6c9dc1d01bcbf8d786c54c31 100644 --- a/internal/tui/components/dialogs/commands/commands.go +++ b/internal/tui/components/dialogs/commands/commands.go @@ -1,7 +1,9 @@ package commands import ( + "context" "os" + "strings" "github.com/charmbracelet/bubbles/v2/help" "github.com/charmbracelet/bubbles/v2/key" @@ -25,8 +27,12 @@ const ( defaultWidth int = 70 ) +type CommandType uint + +func (c CommandType) String() string { return []string{"System", "User"}[c] } + const ( - SystemCommands int = iota + SystemCommands CommandType = iota UserCommands ) @@ -54,9 +60,11 @@ type commandDialogCmp struct { commandList listModel keyMap CommandsDialogKeyMap help help.Model - commandType int // SystemCommands or UserCommands - userCommands []Command // User-defined commands - sessionID string // Current session ID + selected CommandType // Selected SystemCommands or UserCommands + userCommands []Command // User-defined commands + sessionID string // Current session ID + ctx context.Context + cancel context.CancelFunc } type ( @@ -102,7 +110,7 @@ func NewCommandDialog(sessionID string) CommandsDialog { width: defaultWidth, keyMap: DefaultCommandsDialogKeyMap(), help: help, - commandType: SystemCommands, + selected: SystemCommands, sessionID: sessionID, } } @@ -113,7 +121,7 @@ func (c *commandDialogCmp) Init() tea.Cmd { return util.ReportError(err) } c.userCommands = commands - return c.SetCommandType(c.commandType) + return c.setCommandType(c.selected) } func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { @@ -122,7 +130,7 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { c.wWidth = msg.Width c.wHeight = msg.Height return c, tea.Batch( - c.SetCommandType(c.commandType), + c.setCommandType(c.selected), c.commandList.SetSize(c.listWidth(), c.listHeight()), ) case tea.KeyPressMsg: @@ -133,6 +141,9 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return c, nil // No item selected, do nothing } command := (*selectedItem).Value() + if c.cancel != nil { + c.cancel() + } return c, tea.Sequence( util.CmdHandler(dialogs.CloseDialogMsg{}), command.Handler(command), @@ -141,13 +152,11 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if len(c.userCommands) == 0 { return c, nil } - // Toggle command type between System and User commands - if c.commandType == SystemCommands { - return c, c.SetCommandType(UserCommands) - } else { - return c, c.SetCommandType(SystemCommands) - } + return c, c.setCommandType(c.next()) case key.Matches(msg, c.keyMap.Close): + if c.cancel != nil { + c.cancel() + } return c, util.CmdHandler(dialogs.CloseDialogMsg{}) default: u, cmd := c.commandList.Update(msg) @@ -158,6 +167,20 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return c, nil } +func (c *commandDialogCmp) next() CommandType { + switch c.selected { + case SystemCommands: + if len(c.userCommands) > 0 { + return UserCommands + } + fallthrough + case UserCommands: + fallthrough + default: + return SystemCommands + } +} + func (c *commandDialogCmp) View() string { t := styles.CurrentTheme() listView := c.commandList @@ -190,26 +213,35 @@ func (c *commandDialogCmp) Cursor() *tea.Cursor { func (c *commandDialogCmp) commandTypeRadio() string { t := styles.CurrentTheme() - choices := []string{"System", "User"} - iconSelected := "◉" - iconUnselected := "○" - if c.commandType == SystemCommands { - return t.S().Base.Foreground(t.FgHalfMuted).Render(iconSelected + " " + choices[0] + " " + iconUnselected + " " + choices[1]) + + fn := func(i CommandType) string { + if i == c.selected { + return "◉ " + i.String() + } + return "○ " + i.String() + } + + parts := []string{ + fn(SystemCommands), + } + if len(c.userCommands) > 0 { + parts = append(parts, fn(UserCommands)) } - return t.S().Base.Foreground(t.FgHalfMuted).Render(iconUnselected + " " + choices[0] + " " + iconSelected + " " + choices[1]) + return t.S().Base.Foreground(t.FgHalfMuted).Render(strings.Join(parts, " ")) } func (c *commandDialogCmp) listWidth() int { return defaultWidth - 2 // 4 for padding } -func (c *commandDialogCmp) SetCommandType(commandType int) tea.Cmd { - c.commandType = commandType +func (c *commandDialogCmp) setCommandType(commandType CommandType) tea.Cmd { + c.selected = commandType var commands []Command - if c.commandType == SystemCommands { + switch c.selected { + case SystemCommands: commands = c.defaultCommands() - } else { + case UserCommands: commands = c.userCommands } diff --git a/internal/tui/components/dialogs/commands/keys.go b/internal/tui/components/dialogs/commands/keys.go index 7b79a29c28a024154a3b4d8c763969585409fd00..32d34d3c26360f040ea8ecd7e9c1fa3c4d2d7a5a 100644 --- a/internal/tui/components/dialogs/commands/keys.go +++ b/internal/tui/components/dialogs/commands/keys.go @@ -76,6 +76,7 @@ type ArgumentsDialogKeyMap struct { Confirm key.Binding Next key.Binding Previous key.Binding + Cancel key.Binding } func DefaultArgumentsDialogKeyMap() ArgumentsDialogKeyMap { @@ -93,6 +94,10 @@ func DefaultArgumentsDialogKeyMap() ArgumentsDialogKeyMap { key.WithKeys("shift+tab", "up"), key.WithHelp("shift+tab/↑", "previous"), ), + Cancel: key.NewBinding( + key.WithKeys("esc"), + key.WithHelp("esc", "cancel"), + ), } } diff --git a/internal/tui/components/dialogs/commands/loader.go b/internal/tui/components/dialogs/commands/loader.go index 74d9c7e4baee2e2d19f8baca914942f0c0d34cd3..188003e9b71318898cc9a67cd2648c244c216a78 100644 --- a/internal/tui/components/dialogs/commands/loader.go +++ b/internal/tui/components/dialogs/commands/loader.go @@ -15,8 +15,8 @@ import ( ) const ( - UserCommandPrefix = "user:" - ProjectCommandPrefix = "project:" + userCommandPrefix = "user:" + projectCommandPrefix = "project:" ) var namedArgPattern = regexp.MustCompile(`\$([A-Z][A-Z0-9_]*)`) @@ -50,7 +50,7 @@ func buildCommandSources(cfg *config.Config) []commandSource { if dir := getXDGCommandsDir(); dir != "" { sources = append(sources, commandSource{ path: dir, - prefix: UserCommandPrefix, + prefix: userCommandPrefix, }) } @@ -58,14 +58,14 @@ func buildCommandSources(cfg *config.Config) []commandSource { if home := home.Dir(); home != "" { sources = append(sources, commandSource{ path: filepath.Join(home, ".crush", "commands"), - prefix: UserCommandPrefix, + prefix: userCommandPrefix, }) } // Project directory sources = append(sources, commandSource{ path: filepath.Join(cfg.Options.DataDirectory, "commands"), - prefix: ProjectCommandPrefix, + prefix: projectCommandPrefix, }) return sources @@ -127,12 +127,13 @@ func (l *commandLoader) loadCommand(path, baseDir, prefix string) (Command, erro } id := buildCommandID(path, baseDir, prefix) + desc := fmt.Sprintf("Custom command from %s", filepath.Base(path)) return Command{ ID: id, Title: id, - Description: fmt.Sprintf("Custom command from %s", filepath.Base(path)), - Handler: createCommandHandler(id, string(content)), + Description: desc, + Handler: createCommandHandler(id, desc, string(content)), }, nil } @@ -149,21 +150,35 @@ func buildCommandID(path, baseDir, prefix string) string { return prefix + strings.Join(parts, ":") } -func createCommandHandler(id string, content string) func(Command) tea.Cmd { +func createCommandHandler(id, desc, content string) func(Command) tea.Cmd { return func(cmd Command) tea.Cmd { args := extractArgNames(content) - if len(args) > 0 { - return util.CmdHandler(ShowArgumentsDialogMsg{ - CommandID: id, - Content: content, - ArgNames: args, + if len(args) == 0 { + return util.CmdHandler(CommandRunCustomMsg{ + Content: content, }) } + return util.CmdHandler(ShowArgumentsDialogMsg{ + CommandID: id, + Description: desc, + ArgNames: args, + OnSubmit: func(args map[string]string) tea.Cmd { + return execUserPrompt(content, args) + }, + }) + } +} - return util.CmdHandler(CommandRunCustomMsg{ +func execUserPrompt(content string, args map[string]string) tea.Cmd { + return func() tea.Msg { + for name, value := range args { + placeholder := "$" + name + content = strings.ReplaceAll(content, placeholder, value) + } + return CommandRunCustomMsg{ Content: content, - }) + } } } diff --git a/internal/tui/tui.go b/internal/tui/tui.go index 74d82e15514c70ee96b507a01b8f611d3ade6a4d..5fd430fe7c7ba4ac55ae4a716fc98ade9b60ec38 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -34,6 +34,8 @@ import ( "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" "github.com/charmbracelet/lipgloss/v2" + "golang.org/x/text/cases" + "golang.org/x/text/language" ) var lastMouseEvent time.Time @@ -138,12 +140,23 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { a.dialog = u.(dialogs.DialogCmp) return a, tea.Batch(completionCmd, dialogCmd) case commands.ShowArgumentsDialogMsg: + var args []commands.Argument + for _, arg := range msg.ArgNames { + args = append(args, commands.Argument{ + Name: arg, + Title: cases.Title(language.English).String(arg), + Required: true, + }) + } return a, util.CmdHandler( dialogs.OpenDialogMsg{ Model: commands.NewCommandArgumentsDialog( msg.CommandID, - msg.Content, - msg.ArgNames, + msg.CommandID, + msg.CommandID, + msg.Description, + args, + msg.OnSubmit, ), }, ) From ea34b81d8f07bfe0803cc8f482c8f0017deca93e Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Fri, 10 Oct 2025 10:23:31 -0300 Subject: [PATCH 2/4] fixup! fix(cmds): small improvements in user commands Signed-off-by: Carlos Alexandro Becker --- .../tui/components/dialogs/commands/commands.go | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/internal/tui/components/dialogs/commands/commands.go b/internal/tui/components/dialogs/commands/commands.go index 0b662b8538db04be6c9dc1d01bcbf8d786c54c31..17bd9faaec2227a8badb60347b6f2f25847f1e66 100644 --- a/internal/tui/components/dialogs/commands/commands.go +++ b/internal/tui/components/dialogs/commands/commands.go @@ -168,17 +168,10 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (c *commandDialogCmp) next() CommandType { - switch c.selected { - case SystemCommands: - if len(c.userCommands) > 0 { - return UserCommands - } - fallthrough - case UserCommands: - fallthrough - default: - return SystemCommands + if c.selected == SystemCommands { + return UserCommands } + return SystemCommands } func (c *commandDialogCmp) View() string { From 412008faadb8074781c3384b2db9a701027ac095 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Fri, 10 Oct 2025 10:24:00 -0300 Subject: [PATCH 3/4] fixup! fixup! fix(cmds): small improvements in user commands Signed-off-by: Carlos Alexandro Becker --- .../tui/components/dialogs/commands/commands.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/tui/components/dialogs/commands/commands.go b/internal/tui/components/dialogs/commands/commands.go index 17bd9faaec2227a8badb60347b6f2f25847f1e66..6cdb8c8bbcc8aec42d27ff8f06f9b2c1a7a00105 100644 --- a/internal/tui/components/dialogs/commands/commands.go +++ b/internal/tui/components/dialogs/commands/commands.go @@ -27,12 +27,12 @@ const ( defaultWidth int = 70 ) -type CommandType uint +type commandType uint -func (c CommandType) String() string { return []string{"System", "User"}[c] } +func (c commandType) String() string { return []string{"System", "User"}[c] } const ( - SystemCommands CommandType = iota + SystemCommands commandType = iota UserCommands ) @@ -60,7 +60,7 @@ type commandDialogCmp struct { commandList listModel keyMap CommandsDialogKeyMap help help.Model - selected CommandType // Selected SystemCommands or UserCommands + selected commandType // Selected SystemCommands or UserCommands userCommands []Command // User-defined commands sessionID string // Current session ID ctx context.Context @@ -167,7 +167,7 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return c, nil } -func (c *commandDialogCmp) next() CommandType { +func (c *commandDialogCmp) next() commandType { if c.selected == SystemCommands { return UserCommands } @@ -207,7 +207,7 @@ func (c *commandDialogCmp) Cursor() *tea.Cursor { func (c *commandDialogCmp) commandTypeRadio() string { t := styles.CurrentTheme() - fn := func(i CommandType) string { + fn := func(i commandType) string { if i == c.selected { return "◉ " + i.String() } @@ -227,7 +227,7 @@ func (c *commandDialogCmp) listWidth() int { return defaultWidth - 2 // 4 for padding } -func (c *commandDialogCmp) setCommandType(commandType CommandType) tea.Cmd { +func (c *commandDialogCmp) setCommandType(commandType commandType) tea.Cmd { c.selected = commandType var commands []Command From eccaa13488016568d8d3f82c988b2a55151338a0 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Fri, 10 Oct 2025 10:26:32 -0300 Subject: [PATCH 4/4] fixup! fixup! fixup! fix(cmds): small improvements in user commands Signed-off-by: Carlos Alexandro Becker --- internal/tui/components/dialogs/commands/commands.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/internal/tui/components/dialogs/commands/commands.go b/internal/tui/components/dialogs/commands/commands.go index 6cdb8c8bbcc8aec42d27ff8f06f9b2c1a7a00105..3b97fade92a534a9fb429a87c75abf50bcd22fa7 100644 --- a/internal/tui/components/dialogs/commands/commands.go +++ b/internal/tui/components/dialogs/commands/commands.go @@ -1,7 +1,6 @@ package commands import ( - "context" "os" "strings" @@ -63,8 +62,6 @@ type commandDialogCmp struct { selected commandType // Selected SystemCommands or UserCommands userCommands []Command // User-defined commands sessionID string // Current session ID - ctx context.Context - cancel context.CancelFunc } type ( @@ -141,9 +138,6 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return c, nil // No item selected, do nothing } command := (*selectedItem).Value() - if c.cancel != nil { - c.cancel() - } return c, tea.Sequence( util.CmdHandler(dialogs.CloseDialogMsg{}), command.Handler(command), @@ -154,9 +148,6 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } return c, c.setCommandType(c.next()) case key.Matches(msg, c.keyMap.Close): - if c.cancel != nil { - c.cancel() - } return c, util.CmdHandler(dialogs.CloseDialogMsg{}) default: u, cmd := c.commandList.Update(msg)