697fb5de4d
Bind Ctrl+E in the composer to suspend the TUI, spawn $VISUAL/$EDITOR
(fallback `vi`) on a temp file pre-populated with the composer's current
contents, then read the file back into the composer on save.
- New `crates/tui/src/tui/external_editor.rs`:
- `spawn_editor_for_input` toggles raw mode + alt-screen + mouse +
bracketed-paste before/after the edit and forces a `terminal.clear()`
on return so a SIGWINCH during the edit doesn't leave a stale viewport.
- `run_editor_raw` is the testable core: writes seed -> spawns editor ->
reads back -> returns `Edited(new) | Unchanged | Cancelled`. Uses
`tempfile::NamedTempFile` so the temp file is unlinked on every path
(success, non-zero exit, missing binary, IO error).
- `tui/ui.rs`: split the existing `End | Ctrl+e` cursor-end keybinding
so `End` still moves the cursor to the line end, and `Ctrl+E` now
spawns the external editor. Status-line feedback: "Edited in <editor>",
"Editor closed (no changes)", or "Editor cancelled".
- 7 new unit tests cover the resolver precedence (VISUAL > EDITOR > vi),
the no-op / failure / missing-binary / edited paths, and an explicit
temp-file-cleanup assertion via a captured editor argv.
Fixes #91