Преглед на файлове

fix(ui/chat): clean up orphaned temp files, expand picker docs

COMP #11: Remove orphaned .tmp file on rename failure in atomicSaveJSON.
COMP #13: Expand pickerBrowseHandleKey doc comment to describe the full
two-phase interaction model, key mappings, and extensibility via extra
handlers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
claude преди 1 месец
родител
ревизия
6df4e5f8c0
променени са 1 файла, в които са добавени 23 реда и са изтрити 7 реда
  1. 23 7
      internal/ui/chat/util.go

+ 23 - 7
internal/ui/chat/util.go

@@ -50,13 +50,28 @@ func ConfigurePicker(model *picker.Model, cfg *config.Config, title string) {
 // mode. Return (cmd, true) if handled, (nil, false) to fall through.
 type browseKeyHandler func(event *tview.KeyEvent) (tview.Command, bool)
 
-// pickerBrowseHandleKey implements a two-phase ESC for overlay pickers.
-// First ESC enters browse mode (j/k navigate, i returns to input).
-// Second ESC calls closeFn to close the picker.
-// Returns (command, handled). If handled is false, the caller should
-// fall through to the normal picker event handling.
-// The optional extra handlers are checked before the default swallow-all,
-// allowing pickers to add custom browse-mode keys (e.g. favorite toggle).
+// pickerBrowseHandleKey implements a two-phase ESC interaction model for
+// overlay pickers (emoji, search, channels, attachments).
+//
+// When browseMode is false, keys pass through to the picker's input field for
+// filtering/searching. The first ESC press sets browseMode to true instead of
+// closing the picker.
+//
+// When browseMode is true, keys are intercepted before reaching the input field:
+//
+//	j / k     — select next / previous item
+//	g / G     — jump to top / bottom of list
+//	i         — return to input mode (browseMode = false)
+//	Enter     — confirm the selected item
+//	ESC       — close the picker via closeFn
+//
+// The optional extra handlers are checked before the default catch-all,
+// allowing pickers to add custom browse-mode keys (e.g. emoji picker's 'f'
+// for favorite toggle). All other keys are swallowed in browse mode to prevent
+// them from reaching the input field or triggering global keybinds.
+//
+// Returns (command, handled). If handled is false, the caller should fall
+// through to the normal picker event handling.
 func pickerBrowseHandleKey(event *tview.KeyEvent, browseMode *bool, model *picker.Model, closeFn func(), extra ...browseKeyHandler) (tview.Command, bool) {
 	if !*browseMode {
 		if event.Key() == tcell.KeyEsc {
@@ -125,6 +140,7 @@ func atomicSaveJSON(path string, v any) {
 		return
 	}
 	if err := os.Rename(tmpPath, path); err != nil {
+		os.Remove(tmpPath)
 		slog.Error("failed to rename JSON file", "path", path, "err", err)
 	}
 }