Skip to content

/open: choose a terminal editor when VISUAL and EDITOR are unset (#366) - #439

Merged
raiseCatError merged 2 commits into
devfrom
feature/v022-editor-choice
Oct 21, 2026
Merged

raiseCatError merged 2 commits into
devfrom
feature/v022-editor-choice

Conversation

@raiseCatError

@raiseCatError raiseCatError commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner

Draft, do not merge before v0.21 ships. #430 has carried dev into release/v0.21.0; a fix v0.21's physical QA needs would reach the release the same way, so anything merged into dev before the release would ride along. Part of v0.22 (#431); approved as decision D3.

Why (#366)

With $VISUAL and $EDITOR unset and no Zed or VS Code around NMSh, /open could only say that no editor was known, even when Neovim, Helix or Micro was installed.

What changed

  • Settings → Sessions → Terminal editor opens the existing provider chooser (a new editor provider family, so /providers and Ask know it too). It lists Neovim, Helix, Micro, Vim, nano, Emacs (-nw) and Kakoune, marks which are installed here, and previews the exact command /open would compose for the highlighted one (nothing runs).
  • Never assumed, never installed: detection is a PATH lookup only (no version run, so no editor executes); there are no install recipes (the upstream page is named instead). An editor that is not installed cannot be chosen: the chooser says why and saves nothing.
  • Explicit preferences first (resolveHostActions): Open with Zed or VS Code, then the editor NMSh runs inside, then VISUAL/EDITOR, then the chosen editor (only when installed). If the chosen one is missing, /open says so plainly. With nothing chosen, the message names the editors installed here and where to choose.
  • Each editor's own line and column form (editorArguments): Helix file:N:C, Micro +N:C, nano +N,C, Emacs +N:C; Vim, Neovim and Kakoune +N (no documented column flag). Unknown editors get no guessed flag.
  • Explicit execution kept: a terminal editor's command goes into the composer for you to run, quoted for the session's shell, so a path with spaces or shell characters stays one argument. The real PTY, composer drafts, input ownership and focus restoration are unchanged; the native /edit is untouched.

Dependency: o in /view (#434) uses the same bridge; it picks up the chosen editor once both are merged. This PR is independent of #434.

Verification

  • New tests: tests/terminalEditor.test.ts (precedence: environment, surrounding editor, explicit Open with, chosen, missing; per-editor forms; adversarial path; configuration normalization; the family; the Settings row; no recipes or version runs in the catalog) and tests/terminalEditorApp.test.ts (the real TerminalApp with stub executables on a controlled PATH, VISUAL/EDITOR/ZED_TERM cleared: the chooser detects installed and missing editors, previews the command, refuses a missing one, saves an installed one, and /open composes Helix's form quoted). The new module and setting do not exist on dev.
  • Suites: host actions, viewer app, providers overview, Ask (including the coverage audit, which now knows the family), column gutter and Settings: all pass. Full canonical npm run verify on 4ab9f44a: 3141 pass, 5 fail, 2 skipped.
    • 3 were a gap in this PR, fixed in 898fbc33: Setup's coverage audit requires every Settings row and panel to be reachable from Setup, and the new row was not. Setup → Sessions & alerts → Terminal editor now opens the same chooser over Setup and comes back to the same step with the choice in the draft (other unapplied edits kept). New test in tests/terminalEditorApp.test.ts, which fails without the fix; Setup coverage, Setup order and the editor tests: 21/21.
    • 2 were live tests timing out under load (compatibility harness, live zsh input ownership): 16/16 when rerun at load 5.
    • A fresh full run on the fixed head is recorded below when done.
  • CI runs on this PR.

Physical QA (not done)

Ghostty and Terminal.app with VISUAL/EDITOR unset (for example env -u VISUAL -u EDITOR nmsh): /open README.md:3 explains and names the installed editors; choose one in Settings → Terminal editor; /open README.md:3:2 puts its command in the composer at the right line; Enter opens it; quitting returns to NMSh. Choosing an editor that is not installed is refused. Inside Zed's and VS Code's integrated terminals the surrounding editor still wins.

Refs #366

#366 (decision D3): with VISUAL and EDITOR unset and no Zed or VS Code
around, /open (and `o` in /view) could only say that no editor was known.

- src/host/terminalEditors.ts: a curated list (Neovim, Helix, Micro, Vim,
  nano, Emacs with -nw, Kakoune), detected on PATH only. Detection never runs
  an editor (no version arguments), and NMSh never installs one (no install
  recipes; the upstream page is named instead).
- Settings → Sessions → Terminal editor opens the existing provider chooser
  (a new 'editor' provider family, so /providers and Ask see it too). An
  installed editor is saved as terminalEditor; a missing one shows why and
  is not saved. The highlighted editor previews the exact command /open
  would compose; nothing runs.
- resolveHostActions keeps explicit choices first: Open with Zed or VS Code,
  the editor NMSh runs inside, then VISUAL/EDITOR, then the chosen editor,
  only when installed. With none chosen, the message names the editors
  installed here and where to choose.
- editorArguments adds the column forms nano (+N,C) and Emacs (+N:C)
  document; Vim, Neovim and Kakoune keep +N; paths stay single arguments and
  are quoted for the session's shell when composed.

Tests: precedence (environment, surrounding editor, explicit Open with,
chosen, missing), per-editor line and column forms, configuration
normalization, the family and Settings row, and the whole path through
TerminalApp with stub executables on a controlled PATH. Ask's coverage audit
now knows the family.

Refs #366
The Setup coverage audit requires every Settings row and panel to be
reachable from Setup. A route row next to Open with opens the editor
chooser over Setup; the choice joins the draft on the way back.
raiseCatError added a commit that referenced this pull request Oct 18, 2026
…QA passes

The ledger lists every slice and PR with its verification and open
risks; the physical QA checklist gains the held-input states and passes
for #437, #438/#441, #439 and #440; the NL design records the decisions
and the first slice's scope.
@raiseCatError
raiseCatError merged commit 79921f6 into dev Oct 21, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant