diff options
| author | Grail Finder <wohilas@gmail.com> | 2026-02-28 13:59:54 +0300 |
|---|---|---|
| committer | Grail Finder <wohilas@gmail.com> | 2026-02-28 13:59:54 +0300 |
| commit | 133ec279385d38c2b597f5404ad8c8143080f161 (patch) | |
| tree | b01912799775eaa6e460b56d59e8b0028ab3fc21 /helpfuncs.go | |
| parent | d79760a28927de773a0fff46b7482431d8f504cd (diff) | |
Feat(shell): cd and pipes support
Diffstat (limited to 'helpfuncs.go')
| -rw-r--r-- | helpfuncs.go | 107 |
1 files changed, 61 insertions, 46 deletions
diff --git a/helpfuncs.go b/helpfuncs.go index b245bff..b8b7251 100644 --- a/helpfuncs.go +++ b/helpfuncs.go @@ -66,6 +66,14 @@ func isASCII(s string) bool { return true } +func mapToString[V any](m map[string]V) string { + rs := strings.Builder{} + for k, v := range m { + fmt.Fprintf(&rs, "%v: %v\n", k, v) + } + return rs.String() +} + // stripThinkingFromMsg removes thinking blocks from assistant messages. // Skips user, tool, and system messages as they may contain thinking examples. func stripThinkingFromMsg(msg *models.RoleMsg) *models.RoleMsg { @@ -453,9 +461,8 @@ func updateFlexLayout() { } func executeCommandAndDisplay(cmdText string) { - // Parse the command (split by spaces, but handle quoted arguments) - cmdParts := parseCommand(cmdText) - if len(cmdParts) == 0 { + cmdText = strings.TrimSpace(cmdText) + if cmdText == "" { fmt.Fprintf(textView, "\n[red]Error: No command provided[-:-:-]\n") if scrollToEndEnabled { textView.ScrollToEnd() @@ -463,14 +470,58 @@ func executeCommandAndDisplay(cmdText string) { colorText() return } - command := cmdParts[0] - args := []string{} - if len(cmdParts) > 1 { - args = cmdParts[1:] + workingDir := cfg.FilePickerDir + // Handle cd command specially to update working directory + if strings.HasPrefix(cmdText, "cd ") { + newDir := strings.TrimPrefix(cmdText, "cd ") + newDir = strings.TrimSpace(newDir) + // Handle cd ~ or cdHOME + if strings.HasPrefix(newDir, "~") { + home := os.Getenv("HOME") + newDir = strings.Replace(newDir, "~", home, 1) + } + // Check if directory exists + if _, err := os.Stat(newDir); err == nil { + workingDir = newDir + cfg.FilePickerDir = workingDir + // Update shell input label with new directory + shellInput.SetLabel(fmt.Sprintf("[%s]$ ", cfg.FilePickerDir)) + outputContent := workingDir + // Add the command being executed to the chat + fmt.Fprintf(textView, "\n[-:-:b](%d) <%s>: [-:-:-]\n$ %s\n", + len(chatBody.Messages), cfg.ToolRole, cmdText) + fmt.Fprintf(textView, "%s\n", outputContent) + combinedMsg := models.RoleMsg{ + Role: cfg.ToolRole, + Content: "$ " + cmdText + "\n\n" + outputContent, + } + chatBody.Messages = append(chatBody.Messages, combinedMsg) + if scrollToEndEnabled { + textView.ScrollToEnd() + } + colorText() + return + } else { + outputContent := "cd: " + newDir + ": No such file or directory" + fmt.Fprintf(textView, "\n[-:-:b](%d) <%s>: [-:-:-]\n$ %s\n", + len(chatBody.Messages), cfg.ToolRole, cmdText) + fmt.Fprintf(textView, "[red]%s[-:-:-]\n", outputContent) + combinedMsg := models.RoleMsg{ + Role: cfg.ToolRole, + Content: "$ " + cmdText + "\n\n" + outputContent, + } + chatBody.Messages = append(chatBody.Messages, combinedMsg) + if scrollToEndEnabled { + textView.ScrollToEnd() + } + colorText() + return + } } - // Create the command execution - cmd := exec.Command(command, args...) - cmd.Dir = cfg.FilePickerDir + + // Use /bin/sh to support pipes, redirects, etc. + cmd := exec.Command("/bin/sh", "-c", cmdText) + cmd.Dir = workingDir // Execute the command and get output output, err := cmd.CombinedOutput() // Add the command being executed to the chat @@ -519,42 +570,6 @@ func executeCommandAndDisplay(cmdText string) { shellHistoryPos = -1 } -// parseCommand splits command string handling quotes properly -func parseCommand(cmd string) []string { - var args []string - var current string - var inQuotes bool - var quoteChar rune - for _, r := range cmd { - switch r { - case '"', '\'': - if inQuotes { - if r == quoteChar { - inQuotes = false - } else { - current += string(r) - } - } else { - inQuotes = true - quoteChar = r - } - case ' ', '\t': - if inQuotes { - current += string(r) - } else if current != "" { - args = append(args, current) - current = "" - } - default: - current += string(r) - } - } - if current != "" { - args = append(args, current) - } - return args -} - // == search == // Global variables for search state |
