Skip to content

feat(ui): open file in editor with e shortcut#310

Open
duarteocarmo wants to merge 1 commit into
modem-dev:mainfrom
duarteocarmo:feat/open-file-in-editor-shortcut
Open

feat(ui): open file in editor with e shortcut#310
duarteocarmo wants to merge 1 commit into
modem-dev:mainfrom
duarteocarmo:feat/open-file-in-editor-shortcut

Conversation

@duarteocarmo
Copy link
Copy Markdown

@duarteocarmo duarteocarmo commented May 14, 2026

I want to avoid turning hunk into some whole git workflow thing

Open in editor seems reasonable if we’re talking $ EDITOR

— Ben Vinegar (@bentlegen) May 13, 2026

Summary

  • add an e shortcut to open the currently selected sidebar file in $EDITOR
  • open at the selected hunk line when available
  • suspend the TUI while editing, then resume on editor exit
  • auto-refresh the current diff/session after returning from the editor
  • add menu/help entries: "Open file in editor"

I also ran the tests - and they passed.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 14, 2026

Greptile Summary

Adds an e keyboard shortcut (and matching menu entry) that suspends the TUI, opens the currently-selected sidebar file in $EDITOR at the selected hunk line using spawnSync, then resumes and auto-refreshes the diff.

  • openInEditor.ts is the new core module: validates $EDITOR, resolves and existence-checks the file path, quotes the path correctly, spawns the editor synchronously, and returns an error message string or null on success.
  • App.tsx wires up triggerEditSelectedFile via a useCallback, shows transient status notices through a clean timeout-ref pattern, and propagates the new callback through menu/keyboard-shortcut plumbing.
  • Help dialog and menu entries are updated consistently; a snapshot test covers the new menu label ordering.

Confidence Score: 4/5

Safe to merge — the feature is well-isolated, the TUI suspend/resume lifecycle is handled correctly, and the error-notice path is clean.

The core logic in openInEditor.ts has two minor gaps: the +line flag only works with vim-family editors (VS Code users will see unexpected behavior), and the editor process exit code is not inspected, so a crashed or errored editor still triggers a diff refresh. Neither blocks correct operation for the majority of users.

src/ui/lib/openInEditor.ts — the +line flag assumption and missing exit-code check.

Important Files Changed

Filename Overview
src/ui/lib/openInEditor.ts New module that suspends the TUI, spawns the editor synchronously, and resumes. File path is correctly shell-quoted; the +line flag only works with vim/vi-family editors, and spawnSync's exit code is not checked.
src/ui/App.tsx Wires triggerEditSelectedFile callback through existing useCallback/state plumbing. sessionNoticeText + timeout ref pattern is clean with proper cleanup in useEffect.
src/ui/hooks/useAppKeyboardShortcuts.ts Adds 'e' key binding consistent with existing shortcut patterns; no issues.
src/ui/lib/appMenus.ts Adds 'Open file in editor' menu entry with hint 'e'; follows existing structure exactly.
src/ui/components/chrome/HelpDialog.tsx Adds help entry for the 'e' shortcut; no issues.
src/ui/lib/ui-lib.test.ts Updates menu label snapshot to include the new 'Open file in editor' entry; test correctly reflects the new menu order.

Sequence Diagram

sequenceDiagram
    participant User
    participant KeyboardShortcut as useAppKeyboardShortcuts
    participant App as App.tsx
    participant OpenEditor as openInEditor.ts
    participant Renderer as CliRenderer
    participant Editor as $EDITOR (shell)
    participant Diff as refreshCurrentInput

    User->>KeyboardShortcut: press 'e'
    KeyboardShortcut->>App: triggerEditSelectedFile()
    App->>OpenEditor: "openSelectedFileInEditor({ file, renderer, selectedHunk })"
    alt no file selected / no $EDITOR / file missing on disk
        OpenEditor-->>App: error message string
        App->>App: showSessionNotice(message)
    else file exists and $EDITOR set
        OpenEditor->>Renderer: suspend()
        OpenEditor->>Editor: "spawnSync(command, { shell: true, stdio: inherit })"
        Editor-->>OpenEditor: result (status, error)
        OpenEditor->>Renderer: resume()
        OpenEditor-->>App: null (success)
        App->>Diff: triggerRefreshCurrentInput()
    end
Loading
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
src/ui/lib/openInEditor.ts:47
**`+line` flag not supported by VS Code and other common editors**

The `+${line}` flag is a vi/vim convention. Editors like VS Code (`code`) don't support it — VS Code will try to open a file literally named `+1` alongside the real file, which creates a confusing error or spuriously creates an untitled document. Similarly, `subl` (Sublime Text), `kate`, and others use different mechanisms for jump-to-line. For users with `EDITOR=code` or `EDITOR=subl`, line positioning silently breaks.

### Issue 2 of 2
src/ui/lib/openInEditor.ts:58-62
**`result.status` exit code is not checked**

`spawnSync` sets `result.error` only for Node.js-level spawn failures (e.g. `ENOENT`). If the editor itself exits with a non-zero status (permission error, crash, etc.), `result.error` is `undefined` and the function returns `null`, silently triggering a diff refresh as if editing succeeded. Checking `result.status` closes this gap.

```suggestion
  if (result.error) {
    return `Failed to launch editor: ${result.error.message}`;
  }

  if (result.status !== 0 && result.status !== null) {
    return `Editor exited with status ${result.status}.`;
  }

  return null;
```

Reviews (1): Last reviewed commit: "feat(ui): open file in editor with e sho..." | Re-trigger Greptile

Comment thread src/ui/lib/openInEditor.ts Outdated
Comment thread src/ui/lib/openInEditor.ts
@duarteocarmo duarteocarmo force-pushed the feat/open-file-in-editor-shortcut branch from 26cabc7 to f60283f Compare May 14, 2026 07:16
@duarteocarmo
Copy link
Copy Markdown
Author

@benvinegar - should be ready - lmk if anything you don't like.

@benvinegar
Copy link
Copy Markdown
Member

@duarteocarmo This is pretty handy. I just played with it.

But I notice there's a flash of content when you hit e that looks like some git diff output. Is it possible to avoid that?

@duarteocarmo
Copy link
Copy Markdown
Author

@benvinegar - for what editor? terminal based or?

@duarteocarmo duarteocarmo force-pushed the feat/open-file-in-editor-shortcut branch from f60283f to 9d8f245 Compare May 14, 2026 20:01
@duarteocarmo
Copy link
Copy Markdown
Author

@benvinegar - ok. I made a slight change.

  • For non terminal-based editors, we don't need to suspend - so they just open and there's no flicker or anything.
  • For terminal based editors (vi, etc.) we actually need to call renderer suspend(), OpenTUI doesn't have an option to keep showing the alternate screen while doing so. (Other than some hacks like writing escape sequences to the termina - which I would honestly avoid)

lmk what you think

@benvinegar
Copy link
Copy Markdown
Member

Could you add tests for src/ui/lib/openInEditor.ts?

Also a Windows concern: it builds a shell command with Unix-style quoting + shell: true, which might not work w/ cmd.exe.

And please add a changelog entry.

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.

2 participants