on main help sign in
refactor(tui): move command loading to uicmd package
7918c90Ayman Bagabas
internal/tui/components/dialogs/commands/arguments.go+3−12
@@ -11,6 +11,7 @@ import (
11 "github.com/charmbracelet/crush/internal/tui/components/dialogs"
11 "github.com/charmbracelet/crush/internal/tui/components/dialogs"
12 "github.com/charmbracelet/crush/internal/tui/styles"
12 "github.com/charmbracelet/crush/internal/tui/styles"
13 "github.com/charmbracelet/crush/internal/tui/util"
13 "github.com/charmbracelet/crush/internal/tui/util"
14+ "github.com/charmbracelet/crush/internal/uicmd"
14)
15)
15
16
16const (
17const (
@@ -18,20 +19,10 @@ const (
18)
19)
19
20
20// ShowArgumentsDialogMsg is a message that is sent to show the arguments dialog.
21// ShowArgumentsDialogMsg is a message that is sent to show the arguments dialog.
21−type ShowArgumentsDialogMsg struct {
22+type ShowArgumentsDialogMsg = uicmd.ShowArgumentsDialogMsg
22− CommandID string
23− Description string
24− ArgNames []string
25− OnSubmit func(args map[string]string) tea.Cmd
26−}
27
23
28// CloseArgumentsDialogMsg is a message that is sent when the arguments dialog is closed.
24// CloseArgumentsDialogMsg is a message that is sent when the arguments dialog is closed.
29−type CloseArgumentsDialogMsg struct {
25+type CloseArgumentsDialogMsg = uicmd.CloseArgumentsDialogMsg
30− Submit bool
31− CommandID string
32− Content string
33− Args map[string]string
34−}
35
26
36// CommandArgumentsDialog represents the commands dialog.
27// CommandArgumentsDialog represents the commands dialog.
37type CommandArgumentsDialog interface {
28type CommandArgumentsDialog interface {
internal/tui/components/dialogs/commands/commands.go+9−10
@@ -23,6 +23,7 @@ import (
23 "github.com/charmbracelet/crush/internal/tui/exp/list"
23 "github.com/charmbracelet/crush/internal/tui/exp/list"
24 "github.com/charmbracelet/crush/internal/tui/styles"
24 "github.com/charmbracelet/crush/internal/tui/styles"
25 "github.com/charmbracelet/crush/internal/tui/util"
25 "github.com/charmbracelet/crush/internal/tui/util"
26+ "github.com/charmbracelet/crush/internal/uicmd"
26)
27)
27
28
28const (
29const (
@@ -44,13 +45,11 @@ const (
44type listModel = list.FilterableList[list.CompletionItem[Command]]
45type listModel = list.FilterableList[list.CompletionItem[Command]]
45
46
46// Command represents a command that can be executed
47// Command represents a command that can be executed
47−type Command struct {
48+type (
48− ID string
49+ Command = uicmd.Command
49− Title string
50+ CommandRunCustomMsg = uicmd.CommandRunCustomMsg
50− Description string
51+ ShowMCPPromptArgumentsDialogMsg = uicmd.ShowMCPPromptArgumentsDialogMsg
51− Shortcut string // Optional shortcut for the command
52+)
52− Handler func(cmd Command) tea.Cmd
53−}
54
53
55// CommandsDialog represents the commands dialog.
54// CommandsDialog represents the commands dialog.
56type CommandsDialog interface {
55type CommandsDialog interface {
@@ -121,12 +120,12 @@ func NewCommandDialog(sessionID string) CommandsDialog {
121}
120}
122
121
123func (c *commandDialogCmp) Init() tea.Cmd {
122func (c *commandDialogCmp) Init() tea.Cmd {
124− commands, err := LoadCustomCommands()
123+ commands, err := uicmd.LoadCustomCommands()
125 if err != nil {
124 if err != nil {
126 return util.ReportError(err)
125 return util.ReportError(err)
127 }
126 }
128 c.userCommands = commands
127 c.userCommands = commands
129− c.mcpPrompts.SetSlice(loadMCPPrompts())
128+ c.mcpPrompts.SetSlice(uicmd.LoadMCPPrompts())
130 return c.setCommandType(c.selected)
129 return c.setCommandType(c.selected)
131}
130}
132
131
@@ -142,7 +141,7 @@ func (c *commandDialogCmp) Update(msg tea.Msg) (util.Model, tea.Cmd) {
142 case pubsub.Event[mcp.Event]:
141 case pubsub.Event[mcp.Event]:
143 // Reload MCP prompts when MCP state changes
142 // Reload MCP prompts when MCP state changes
144 if msg.Type == pubsub.UpdatedEvent {
143 if msg.Type == pubsub.UpdatedEvent {
145− c.mcpPrompts.SetSlice(loadMCPPrompts())
144+ c.mcpPrompts.SetSlice(uicmd.LoadMCPPrompts())
146 // If we're currently viewing MCP prompts, refresh the list
145 // If we're currently viewing MCP prompts, refresh the list
147 if c.selected == MCPPrompts {
146 if c.selected == MCPPrompts {
148 return c, c.setCommandType(MCPPrompts)
147 return c, c.setCommandType(MCPPrompts)
internal/tui/components/dialogs/commands/loader.go → internal/uicmd/uicmd.gorenamed+34−3
@@ -1,4 +1,7 @@
1−package commands
1+// Package uicmd provides functionality to load and handle custom commands
2+// from markdown files and MCP prompts.
3+// TODO: Move this into internal/ui after refactoring.
4+package uicmd
2
5
3import (
6import (
4 "cmp"
7 "cmp"
@@ -18,6 +21,31 @@ import (
18 "github.com/charmbracelet/crush/internal/tui/util"
21 "github.com/charmbracelet/crush/internal/tui/util"
19)
22)
20
23
24+// Command represents a command that can be executed
25+type Command struct {
26+ ID string
27+ Title string
28+ Description string
29+ Shortcut string // Optional shortcut for the command
30+ Handler func(cmd Command) tea.Cmd
31+}
32+
33+// ShowArgumentsDialogMsg is a message that is sent to show the arguments dialog.
34+type ShowArgumentsDialogMsg struct {
35+ CommandID string
36+ Description string
37+ ArgNames []string
38+ OnSubmit func(args map[string]string) tea.Cmd
39+}
40+
41+// CloseArgumentsDialogMsg is a message that is sent when the arguments dialog is closed.
42+type CloseArgumentsDialogMsg struct {
43+ Submit bool
44+ CommandID string
45+ Content string
46+ Args map[string]string
47+}
48+
21const (
49const (
22 userCommandPrefix = "user:"
50 userCommandPrefix = "user:"
23 projectCommandPrefix = "project:"
51 projectCommandPrefix = "project:"
@@ -35,7 +63,10 @@ type commandSource struct {
35}
63}
36
64
37func LoadCustomCommands() ([]Command, error) {
65func LoadCustomCommands() ([]Command, error) {
38− cfg := config.Get()
66+ return LoadCustomCommandsFromConfig(config.Get())
67+}
68+
69+func LoadCustomCommandsFromConfig(cfg *config.Config) ([]Command, error) {
39 if cfg == nil {
70 if cfg == nil {
40 return nil, fmt.Errorf("config not loaded")
71 return nil, fmt.Errorf("config not loaded")
41 }
72 }
@@ -221,7 +252,7 @@ type CommandRunCustomMsg struct {
221 Content string
252 Content string
222}
253}
223
254
224−func loadMCPPrompts() []Command {
255+func LoadMCPPrompts() []Command {
225 var commands []Command
256 var commands []Command
226 for mcpName, prompts := range mcp.Prompts() {
257 for mcpName, prompts := range mcp.Prompts() {
227 for _, prompt := range prompts {
258 for _, prompt := range prompts {