Enha: codingdir for coding assistant

This commit is contained in:
Grail Finder
2026-02-18 22:00:52 +03:00
parent f560ecf70b
commit 931b646c30
7 changed files with 61 additions and 2 deletions

View File

@@ -43,6 +43,7 @@ STT_SR = 16000 # Sample rate for audio recording
DBPATH = "gflt.db"
FilePickerDir = "." # Directory where file picker should start
FilePickerExts = "png,jpg,jpeg,gif,webp" # Comma-separated list of allowed file extensions for file picker
CodingDir = "." # Default directory for coding assistant file operations (relative paths resolved against this)
EnableMouse = false # Enable mouse support in the UI
# character specific context
CharSpecificContextEnabled = true

View File

@@ -31,6 +31,7 @@ type Config struct {
DBPATH string `toml:"DBPATH"`
FilePickerDir string `toml:"FilePickerDir"`
FilePickerExts string `toml:"FilePickerExts"`
CodingDir string `toml:"CodingDir"`
ImagePreview bool `toml:"ImagePreview"`
EnableMouse bool `toml:"EnableMouse"`
// embeddings

View File

@@ -145,6 +145,9 @@ This document explains how to set up and configure the application using the `co
#### FilePickerExts (`"png,jpg,jpeg,gif,webp"`)
- Comma-separated list of allowed file extensions for the file picker.
#### CodingDir (`"."`)
- Default directory for coding assistant file operations. Relative paths in file tools (file_read, file_write, etc.) are resolved against this directory. Use absolute paths (starting with `/`) to bypass this.
#### EnableMouse (`false`)
- Enable or disable mouse support in the UI. When set to `true`, allows clicking buttons and interacting with UI elements using the mouse, but prevents the terminal from handling mouse events normally (such as selecting and copying text). When set to `false`, enables default terminal behavior allowing you to select and copy text, but disables mouse interaction with UI elements.

File diff suppressed because one or more lines are too long

View File

@@ -820,7 +820,7 @@ func makeFilePicker() *tview.Flex {
}
// Create UI elements
listView := tview.NewList()
listView.SetBorder(true).SetTitle("Files & Directories").SetTitleAlign(tview.AlignLeft)
listView.SetBorder(true).SetTitle("Files & Directories [c: set CodingDir]").SetTitleAlign(tview.AlignLeft)
// Status view for selected file information
statusView := tview.NewTextView()
statusView.SetBorder(true).SetTitle("Selected File").SetTitleAlign(tview.AlignLeft)
@@ -1032,6 +1032,37 @@ func makeFilePicker() *tview.Flex {
refreshList(currentDisplayDir, "")
return nil
}
if event.Rune() == 'c' {
// Set CodingDir to current directory
itemIndex := listView.GetCurrentItem()
if itemIndex >= 0 && itemIndex < listView.GetItemCount() {
itemText, _ := listView.GetItemText(itemIndex)
// Get the actual directory path
var targetDir string
if strings.HasPrefix(itemText, "Exit") || strings.HasPrefix(itemText, "Select this directory") {
targetDir = currentDisplayDir
} else {
actualItemName := itemText
if bracketPos := strings.Index(itemText, " ["); bracketPos != -1 {
actualItemName = itemText[:bracketPos]
}
if strings.HasPrefix(actualItemName, "../") {
targetDir = path.Dir(currentDisplayDir)
} else if strings.HasSuffix(actualItemName, "/") {
dirName := strings.TrimSuffix(actualItemName, "/")
targetDir = path.Join(currentDisplayDir, dirName)
} else {
targetDir = currentDisplayDir
}
}
cfg.CodingDir = targetDir
if err := notifyUser("CodingDir", "Set to: "+targetDir); err != nil {
logger.Error("failed to notify user", "error", err)
}
pages.RemovePage(filePickerPage)
return nil
}
}
case tcell.KeyEnter:
// Get the currently highlighted item in the list
itemIndex := listView.GetCurrentItem()

View File

@@ -9,6 +9,7 @@ import (
"io"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
@@ -377,6 +378,8 @@ func fileCreate(args map[string]string) []byte {
return []byte(msg)
}
path = resolvePath(path)
content, ok := args["content"]
if !ok {
content = ""
@@ -400,6 +403,8 @@ func fileRead(args map[string]string) []byte {
return []byte(msg)
}
path = resolvePath(path)
content, err := readStringFromFile(path)
if err != nil {
msg := "failed to read file; error: " + err.Error()
@@ -428,6 +433,7 @@ func fileWrite(args map[string]string) []byte {
logger.Error(msg)
return []byte(msg)
}
path = resolvePath(path)
content, ok := args["content"]
if !ok {
content = ""
@@ -448,6 +454,7 @@ func fileWriteAppend(args map[string]string) []byte {
logger.Error(msg)
return []byte(msg)
}
path = resolvePath(path)
content, ok := args["content"]
if !ok {
content = ""
@@ -469,6 +476,8 @@ func fileDelete(args map[string]string) []byte {
return []byte(msg)
}
path = resolvePath(path)
if err := removeFile(path); err != nil {
msg := "failed to delete file; error: " + err.Error()
logger.Error(msg)
@@ -486,6 +495,7 @@ func fileMove(args map[string]string) []byte {
logger.Error(msg)
return []byte(msg)
}
src = resolvePath(src)
dst, ok := args["dst"]
if !ok || dst == "" {
@@ -493,6 +503,7 @@ func fileMove(args map[string]string) []byte {
logger.Error(msg)
return []byte(msg)
}
dst = resolvePath(dst)
if err := moveFile(src, dst); err != nil {
msg := "failed to move file; error: " + err.Error()
@@ -511,6 +522,7 @@ func fileCopy(args map[string]string) []byte {
logger.Error(msg)
return []byte(msg)
}
src = resolvePath(src)
dst, ok := args["dst"]
if !ok || dst == "" {
@@ -518,6 +530,7 @@ func fileCopy(args map[string]string) []byte {
logger.Error(msg)
return []byte(msg)
}
dst = resolvePath(dst)
if err := copyFile(src, dst); err != nil {
msg := "failed to copy file; error: " + err.Error()
@@ -535,6 +548,8 @@ func fileList(args map[string]string) []byte {
path = "." // default to current directory
}
path = resolvePath(path)
files, err := listDirectory(path)
if err != nil {
msg := "failed to list directory; error: " + err.Error()
@@ -558,6 +573,13 @@ func fileList(args map[string]string) []byte {
// Helper functions for file operations
func resolvePath(p string) string {
if filepath.IsAbs(p) {
return p
}
return filepath.Join(cfg.CodingDir, p)
}
func readStringFromFile(filename string) (string, error) {
data, err := os.ReadFile(filename)
if err != nil {

1
tui.go
View File

@@ -76,6 +76,7 @@ var (
[yellow]Ctrl+c[white]: close programm
[yellow]Ctrl+n[white]: start a new chat
[yellow]Ctrl+o[white]: open image file picker
[yellow]c[white]: (in file picker) set current dir as CodingDir
[yellow]Ctrl+p[white]: props edit form (min-p, dry, etc.)
[yellow]Ctrl+v[white]: show API link selection popup to choose current API
[yellow]Ctrl+r[white]: start/stop recording from your microphone (needs stt server or whisper binary)