Skip to content

/view: o opens the file shown in your own editor, at the line on screen (#366) - #434

Merged
raiseCatError merged 1 commit into
devfrom
feature/v022-view-open-editor
Oct 21, 2026
Merged

raiseCatError merged 1 commit into
devfrom
feature/v022-view-open-editor

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).

Why

#366 asks for clearer paths between NMSh's native surfaces and the editors people already use, reusing installed tools rather than building editors. /view could hand a file only to the native /edit (e), and its own notes for a partly shown or undecodable file said "less or an editor" without a way to get there. /open already knows how to reach the person's editor safely.

What changed

  • o in /view of a file sends the file and the first line on screen to the same bridge /open uses (resolveHostActions, Settings → Open with):
    • Zed / VS Code (around NMSh, or chosen in Open with): launched with argv, the viewer stays, its status says Opened in Zed. (or why it could not start).
    • A terminal editor from $VISUAL/$EDITOR: its command (nvim +41 /path/notes.txt, hx '/path/my notes.txt:41'), quoted for the session's shell, goes in the composer for the person to run — never run for them — and the viewer closes so it is in view.
    • A draft already in the composer is never replaced: the viewer says so instead.
    • No editor known: the viewer shows the bridge's reason (set VISUAL/EDITOR, or choose Open with).
  • Rendered Markdown rows are not source lines, so the file then opens at its start; the source view (m) keeps the line. Stored output is not a file and offers nothing new.
  • The truncation notes and the UTF-16 refusal now name this way to the rest; Ask's /view description lists e and o. Footer: e edit · o open in editor.

No new launcher, editor registry or PTY ownership; paths stay single argv elements; nothing runs without the person's Enter.

Verification

  • New tests fail before the change (5 of 5) and pass after: tests/viewerOpenEditor.test.ts drives the real key handler and the real bridge with a fake host (terminal editor at the line shown with nothing executed — the capture session throws on any submission; a file named my notes; rm -rf ~ $(x).txt kept as one quoted argument; a draft left alone; a GUI editor launched, a launch failure and no editor reported, viewer kept open) and tests/viewer.test.ts (key → action for files, Markdown rendered vs. source, output; footer; notes).
  • Focused: viewer, viewer app, host actions and Ask suites — 125/125. npm run verify:fast — pass.
  • Full canonical npm run verify on 5d81d93e (NMSH_TEST_TMPDIR=/Volumes/T7Tmp/ai-dev, load 4–13): exit 0, 3,148 tests, 3,146 pass, 2 skipped, 0 failed.

Physical QA (not done)

Checklist: docs/testing/v022-physical-qa.md pass 2 (in #435). Ghostty and Terminal.app: /view a long file, scroll, o with EDITOR=nvim (composer gets nvim +N file; Enter opens it at that line; quitting returns to NMSh), with EDITOR unset outside an editor (the viewer explains), and inside Zed's and VS Code's integrated terminals (the file opens there at the line). Narrow width: the footer wraps and Esc stays reachable.

Refs #366

#366 asked for clearer paths between the native viewer and the editors people
already use. /view could hand a file only to the native /edit (e), and its
own notes for a partly shown or undecodable file said "less or an editor"
without a way to get there.

- In /view of a file, o sends the file and the first line on screen to the
  same bridge /open uses (resolveHostActions): Zed or VS Code opens beside
  NMSh with argv and the viewer stays; a terminal editor from $VISUAL/$EDITOR
  gets its command, quoted for the session's shell, placed in the composer
  for the person to run, never run for them, and the viewer closes so it is
  in view. A draft already in the composer is never replaced: the viewer says
  so instead. With no editor known, the viewer shows the bridge's reason.
- Rendered Markdown rows are not source lines, so the file then opens at its
  start; the source view (m) keeps the line. Stored output is not a file and
  offers nothing new.
- The truncation notes and the UTF-16 refusal name this way to the rest;
  Ask's /view description lists e and o.

Tests drive the real key handler and the real bridge with a fake host:
terminal editor at the line shown with nothing executed, a file name with
spaces and shell characters kept as one quoted argument, a draft left alone,
a GUI editor launched (and a launch failure and no editor reported) with the
viewer kept open. All five fail before the change.

Refs #366
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