Skip to content

fix(open_file): keep the user's Visual mode, unsaved changes and focus - #387

Merged
ThomasK33 merged 12 commits into
mainfrom
fix/open-file-window-followups
Nov 1, 2026
Merged

ThomasK33 merged 12 commits into
mainfrom
fix/open-file-window-followups

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

Why

This PR is one of the small, reviewed fixes that close the open follow-up issues in claudecode.nvim (#385). It covers the openFile items of #385 item 5, and one more bug found while testing them.

  • i<C-o>v, then openFile: openFile ended the user's Visual mode, selected in the opened file, and Insert mode resumed there. The user's next keys acted on Claude's selection. In the live run, ld deleted beta and gamma from the opened file.
  • openFile on a file that a window shows with unsaved changes failed with E37: No write since last change. :edit and :pedit re-read the shown buffer. The preview path also left a stray preview window. This happens when the user types in the file Claude opens.
  • The same re-read opened the closed folds of a diff window on that buffer.
  • With only the preview window and a terminal, openFile split the 12-line preview window.
  • With no editor window and makeFrontmost: false, openFile left the focus in the split it made.

What changed

All code changes are in lua/claudecode/tools/open_file.lua.

  • Visual or Select mode that CTRL-O started counts as the middle of a command on Neovim 0.10 and later, where state() shows S. openFile then shows the file in the preview window and leaves the user's mode alone. On 0.8 and 0.9 this mode looks like plain Visual mode: after the call the mode is v with Claude's selection, and the user's next Visual command acts on it. The README documents that.
  • A loaded buffer is shown as it is. openFile skips :edit when the window already shows the buffer, and the preview path no longer runs :pedit. It puts the buffer in the preview window with nvim_win_set_buf(), which loads a new file there, so BufReadPost, FileType and BufEnter run once, in the preview window, as with :pedit. It makes that window with the options :pedit sets when the tab page has none. :pedit also ended Visual mode.
  • Like :pedit, the preview path shows the file in a preview window that has 'winfixbuf' set, and keeps the option. When an autocommand clears 'previewwindow' as the window gets the file, openFile answers -32000, as before.
  • After Claude rewrites a file, openFile never lets Neovim ask the user about it (W11/W12). It runs :edit and nvim_win_set_buf() for a loaded buffer, and :checktime for a buffer the window already shows, with a one-shot FileChangedShell autocommand for that buffer. The autocommand loads a buffer without unsaved changes again, as :edit did, and keeps a buffer with unsaved changes as it is. An unchanged file is not read again. On main, entering a hidden buffer with unsaved changes asked W12, and the user's next l loaded the file and dropped the changes. The README names the two cases where Neovim can still ask ('eventignore' that ignores FileChangedShell, and a user's autocommand that deletes openFile's).
  • In the middle of a command openFile sends no keys, so it no longer runs zz on a text match.
  • The fallback moves off the preview window before it splits, and with makeFrontmost: false it gives the focus back.
  • lua/claudecode/README.md (Diffs) names openDiff's new-tab and split paths. lua/claudecode/tools/README.md names outline sidebars, the CTRL-O Visual case, and the preview case of makeFrontmost: false.

Scope

  • Item 5 (d), preview: true with makeFrontmost: false when the current window shows the file, is kept as it is and documented. The file goes to the preview window, which gets the marks but no selection, because Visual mode exists only in the current window.
  • The "a register prefix stays documented. On 0.10 and later state() can tell it apart. That is a follow-up.
  • diff.lua is unchanged, because another PR owns it. openDiff can still split the preview window when no other editor window exists, and the unused legacy diff.open_diff fallback has no preview-window check.

Blast Radius

openFile only. Normal-mode openFile into a window that does not show the file runs :edit as before. The preview window now shows a loaded buffer without re-reading it from disk. The mid-command and preview paths change only as described above.

Verification

  • Live run with the verify-claudecode-nvim harness on Neovim 0.12.3:
    • The user types in other.txt, then Claude opens other.txt at line 3. Before: -32000 with E37 and a stray preview window. After: the preview window shows line 3, and the user keeps typing.
    • The user types i<C-o>v, Claude opens hello.txt with startText/endText, and the user types ld. Before: hello.txt lost beta and gamma, and Insert mode resumed in hello.txt. After: hello.txt is unchanged, Visual mode stays in other.txt, ld deletes on there, and Insert mode resumes in other.txt.
    • Both runs leave the files on disk unchanged.
  • Headless matrix with 104 runs per tree on Neovim 0.8.3, 0.9.5, 0.10.4 and 0.12.3. After the fix, every run gives the intended result, the same on every version except the documented i<C-o>v case on 0.8 and 0.9. The openFile matrix from fix(open_file): leave the user's window alone in the middle of a command #382 (1,120 runs) gives the same results before and after, except 48 runs that change as intended: the user's diff window keeps its closed fold, so the user's dw acts as in plain Vim, and a pending dv keeps its forced motion (mode nov). The fix(open_file,diff): never pick the preview window as the main editor window #384 window-choice runs still keep the file out of the preview window (12 of 12).
  • File changed on disk after it was opened (Neovim 0.8.3, 0.10.4 and 0.12.3, the main window or the preview window shows it): main and this PR find startText in the new text. An earlier commit of this PR (522788d) searched the old text.
  • With 'noautoread', live on 0.12.3: Claude writes the shown file, then calls openFile, in Normal mode and while the user types in another file. On 43980c4 the W11 dialog held the reply, and the user's typed hello world became lo world. Now, as on main, the reply comes at once, the file shows the new text, and the typed text is intact (alphaabchello world).
  • Hidden buffer that Claude rewrote, live on 0.12.3, 'autoread' on and off, with and without unsaved changes, then the user presses l: on 32cc297, 3 of 4 runs showed the W11/W12 dialog and held the reply, and l loaded the file and dropped the unsaved edits. Now all 4 reply at once with no dialog, the clean buffer shows Claude's text, and the unsaved edits stay. The same holds while the user types in another file (the preview path).
  • The verifier's matrices, main against this PR on Neovim 0.8.3 to 0.12.3: the fix(open_file): leave the user's window alone in the middle of a command #382 matrix (1,856 runs) is identical to main, including the key-reading BufEnter hooks. The fix(open_file): never change the buffer when openFile selects #370 matrix differs only in dv keeping mode nov (32 of 1,568), the fix(open_file,diff): never pick the preview window as the main editor window #384 matrix only in the split below the preview window (8 of 416). In the openFile probes, events for a new file run once in the preview window, FileType window options stay there, and a clean changed file reloads with and without 'autoread', as on main.
  • The new unit tests fail on their test commits (11, 2, 3, 5 and 8 tests) and pass with the fixes. mise run check, mise run test (947 passed, shuffled), and the integration suite on 0.8.3 and 0.12.3 (21 passed each) pass on the head.

Before the fix, ld after i<C-o>v deleted Claude's selection in hello.txt:

Before: hello.txt lost beta and gamma

After the fix, hello.txt is unchanged in the preview window, and ld deleted on in the user's file:

After: hello.txt is unchanged

Part of #385


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: xhigh

- Visual or Select mode that CTRL-O started from Insert mode takes the
  normal path: openFile edits the file into the user's window and ends
  the user's selection, and Insert mode then resumes in the opened file.
- A window that already shows the file with unsaved changes makes
  openFile fail: :edit and :pedit re-read it and stop with E37.
- With only the preview window and a terminal, openFile splits the
  small preview window instead of the terminal.
- With no editor window and makeFrontmost=false, the focus moves to the
  split openFile makes.

The specs fail until the next commit. The preview mock now models how
:edit and :pedit re-read a shown file and end Visual mode, and the
fallback mock models wincmd and vsplit.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_
- Visual or Select mode that CTRL-O started from Insert or Replace mode
  now counts as the middle of a command on Neovim 0.10 and later, where
  state() shows it with "S". openFile then shows the file in the
  preview window and the user's selection stays.
- A loaded buffer is shown as it is. openFile no longer runs :edit in a
  window that already shows the buffer, and it no longer runs :pedit:
  both re-read that buffer, which failed with E37 on unsaved changes
  and opened the folds of the user's diff windows, and :pedit also
  ended Visual mode. The preview path now loads the buffer and makes
  the preview window the way :pedit does.
- In the middle of a command openFile sends no keys at all, so it no
  longer centers the preview window on a text match.
- The fallback splits the window below the preview window, not the
  small preview window, and with makeFrontmost=false it gives the focus
  back.

The READMEs now name the new-tab and split paths of openDiff, the
outline sidebars, and what makeFrontmost=false with preview selects.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_
…followups

# Conflicts:
#	lua/claudecode/README.md
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-01T07:47:38.057345Z bb1097b Manual request
🔒 Security Review ✅ Completed 2026-11-01T07:47:41.056867Z bb1097b Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 11afa73bb2

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11afa73bb2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lua/claudecode/tools/open_file.lua Resolved
Comment thread lua/claudecode/tools/open_file.lua Resolved
…e preview path

- An existing preview window with 'winfixbuf' set makes openFile fail
  with E1513, while :pedit shows the file there and keeps the option.
- An autocommand that clears 'previewwindow' when the window gets the
  file leaves openFile answering success with no preview window, while
  :pedit answered -32000.

The specs fail until the next commit. The preview mock now models
'winfixbuf', which nvim_win_set_buf refuses and a split does not copy.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_
…ewwindow' after

- openFile clears 'winfixbuf' on the preview window while it shows the
  file there and sets it again after, so a pinned preview window gets
  the file as with :pedit, instead of failing with E1513.
- After the preview window gets the file, openFile checks that the
  window is still valid and still has 'previewwindow' set. When an
  autocommand cleared it or closed the window, openFile raises -32000
  "No preview window shows the file", as it did with :pedit.

tools/README.md documents the new error data and the 'winfixbuf' case.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 522788dd92

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 522788dd92

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

…he file changed on disk

When a window already shows the loaded buffer, openFile neither runs
:edit nor switches the buffer, so Neovim does not check the file on
disk. After Claude writes the file, openFile then searches the old
text: startText is not found. On main, :edit and :pedit re-read it.

The specs fail until the next commit. The preview mock now models how
entering a buffer, :edit and :checktime load a changed file again, and
how Neovim asks the user when the buffer has unsaved changes.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_
When a window already shows the loaded buffer, openFile now runs
:checktime for it, as Neovim does when a window enters a buffer. So
after Claude writes the file, openFile searches the new text, as :edit
and :pedit did before. The check runs only when the buffer has no
unsaved changes: for a changed buffer Neovim asks the user, and the
user's next key would answer. An unchanged file is not read again, so
the folds of other windows on the buffer stay.

The preview mock now reports 'modified' from the buffer.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 43980c4620

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 43980c4620

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

…d of the preview path

- With 'noautoread', the :checktime that openFile runs for a shown
  buffer whose file changed on disk makes Neovim ask the user. The
  user's next key answers, and the reply waits for it.
- For a file that is not loaded yet, the preview path loads it with
  bufload() in Neovim's hidden autocommand window. FileType options for
  the window are lost, and BufEnter runs twice.

The specs fail until the next commit. The preview mock now models
'autoread', FileChangedShell and v:fcs_choice, and which window loads
and enters a buffer.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_
…eview in its window

- When a window already shows the buffer and its file changed on disk,
  openFile now adds a one-shot FileChangedShell autocommand for that
  buffer that chooses "reload", then runs :checktime. With
  'noautoread', :checktime alone asked the user: the reply waited for
  the answer, and in the middle of a command the dialog took the user's
  typed keys. A buffer with unsaved changes is still not checked.
- The preview path no longer runs bufload() before nvim_win_set_buf().
  bufload() loaded the file in Neovim's hidden autocommand window, so
  FileType options for the window were lost in the preview window, and
  BufEnter and BufWinEnter ran twice. nvim_win_set_buf() now loads it
  in the preview window, once, as :pedit did.

tools/README.md now says that openFile reloads without asking, and
what the mode is after a CTRL-O Visual openFile on Neovim 0.8 and 0.9.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: 32cc297b82

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 32cc297b82

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

…den changed buffer

- When the buffer is loaded but not shown in the window openFile uses,
  :edit and nvim_win_set_buf() enter it, and Neovim checks its file on
  disk. After Claude rewrote the file, Neovim asks the user (W12 for
  unsaved changes, W11 with 'noautoread'). The reply waits, and the
  user's next `l` loads the file and drops the unsaved changes.
- With 'eventignore' set to ignore FileChangedShell, openFile's
  :checktime still asks with 'noautoread'.
- A user's FileChangedShell autocommand that runs `autocmd!` makes
  openFile's nvim_del_autocmd() fail.

The specs fail until the next commit. The preview mock now models
'eventignore' and the failing delete.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_
…le enters a buffer

openFile now runs :edit and nvim_win_set_buf() for a loaded buffer, and
:checktime, with a one-shot FileChangedShell autocommand for that
buffer. It keeps a buffer with unsaved changes as it is and loads one
without unsaved changes again. Before, entering a hidden buffer whose
file Claude rewrote made Neovim ask (W12 for unsaved changes, W11 with
'noautoread'): the reply waited, and the user's next `l` loaded the
file and dropped the unsaved changes.

openFile skips :checktime when 'eventignore' ignores FileChangedShell,
because Neovim would ask without the autocommand. Deleting the
autocommand no longer fails when a user's autocommand ran
`autocmd! FileChangedShell`.

tools/README.md describes when Neovim can still ask.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bb1097b085

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lua/claudecode/tools/open_file.lua Resolved
@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: bb1097b085

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 added this pull request to the merge queue Nov 1, 2026
Merged via the queue into main with commit c9c4b07 Nov 1, 2026
6 checks passed
@ThomasK33
ThomasK33 deleted the fix/open-file-window-followups branch November 1, 2026 09:36
@github-actions github-actions Bot mentioned this pull request Nov 1, 2026
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