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 <kujtimii.h@gmail.com> * Also search in $HOME/.opencode/commands --------- Co-authored-by: Kujtim Hoxha <kujtimii.h@gmail.com>
This commit is contained in:
@@ -3,6 +3,8 @@ package tui
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
@@ -126,6 +128,9 @@ type appModel struct {
|
||||
|
||||
showThemeDialog bool
|
||||
themeDialog dialog.ThemeDialog
|
||||
|
||||
showArgumentsDialog bool
|
||||
argumentsDialog dialog.ArgumentsDialogCmp
|
||||
}
|
||||
|
||||
func (a appModel) Init() tea.Cmd {
|
||||
@@ -199,6 +204,13 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
|
||||
a.initDialog.SetSize(msg.Width, msg.Height)
|
||||
|
||||
if a.showArgumentsDialog {
|
||||
a.argumentsDialog.SetSize(msg.Width, msg.Height)
|
||||
args, argsCmd := a.argumentsDialog.Update(msg)
|
||||
a.argumentsDialog = args.(dialog.ArgumentsDialogCmp)
|
||||
cmds = append(cmds, argsCmd, a.argumentsDialog.Init())
|
||||
}
|
||||
|
||||
return a, tea.Batch(cmds...)
|
||||
|
||||
case pubsub.Event[logging.Log]:
|
||||
@@ -307,7 +319,36 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
status.Info("Command selected: " + msg.Command.Title)
|
||||
return a, nil
|
||||
|
||||
case dialog.ShowArgumentsDialogMsg:
|
||||
// Show arguments dialog
|
||||
a.argumentsDialog = dialog.NewArgumentsDialogCmp(msg.CommandID, msg.Content)
|
||||
a.showArgumentsDialog = true
|
||||
return a, a.argumentsDialog.Init()
|
||||
|
||||
case dialog.CloseArgumentsDialogMsg:
|
||||
// Close arguments dialog
|
||||
a.showArgumentsDialog = false
|
||||
|
||||
// If submitted, replace $ARGUMENTS and run the command
|
||||
if msg.Submit {
|
||||
// Replace $ARGUMENTS with the provided arguments
|
||||
content := strings.ReplaceAll(msg.Content, "$ARGUMENTS", msg.Arguments)
|
||||
|
||||
// Execute the command with arguments
|
||||
return a, util.CmdHandler(dialog.CommandRunCustomMsg{
|
||||
Content: content,
|
||||
})
|
||||
}
|
||||
return a, nil
|
||||
|
||||
case tea.KeyMsg:
|
||||
// If arguments dialog is open, let it handle the key press first
|
||||
if a.showArgumentsDialog {
|
||||
args, cmd := a.argumentsDialog.Update(msg)
|
||||
a.argumentsDialog = args.(dialog.ArgumentsDialogCmp)
|
||||
return a, cmd
|
||||
}
|
||||
|
||||
switch {
|
||||
case key.Matches(msg, keys.Quit):
|
||||
a.showQuit = !a.showQuit
|
||||
@@ -327,6 +368,9 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if a.showModelDialog {
|
||||
a.showModelDialog = false
|
||||
}
|
||||
if a.showArgumentsDialog {
|
||||
a.showArgumentsDialog = false
|
||||
}
|
||||
return a, nil
|
||||
case key.Matches(msg, keys.SwitchSession):
|
||||
if a.currentPage == page.ChatPage && !a.showQuit && !a.showPermissions && !a.showCommandDialog {
|
||||
@@ -718,6 +762,21 @@ func (a appModel) View() string {
|
||||
)
|
||||
}
|
||||
|
||||
if a.showArgumentsDialog {
|
||||
overlay := a.argumentsDialog.View()
|
||||
row := lipgloss.Height(appView) / 2
|
||||
row -= lipgloss.Height(overlay) / 2
|
||||
col := lipgloss.Width(appView) / 2
|
||||
col -= lipgloss.Width(overlay) / 2
|
||||
appView = layout.PlaceOverlay(
|
||||
col,
|
||||
row,
|
||||
overlay,
|
||||
appView,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
return appView
|
||||
}
|
||||
|
||||
@@ -781,5 +840,15 @@ If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (
|
||||
},
|
||||
})
|
||||
|
||||
// Load custom commands
|
||||
customCommands, err := dialog.LoadCustomCommands()
|
||||
if err != nil {
|
||||
slog.Warn("Failed to load custom commands", "error", err)
|
||||
} else {
|
||||
for _, cmd := range customCommands {
|
||||
model.RegisterCommand(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
return model
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user