Skip to content

Support user-defined custom editors in the Open In picker - #10

Merged
kevinher7 merged 2 commits into
personalfrom
feat/custom-editors
Jun 12, 2026
Merged

kevinher7 merged 2 commits into
personalfrom
feat/custom-editors

Conversation

@kevinher7

@kevinher7 kevinher7 commented Jun 12, 2026 •

Copy link
Copy Markdown
Owner

What Changed

Adds a customEditors array to server settings (settings.json) so any command can be offered in the "Open in" picker — e.g. a terminal editor wrapped in a terminal emulator:

"customEditors": [
  {
    "id": "nvim-ghostty",
    "name": "Neovim (Ghostty)",
    "command": ["ghostty", "-e", "nvim", "{path}"]
  }
]
  • contracts: EditorId widens to built-in literals | custom:<slug> (Schema.TemplateLiteral, mirroring the existing script.<id>.run pattern); new CustomEditorDefinition with a {path} placeholder (target path is appended when no argument contains it); ServerSettings.customEditors defaults to [] so existing settings files and persisted localStorage editor ids decode unchanged.
  • server: resolveEditorLaunch resolves custom: ids against definitions the shell.openInEditor RPC handler reads from server settings. Commands come exclusively from the server-side settings file — the client still only sends an editor id, so the security posture is unchanged.
  • web: the picker lists custom editors (always shown — the user opted in explicitly; a missing command surfaces as an error toast instead of a silently hidden entry), preferred-editor resolution covers them everywhere (picker, file links, diagnostics "open logs", keybindings toast), and the existing mod+o / editor.openFavorite shortcut works once a custom editor is the last-used one.
  • settings.json edits hot-reload through the existing settings watcher and stream to connected clients via the server config subscription — no restart needed.

Also includes a separate commit fixing a pre-existing formatting issue in Migrations.ts that made vp check fail on the base branch.

Why

There is currently no way to open a session's worktree in a terminal editor like Neovim — the editor list is a hardcoded set of GUI editors. Rather than hardcoding one more entry (ghostty+nvim), this makes the list user-extensible through the already-existing, file-backed, hot-reloading server settings pipeline, which keeps the change small: no new service, no new RPC, no client-supplied commands.

UI Changes

Custom editors appear as additional entries in the existing Open In dropdown (terminal icon + configured name). No layout changes; no screenshots included.

Testing

  • 4 new resolveEditorLaunch unit tests: {path} substitution, append-when-no-placeholder, multi-argument substitution, unknown custom id fails
  • vp run typecheck passes for all 15 packages; vp check passes
  • Full server suite (1180 tests), shared (175), and web localApi (17) pass
  • Local config prepared with ["/Applications/Ghostty.app/Contents/MacOS/ghostty", "-e", "nvim", "{path}"] in ~/.t3/dev/settings.json (not yet exercised through the running app)

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

🤖 Generated with Claude Code

kevinher7 and others added 2 commits June 13, 2026 01:24
`vp check` fails on the branch without this; the change is the
formatter's own output.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a `customEditors` array to server settings (settings.json) so any
command can act as an "Open in" target, e.g. a terminal editor wrapped
in a terminal emulator:

  "customEditors": [
    { "id": "nvim-ghostty", "name": "Neovim (Ghostty)",
      "command": ["ghostty", "-e", "nvim", "{path}"] }
  ]

- contracts: EditorId widens to builtin literals | `custom:<slug>`
  template literal; CustomEditorDefinition schema with a {path}
  placeholder (target path appended when no arg contains it)
- server: resolveEditorLaunch resolves custom ids against definitions
  passed by the shell.openInEditor RPC handler (sourced from server
  settings, never from the client, so the client still only sends ids)
- web: picker lists custom editors (always shown - the user opted in
  explicitly; a missing command surfaces as a launch error toast
  instead of a hidden entry), preference resolution covers them, and
  the existing mod+o editor.openFavorite shortcut works once a custom
  editor is the last-used one
- settings.json edits hot-reload through the existing settings watcher
  and stream to clients via the server config subscription

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kevinher7 kevinher7 self-assigned this Jun 12, 2026
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L labels Jun 12, 2026
@kevinher7
kevinher7 merged commit 4cf87fb into personal Jun 12, 2026
10 of 22 checks passed
kevinher7 added a commit that referenced this pull request Jul 2, 2026
Resolves conflicts between upstream's client connection architecture
rewrite (pingdotgg#2978) and downstream features:

- Tag catalog / sidebar tag filtering (#1): ported tag state into the
  new client-runtime atom architecture (shellReducer tag events,
  tagEntities/tagCommands modules, useTags hook) and rewrote the
  Sidebar/ChatView tag command dispatch from readEnvironmentApi to
  atom commands.
- Custom editors in the Open In picker (#10): threaded customEditors
  through the rewritten ExternalLauncher service (HostProcessPlatform,
  typed launcher errors) and replaced the deleted rpc/serverState
  selectors with a primaryServerCustomEditorsAtom.
- Re-applied prTemplate/username text-generation prompt params and
  GitVcsDriver test mocks onto upstream's restructured providers.
- Accepted upstream deletions of store.ts/serverState.ts and moved
  fork test fixtures (tags: [], listAllTags/getTagById mocks) to the
  relocated test files.

vp check, vp run typecheck, and the client-runtime/web/server test
suites pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant