From d856d299916c4fc7c24de8120cf8ab26260e4267 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Thu, 9 Oct 2025 18:12:32 -0300 Subject: [PATCH] fix: dont oversubmit Signed-off-by: Carlos Alexandro Becker --- .../components/dialogs/commands/commands.go | 57 +++++++------------ .../tui/components/dialogs/commands/loader.go | 2 +- internal/tui/exp/list/filterable.go | 5 +- 3 files changed, 26 insertions(+), 38 deletions(-) diff --git a/internal/tui/components/dialogs/commands/commands.go b/internal/tui/components/dialogs/commands/commands.go index cf60e03ff1b6cf1492d3d7d8cd6d5d22bd79fb3b..dc8289dc53eb5a17f8a4a3e22485de176ad16dd0 100644 --- a/internal/tui/components/dialogs/commands/commands.go +++ b/internal/tui/components/dialogs/commands/commands.go @@ -3,6 +3,7 @@ package commands import ( "context" "os" + "slices" "strings" "github.com/charmbracelet/bubbles/v2/help" @@ -12,6 +13,7 @@ import ( "github.com/charmbracelet/lipgloss/v2" "github.com/charmbracelet/crush/internal/config" + "github.com/charmbracelet/crush/internal/csync" "github.com/charmbracelet/crush/internal/llm/agent" "github.com/charmbracelet/crush/internal/llm/prompt" "github.com/charmbracelet/crush/internal/pubsub" @@ -63,10 +65,10 @@ type commandDialogCmp struct { commandList listModel keyMap CommandsDialogKeyMap help help.Model - selected CommandType // Selected SystemCommands, UserCommands, or MCPPrompts - userCommands []Command // User-defined commands - mcpPrompts []Command // MCP prompts - sessionID string // Current session ID + selected CommandType // Selected SystemCommands, UserCommands, or MCPPrompts + userCommands []Command // User-defined commands + mcpPrompts *csync.Slice[Command] // MCP prompts + sessionID string // Current session ID ctx context.Context cancel context.CancelFunc } @@ -116,6 +118,7 @@ func NewCommandDialog(sessionID string) CommandsDialog { help: help, selected: SystemCommands, sessionID: sessionID, + mcpPrompts: csync.NewSlice[Command](), } } @@ -125,26 +128,11 @@ func (c *commandDialogCmp) Init() tea.Cmd { return util.ReportError(err) } c.userCommands = commands - c.mcpPrompts = LoadMCPPrompts() + c.mcpPrompts.SetSlice(loadMCPPrompts()) // Subscribe to MCP events c.ctx, c.cancel = context.WithCancel(context.Background()) - return tea.Batch( - c.SetCommandType(c.selected), - c.subscribeMCPEvents(), - ) -} - -func (c *commandDialogCmp) subscribeMCPEvents() tea.Cmd { - return func() tea.Msg { - ch := agent.SubscribeMCPEvents(c.ctx) - for event := range ch { - if event.Type == pubsub.UpdatedEvent { - return event - } - } - return nil - } + return c.setCommandType(c.selected) } func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { @@ -153,21 +141,18 @@ 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.selected), + c.setCommandType(c.selected), c.commandList.SetSize(c.listWidth(), c.listHeight()), ) case pubsub.Event[agent.MCPEvent]: // Reload MCP prompts when MCP state changes if msg.Type == pubsub.UpdatedEvent { - c.mcpPrompts = LoadMCPPrompts() + c.mcpPrompts.SetSlice(loadMCPPrompts()) // If we're currently viewing MCP prompts, refresh the list if c.selected == MCPPrompts { - return c, tea.Batch( - c.SetCommandType(MCPPrompts), - c.subscribeMCPEvents(), - ) + return c, c.setCommandType(MCPPrompts) } - return c, c.subscribeMCPEvents() + return c, nil } case tea.KeyPressMsg: switch { @@ -185,10 +170,10 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { command.Handler(command), ) case key.Matches(msg, c.keyMap.Tab): - if len(c.userCommands) == 0 && len(c.mcpPrompts) == 0 { + if len(c.userCommands) == 0 && c.mcpPrompts.Len() == 0 { return c, nil } - return c, c.SetCommandType(c.next()) + return c, c.setCommandType(c.next()) case key.Matches(msg, c.keyMap.Close): if c.cancel != nil { c.cancel() @@ -209,12 +194,12 @@ func (c *commandDialogCmp) next() CommandType { if len(c.userCommands) > 0 { return UserCommands } - if len(c.mcpPrompts) > 0 { + if c.mcpPrompts.Len() > 0 { return MCPPrompts } fallthrough case UserCommands: - if len(c.mcpPrompts) > 0 { + if c.mcpPrompts.Len() > 0 { return MCPPrompts } fallthrough @@ -231,7 +216,7 @@ func (c *commandDialogCmp) View() string { radio := c.commandTypeRadio() header := t.S().Base.Padding(0, 1, 1, 1).Render(core.Title("Commands", c.width-lipgloss.Width(radio)-5) + " " + radio) - if len(c.userCommands) == 0 && len(c.mcpPrompts) == 0 { + if len(c.userCommands) == 0 && c.mcpPrompts.Len() == 0 { header = t.S().Base.Padding(0, 1, 1, 1).Render(core.Title("Commands", c.width-4)) } content := lipgloss.JoinVertical( @@ -271,7 +256,7 @@ func (c *commandDialogCmp) commandTypeRadio() string { if len(c.userCommands) > 0 { parts = append(parts, fn(UserCommands)) } - if len(c.mcpPrompts) > 0 { + if c.mcpPrompts.Len() > 0 { parts = append(parts, fn(MCPPrompts)) } return t.S().Base.Foreground(t.FgHalfMuted).Render(strings.Join(parts, " ")) @@ -281,7 +266,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 @@ -291,7 +276,7 @@ func (c *commandDialogCmp) SetCommandType(commandType CommandType) tea.Cmd { case UserCommands: commands = c.userCommands case MCPPrompts: - commands = c.mcpPrompts + commands = slices.Collect(c.mcpPrompts.Seq()) } commandItems := []list.CompletionItem[Command]{} diff --git a/internal/tui/components/dialogs/commands/loader.go b/internal/tui/components/dialogs/commands/loader.go index 391350768806b6da06ffebd9a4f7c02b0bb96a0f..31bbee94e13e0e41ada9ba01a101921dee3b45a6 100644 --- a/internal/tui/components/dialogs/commands/loader.go +++ b/internal/tui/components/dialogs/commands/loader.go @@ -223,7 +223,7 @@ type CommandRunCustomMsg struct { Content string } -func LoadMCPPrompts() []Command { +func loadMCPPrompts() []Command { prompts := agent.GetMCPPrompts() commands := make([]Command, 0, len(prompts)) diff --git a/internal/tui/exp/list/filterable.go b/internal/tui/exp/list/filterable.go index e639786db5777aaeda237e959dffe36d9c6a7583..1b3b9c8cfbc90e19b0e9d2313eb885b5d301dda4 100644 --- a/internal/tui/exp/list/filterable.go +++ b/internal/tui/exp/list/filterable.go @@ -276,7 +276,10 @@ func (f *filterableList[T]) Filter(query string) tea.Cmd { func (f *filterableList[T]) SetItems(items []T) tea.Cmd { f.items = items - return f.list.SetItems(items) + return tea.Sequence( + f.list.SetItems(items), + f.Filter(f.query), + ) } func (f *filterableList[T]) Cursor() *tea.Cursor {