summaryrefslogtreecommitdiff
path: root/internal/tmuxedit
diff options
context:
space:
mode:
Diffstat (limited to 'internal/tmuxedit')
-rw-r--r--internal/tmuxedit/history.go30
-rw-r--r--internal/tmuxedit/history_test.go4
-rw-r--r--internal/tmuxedit/run.go19
3 files changed, 19 insertions, 34 deletions
diff --git a/internal/tmuxedit/history.go b/internal/tmuxedit/history.go
index eab4db2..eac3114 100644
--- a/internal/tmuxedit/history.go
+++ b/internal/tmuxedit/history.go
@@ -9,6 +9,7 @@ import (
"time"
"codeberg.org/snonux/hexai/internal/appconfig"
+ "codeberg.org/snonux/hexai/internal/textutil"
)
// HistoryEntry represents a single submission to the AI agent via tmux popup.
@@ -52,14 +53,15 @@ func AppendHistory(text, agent, cwd string) error {
if err != nil {
return fmt.Errorf("cannot open history file: %w", err)
}
- defer f.Close()
+ defer func() { _ = f.Close() }() // best-effort on error paths
// Write entry
if _, err := f.Write(data); err != nil {
return fmt.Errorf("cannot write history entry: %w", err)
}
- return nil
+ // Check Close error to catch deferred-write failures (e.g. disk full).
+ return f.Close()
}
// GetHistory retrieves the most recent history entries (up to limit).
@@ -84,7 +86,7 @@ func GetHistory(limit int) ([]HistoryEntry, error) {
// Parse JSONL line by line
var entries []HistoryEntry
- lines := splitLines(data)
+ lines := textutil.SplitLinesBytes(data)
for i, line := range lines {
if len(line) == 0 {
continue // Skip empty lines
@@ -107,25 +109,3 @@ func GetHistory(limit int) ([]HistoryEntry, error) {
return entries, nil
}
-
-// splitLines splits data into lines (handles both \n and \r\n)
-func splitLines(data []byte) [][]byte {
- var lines [][]byte
- start := 0
- for i := 0; i < len(data); i++ {
- if data[i] == '\n' {
- // Include everything before the newline (excluding \r if present)
- end := i
- if end > start && data[end-1] == '\r' {
- end--
- }
- lines = append(lines, data[start:end])
- start = i + 1
- }
- }
- // Handle last line if it doesn't end with newline
- if start < len(data) {
- lines = append(lines, data[start:])
- }
- return lines
-}
diff --git a/internal/tmuxedit/history_test.go b/internal/tmuxedit/history_test.go
index b9d59d3..f6d6d7d 100644
--- a/internal/tmuxedit/history_test.go
+++ b/internal/tmuxedit/history_test.go
@@ -6,6 +6,8 @@ import (
"path/filepath"
"testing"
"time"
+
+ "codeberg.org/snonux/hexai/internal/textutil"
)
func TestAppendHistory(t *testing.T) {
@@ -164,7 +166,7 @@ func TestSplitLines(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- got := splitLines([]byte(tt.input))
+ got := textutil.SplitLinesBytes([]byte(tt.input))
gotStr := make([]string, len(got))
for i, b := range got {
gotStr[i] = string(b)
diff --git a/internal/tmuxedit/run.go b/internal/tmuxedit/run.go
index efa503b..da484df 100644
--- a/internal/tmuxedit/run.go
+++ b/internal/tmuxedit/run.go
@@ -112,22 +112,23 @@ func loadConfig(configPath string) appconfig.App {
var debugLog *log.Logger
// initDebugLog creates a debug log file in the state directory
-// (~/.local/state/hexai/hexai-tmux-edit.log). Returns an error if the
-// state directory cannot be resolved. Silently skips logging if the
-// log file itself cannot be opened.
-func initDebugLog() error {
+// (~/.local/state/hexai/hexai-tmux-edit.log). Returns a closer for the
+// log file handle and an error if the state directory cannot be resolved.
+// Silently skips logging (returns a no-op closer) if the log file cannot
+// be opened.
+func initDebugLog() (func(), error) {
stateDir, err := appconfig.StateDir()
if err != nil {
- return fmt.Errorf("cannot create state directory: %w", err)
+ return nil, fmt.Errorf("cannot create state directory: %w", err)
}
logPath := filepath.Join(stateDir, "hexai-tmux-edit.log")
f, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o644)
if err != nil {
- return nil
+ return func() {}, nil
}
debugLog = log.New(f, "", log.LstdFlags|log.Lmicroseconds)
- return nil
+ return func() { _ = f.Close() }, nil
}
func dbg(format string, args ...any) {
@@ -140,9 +141,11 @@ func dbg(format string, args ...any) {
// It resolves the agent (by name or auto-detect), extracts the current
// prompt, opens the editor popup, then clears and sends the result.
func runWithConfig(opts Options, cfg appconfig.App) error {
- if err := initDebugLog(); err != nil {
+ closeLog, err := initDebugLog()
+ if err != nil {
return fmt.Errorf("init debug log: %w", err)
}
+ defer closeLog()
dbg("=== hexai-tmux-edit start ===")
dbg("opts: pane=%q agent=%q config=%q", opts.Pane, opts.Agent, opts.ConfigPath)