Skip to content
Prev Previous commit
Next Next commit
allow adding args
  • Loading branch information
ezynda3 committed Jul 25, 2025
commit 949d1f9ce3ce5aa9760d3d209372aea1ba217e99
133 changes: 90 additions & 43 deletions packages/tui/internal/components/chat/editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ type editorComponent struct {
reverted bool
}

// Message type for inserting command text into the editor
type insertCommandMsg struct {
content string
}

// Helper function to check if content contains argument placeholders
func containsArgumentPlaceholders(content string) bool {
return strings.Contains(content, "$ARGUMENTS") || strings.Contains(content, "{{args}}")
}

func (m *editorComponent) Init() tea.Cmd {
return tea.Batch(m.textarea.Focus(), m.spinner.Tick, tea.EnableReportFocus)
}
Expand Down Expand Up @@ -216,6 +226,11 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} else {
m.textarea.InsertRunesFromUserInput([]rune(text))
}
case insertCommandMsg:
// Insert the command text into the editor
m.textarea.SetValue(msg.content)
m.textarea.MoveToEnd()
return m, nil
case dialog.ThemeSelectedMsg:
m.textarea = updateTextareaStyles(m.textarea)
m.spinner = createSpinner()
Expand All @@ -230,50 +245,13 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Extract the actual command name (e.g., "custom_user_hello" -> "user:hello")
actualName := strings.ReplaceAll(strings.TrimPrefix(commandName, "custom_"), "_", ":")

// Get the current input text to extract arguments
content := m.textarea.Value()
slashIndex := strings.LastIndex(content, "/")
args := ""
if slashIndex != -1 {
// Extract everything after the command name as arguments
afterSlash := content[slashIndex+1:]
parts := strings.SplitN(afterSlash, " ", 2)
if len(parts) > 1 {
args = strings.TrimSpace(parts[1])
}
}

// Clear the current input
m.textarea.SetValue("")

// Fetch and resolve the command content, then submit it
cmds = append(cmds, func() tea.Msg {
// Call the server to resolve the command
var result struct {
Success bool `json:"success"`
Content string `json:"content"`
Error string `json:"error"`
}

payload := map[string]string{
"name": actualName,
"arguments": args,
}

err := m.app.Client.Post(context.Background(), "/command/resolve", payload, &result)
if err != nil {
// Return an error message to be displayed
return toast.NewErrorToast(fmt.Sprintf("Failed to resolve command: %v", err))()
}

if !result.Success {
return toast.NewErrorToast(result.Error)()
}
// For custom commands, always populate the input field first
// This gives users a chance to add arguments if needed
m.textarea.SetValue("/" + actualName + " ")
m.textarea.MoveToEnd()

// Create and send the prompt with the resolved content
prompt := app.Prompt{Text: result.Content}
return app.SendPrompt(prompt)
})
// Don't submit automatically - let the user press enter
return m, nil
} else {
// Handle built-in command
if cmd, ok := m.app.Commands[commands.CommandName(commandName)]; ok {
Expand Down Expand Up @@ -490,6 +468,75 @@ func (m *editorComponent) Submit() (tea.Model, tea.Cmd) {
return m, nil
}

// Check if this is a custom command that needs to be resolved
if strings.HasPrefix(value, "/") {
parts := strings.SplitN(value, " ", 2)
if len(parts) > 0 {
commandName := strings.TrimPrefix(parts[0], "/")
args := ""
if len(parts) > 1 {
args = parts[1]
}

// Check if it's a custom command (contains ":")
if strings.Contains(commandName, ":") {
// This is a custom command, we need to resolve it
var cmds []tea.Cmd

// Clear the editor first
updated, cmd := m.Clear()
m = updated.(*editorComponent)
cmds = append(cmds, cmd)

// Resolve and submit the command
cmds = append(cmds, func() tea.Msg {
// Import context here since we need it
ctx := context.Background()

// Call the server to resolve the command
var result struct {
Success bool `json:"success"`
Content string `json:"content"`
Error string `json:"error"`
}

payload := map[string]string{
"name": commandName,
"arguments": args,
}

err := m.app.Client.Post(ctx, "/command/resolve", payload, &result)
if err != nil {
return toast.NewErrorToast(fmt.Sprintf("Failed to resolve command: %v", err))()
}

if !result.Success {
return toast.NewErrorToast(result.Error)()
}

// Check if the resolved content still has placeholders (user didn't provide args)
if containsArgumentPlaceholders(result.Content) {
return toast.NewErrorToast("Please provide arguments for the command")()
}

// Create and send the prompt with the resolved content
prompt := app.Prompt{Text: result.Content}
m.app.State.AddPromptToHistory(prompt)
m.app.SaveState()
return app.SendPrompt(prompt)
})

return m, tea.Batch(cmds...)
}
}
}

// Check if the value contains unresolved argument placeholders
if containsArgumentPlaceholders(value) {
// Show an error toast
return m, toast.NewErrorToast("Please provide arguments for the command (replace $ARGUMENTS or {{args}} with your input)")
}

var cmds []tea.Cmd
attachments := m.textarea.GetAttachments()

Expand Down