diff options
| author | Ed Zynda <[email protected]> | 2025-05-09 17:33:35 +0300 |
|---|---|---|
| committer | adamdottv <[email protected]> | 2025-05-12 09:58:59 -0500 |
| commit | 1f8580553c95e46bd478550f0a4fe17a2d039ddc (patch) | |
| tree | 5c50da0644b2c64ebf467d6d7efca60b972c7ba2 /internal/tui/components/dialog/arguments.go | |
| parent | f92b2b76dc0836b8ad9f4a47a16941efdb2accf6 (diff) | |
| download | opencode-1f8580553c95e46bd478550f0a4fe17a2d039ddc.tar.gz opencode-1f8580553c95e46bd478550f0a4fe17a2d039ddc.zip | |
feat: custom commands (#133)
* Implement custom commands
* Add User: prefix
* Reuse var
* Check if the agent is busy and if so report a warning
* Update README
* fix typo
* Implement user and project scoped custom commands
* Allow for $ARGUMENTS
* UI tweaks
* Update internal/tui/components/dialog/arguments.go
Co-authored-by: Kujtim Hoxha <[email protected]>
* Also search in $HOME/.opencode/commands
---------
Co-authored-by: Kujtim Hoxha <[email protected]>
Diffstat (limited to 'internal/tui/components/dialog/arguments.go')
| -rw-r--r-- | internal/tui/components/dialog/arguments.go | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/internal/tui/components/dialog/arguments.go b/internal/tui/components/dialog/arguments.go new file mode 100644 index 000000000..7c9e0f863 --- /dev/null +++ b/internal/tui/components/dialog/arguments.go @@ -0,0 +1,173 @@ +package dialog + +import ( + "github.com/charmbracelet/bubbles/key" + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + + "github.com/opencode-ai/opencode/internal/tui/styles" + "github.com/opencode-ai/opencode/internal/tui/theme" + "github.com/opencode-ai/opencode/internal/tui/util" +) + +// ArgumentsDialogCmp is a component that asks the user for command arguments. +type ArgumentsDialogCmp struct { + width, height int + textInput textinput.Model + keys argumentsDialogKeyMap + commandID string + content string +} + +// NewArgumentsDialogCmp creates a new ArgumentsDialogCmp. +func NewArgumentsDialogCmp(commandID, content string) ArgumentsDialogCmp { + t := theme.CurrentTheme() + ti := textinput.New() + ti.Placeholder = "Enter arguments..." + ti.Focus() + ti.Width = 40 + ti.Prompt = "" + ti.PlaceholderStyle = ti.PlaceholderStyle.Background(t.Background()) + ti.PromptStyle = ti.PromptStyle.Background(t.Background()) + ti.TextStyle = ti.TextStyle.Background(t.Background()) + + return ArgumentsDialogCmp{ + textInput: ti, + keys: argumentsDialogKeyMap{}, + commandID: commandID, + content: content, + } +} + +type argumentsDialogKeyMap struct { + Enter key.Binding + Escape key.Binding +} + +// ShortHelp implements key.Map. +func (k argumentsDialogKeyMap) ShortHelp() []key.Binding { + return []key.Binding{ + key.NewBinding( + key.WithKeys("enter"), + key.WithHelp("enter", "confirm"), + ), + key.NewBinding( + key.WithKeys("esc"), + key.WithHelp("esc", "cancel"), + ), + } +} + +// FullHelp implements key.Map. +func (k argumentsDialogKeyMap) FullHelp() [][]key.Binding { + return [][]key.Binding{k.ShortHelp()} +} + +// Init implements tea.Model. +func (m ArgumentsDialogCmp) Init() tea.Cmd { + return tea.Batch( + textinput.Blink, + m.textInput.Focus(), + ) +} + +// Update implements tea.Model. +func (m ArgumentsDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + var cmd tea.Cmd + var cmds []tea.Cmd + + switch msg := msg.(type) { + case tea.KeyMsg: + switch { + case key.Matches(msg, key.NewBinding(key.WithKeys("esc"))): + return m, util.CmdHandler(CloseArgumentsDialogMsg{}) + case key.Matches(msg, key.NewBinding(key.WithKeys("enter"))): + return m, util.CmdHandler(CloseArgumentsDialogMsg{ + Submit: true, + CommandID: m.commandID, + Content: m.content, + Arguments: m.textInput.Value(), + }) + } + case tea.WindowSizeMsg: + m.width = msg.Width + m.height = msg.Height + } + + m.textInput, cmd = m.textInput.Update(msg) + cmds = append(cmds, cmd) + + return m, tea.Batch(cmds...) +} + +// View implements tea.Model. +func (m ArgumentsDialogCmp) View() string { + t := theme.CurrentTheme() + baseStyle := styles.BaseStyle() + + // Calculate width needed for content + maxWidth := 60 // Width for explanation text + + title := baseStyle. + Foreground(t.Primary()). + Bold(true). + Width(maxWidth). + Padding(0, 1). + Render("Command Arguments") + + explanation := baseStyle. + Foreground(t.Text()). + Width(maxWidth). + Padding(0, 1). + Render("This command requires arguments. Please enter the text to replace $ARGUMENTS with:") + + inputField := baseStyle. + Foreground(t.Text()). + Width(maxWidth). + Padding(1, 1). + Render(m.textInput.View()) + + maxWidth = min(maxWidth, m.width-10) + + content := lipgloss.JoinVertical( + lipgloss.Left, + title, + explanation, + inputField, + ) + + return baseStyle.Padding(1, 2). + Border(lipgloss.RoundedBorder()). + BorderBackground(t.Background()). + BorderForeground(t.TextMuted()). + Background(t.Background()). + Width(lipgloss.Width(content) + 4). + Render(content) +} + +// SetSize sets the size of the component. +func (m *ArgumentsDialogCmp) SetSize(width, height int) { + m.width = width + m.height = height +} + +// Bindings implements layout.Bindings. +func (m ArgumentsDialogCmp) Bindings() []key.Binding { + return m.keys.ShortHelp() +} + +// CloseArgumentsDialogMsg is a message that is sent when the arguments dialog is closed. +type CloseArgumentsDialogMsg struct { + Submit bool + CommandID string + Content string + Arguments string +} + +// ShowArgumentsDialogMsg is a message that is sent to show the arguments dialog. +type ShowArgumentsDialogMsg struct { + CommandID string + Content string +} + |
