refactor(tui): move command loading to uicmd package

Ayman Bagabas created

Change summary

internal/tui/components/dialogs/commands/arguments.go | 15 +----
internal/tui/components/dialogs/commands/commands.go  | 19 +++---
internal/uicmd/uicmd.go                               | 37 +++++++++++-
3 files changed, 46 insertions(+), 25 deletions(-)

Detailed changes

internal/tui/components/dialogs/commands/arguments.go 🔗

@@ -11,6 +11,7 @@ import (
 	"github.com/charmbracelet/crush/internal/tui/components/dialogs"
 	"github.com/charmbracelet/crush/internal/tui/styles"
 	"github.com/charmbracelet/crush/internal/tui/util"
+	"github.com/charmbracelet/crush/internal/uicmd"
 )
 
 const (
@@ -18,20 +19,10 @@ const (
 )
 
 // ShowArgumentsDialogMsg is a message that is sent to show the arguments dialog.
-type ShowArgumentsDialogMsg struct {
-	CommandID   string
-	Description string
-	ArgNames    []string
-	OnSubmit    func(args map[string]string) tea.Cmd
-}
+type ShowArgumentsDialogMsg = uicmd.ShowArgumentsDialogMsg
 
 // CloseArgumentsDialogMsg is a message that is sent when the arguments dialog is closed.
-type CloseArgumentsDialogMsg struct {
-	Submit    bool
-	CommandID string
-	Content   string
-	Args      map[string]string
-}
+type CloseArgumentsDialogMsg = uicmd.CloseArgumentsDialogMsg
 
 // CommandArgumentsDialog represents the commands dialog.
 type CommandArgumentsDialog interface {

internal/tui/components/dialogs/commands/commands.go 🔗

@@ -23,6 +23,7 @@ import (
 	"github.com/charmbracelet/crush/internal/tui/exp/list"
 	"github.com/charmbracelet/crush/internal/tui/styles"
 	"github.com/charmbracelet/crush/internal/tui/util"
+	"github.com/charmbracelet/crush/internal/uicmd"
 )
 
 const (
@@ -44,13 +45,11 @@ const (
 type listModel = list.FilterableList[list.CompletionItem[Command]]
 
 // Command represents a command that can be executed
-type Command struct {
-	ID          string
-	Title       string
-	Description string
-	Shortcut    string // Optional shortcut for the command
-	Handler     func(cmd Command) tea.Cmd
-}
+type (
+	Command                         = uicmd.Command
+	CommandRunCustomMsg             = uicmd.CommandRunCustomMsg
+	ShowMCPPromptArgumentsDialogMsg = uicmd.ShowMCPPromptArgumentsDialogMsg
+)
 
 // CommandsDialog represents the commands dialog.
 type CommandsDialog interface {
@@ -121,12 +120,12 @@ func NewCommandDialog(sessionID string) CommandsDialog {
 }
 
 func (c *commandDialogCmp) Init() tea.Cmd {
-	commands, err := LoadCustomCommands()
+	commands, err := uicmd.LoadCustomCommands()
 	if err != nil {
 		return util.ReportError(err)
 	}
 	c.userCommands = commands
-	c.mcpPrompts.SetSlice(loadMCPPrompts())
+	c.mcpPrompts.SetSlice(uicmd.LoadMCPPrompts())
 	return c.setCommandType(c.selected)
 }
 
@@ -142,7 +141,7 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
 	case pubsub.Event[mcp.Event]:
 		// Reload MCP prompts when MCP state changes
 		if msg.Type == pubsub.UpdatedEvent {
-			c.mcpPrompts.SetSlice(loadMCPPrompts())
+			c.mcpPrompts.SetSlice(uicmd.LoadMCPPrompts())
 			// If we're currently viewing MCP prompts, refresh the list
 			if c.selected == MCPPrompts {
 				return c, c.setCommandType(MCPPrompts)

internal/tui/components/dialogs/commands/loader.go → internal/uicmd/uicmd.go 🔗

@@ -1,4 +1,7 @@
-package commands
+// Package uicmd provides functionality to load and handle custom commands
+// from markdown files and MCP prompts.
+// TODO: Move this into internal/ui after refactoring.
+package uicmd
 
 import (
 	"cmp"
@@ -18,6 +21,31 @@ import (
 	"github.com/charmbracelet/crush/internal/tui/util"
 )
 
+// Command represents a command that can be executed
+type Command struct {
+	ID          string
+	Title       string
+	Description string
+	Shortcut    string // Optional shortcut for the command
+	Handler     func(cmd Command) tea.Cmd
+}
+
+// ShowArgumentsDialogMsg is a message that is sent to show the arguments dialog.
+type ShowArgumentsDialogMsg struct {
+	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.
+type CloseArgumentsDialogMsg struct {
+	Submit    bool
+	CommandID string
+	Content   string
+	Args      map[string]string
+}
+
 const (
 	userCommandPrefix    = "user:"
 	projectCommandPrefix = "project:"
@@ -35,7 +63,10 @@ type commandSource struct {
 }
 
 func LoadCustomCommands() ([]Command, error) {
-	cfg := config.Get()
+	return LoadCustomCommandsFromConfig(config.Get())
+}
+
+func LoadCustomCommandsFromConfig(cfg *config.Config) ([]Command, error) {
 	if cfg == nil {
 		return nil, fmt.Errorf("config not loaded")
 	}
@@ -221,7 +252,7 @@ type CommandRunCustomMsg struct {
 	Content string
 }
 
-func loadMCPPrompts() []Command {
+func LoadMCPPrompts() []Command {
 	var commands []Command
 	for mcpName, prompts := range mcp.Prompts() {
 		for _, prompt := range prompts {