Skip to content

vim: Fix bug where repeat operator could lead to unrecoverable replaying state#46376

Merged
dinocosta merged 1 commit intomainfrom
fix-vim-repeat-count
Jan 8, 2026
Merged

vim: Fix bug where repeat operator could lead to unrecoverable replaying state#46376
dinocosta merged 1 commit intomainfrom
fix-vim-repeat-count

Conversation

@dinocosta
Copy link
Member

When a recorded action moves focus away from the editor (e.g., buffer_search::Deploy), the EndRepeat action handler is not invoked because is node is no longer on the dispatch path. This left dot_replaying set to true, causing subsequent repeats to malfunction and the VimGlobals.pre_count value to never be reset.

Reset dot_replaying as a fail-safe when the replayer exhausts its action queue, ensuring the state is always cleaned up regardless of whether EndRepeat was handled.

Release Notes:

  • Fixed vim repeat (.) breaking when the recorded action moves focus away from the editor

When a recorded action moves focus away from the editor (e.g.,
`buffer_search::Deploy`), the `EndRepeat` action handler is not invoked
because is node is no longer on the dispatch path. This left
`dot_replaying` set to `true`, causing subsequent repeats to malfunction
and the `VimGlobals.pre_count` value to never be reset.

Reset `dot_replaying` as a fail-safe when the replayer exhausts its
action queue, ensuring the state is always cleaned up regardless of
whether `EndRepeat` was handled.

Co-authored-by: neel <neel@chot.ai>
@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Jan 8, 2026
@dinocosta dinocosta self-assigned this Jan 8, 2026
@dinocosta dinocosta merged commit 00e3b2e into main Jan 8, 2026
37 of 39 checks passed
@dinocosta dinocosta deleted the fix-vim-repeat-count branch January 8, 2026 16:41
baldwindavid added a commit to baldwindavid/zed that referenced this pull request Jan 8, 2026
* main: (349 commits)
  component_preview: Fix license symlink (zed-industries#46379)
  Do not react on already observed buffer edits' versions (zed-industries#46308)
  Fix EP CLI output flicker (zed-industries#46313)
  vim: Fix bug where repeat operator could lead to unrecoverable replaying state (zed-industries#46376)
  vim: Implement text-based matching bracket logic for Vim '%' motion to correctly find pairs within comments (zed-industries#45559)
  Improve LSP button error message (zed-industries#46377)
  agent: Make reject/accept keybindings consistent with restore/stage (zed-industries#46373)
  Enable test-support features for some dev dependencies (zed-industries#46370)
  Capture terminal output when thread is interrupted (zed-industries#46306)
  Inline assistant tools: no more feature flag (zed-industries#46107)
  Add `ep split` subcommand for dataset splitting (zed-industries#46364)
  lsp_button: Fix long LSP version label (zed-industries#46359)
  remote: Introduce a proper mock remote connection (zed-industries#46337)
  ep: Allow matching patches against files without trailing newlines (zed-industries#46357)
  docs: Update "Custom Keybindings for Extension-Based Agents section" to include a troubleshooting note for defining an agent name (zed-industries#46144)
  Fail early if clangd is downloaded on aarch Linux (zed-industries#46346)
  ep: Handle errored requests in Anthropic batches (zed-industries#46351)
  settings_ui: Fix settings search missing results when BM25 finds partial matches (zed-industries#46349)
  workspace: Unpreview active tab when closing other tabs (zed-industries#46294)
  terminal: Skip SHLVL when loading login shell environment (zed-industries#46273)
  ...
rtfeldman pushed a commit that referenced this pull request Jan 8, 2026
…ing state (#46376)

When a recorded action moves focus away from the editor (e.g.,
`buffer_search::Deploy`), the `EndRepeat` action handler is not invoked
because is node is no longer on the dispatch path. This left
`dot_replaying` set to `true`, causing subsequent repeats to malfunction
and the `VimGlobals.pre_count` value to never be reset.

Reset `dot_replaying` as a fail-safe when the replayer exhausts its
action queue, ensuring the state is always cleaned up regardless of
whether `EndRepeat` was handled.

Release Notes:

- Fixed vim repeat (`.`) breaking when the recorded action moves focus
away from the editor

Co-authored-by: neel <neel@chot.ai>
rtfeldman pushed a commit that referenced this pull request Jan 9, 2026
…ing state (#46376)

When a recorded action moves focus away from the editor (e.g.,
`buffer_search::Deploy`), the `EndRepeat` action handler is not invoked
because is node is no longer on the dispatch path. This left
`dot_replaying` set to `true`, causing subsequent repeats to malfunction
and the `VimGlobals.pre_count` value to never be reset.

Reset `dot_replaying` as a fail-safe when the replayer exhausts its
action queue, ensuring the state is always cleaned up regardless of
whether `EndRepeat` was handled.

Release Notes:

- Fixed vim repeat (`.`) breaking when the recorded action moves focus
away from the editor

Co-authored-by: neel <neel@chot.ai>
@dinocosta
Copy link
Member Author

Here's some notes I took while researching this bug, in case it's helpful in the future ✏️

  1. The observe_action method pushes every action into a vector of recorded
    action, which can also include actions that move focus away from the editor,
    like buffer_search::Deploy
  2. When an action that moves focus away happens, the Vim.blurred method is
    called, which stops recording immediately with
    Vim.stop_recording_immediately
  3. Repeating the recorded actions with . runs the Vim.repeat method, which
    will call Vim.take_count method
  4. When taking count with Vim.take_count, it first checks if
    VimGlobals.dot_replaying is true. The first time it runs, this is false,
    so VimGlobals.pre_count.take() gets called, reseting the pre_count value,
    whose value will later be moved to VimGlobals.recorded_count
  5. Back in the Vim.repeat method, the EndRepeat action is pushed to the list
    of actions to be replayed, which is meant to stop the replay. The handler for
    EndRepeat is then responsible for updating dot_replaying to false
  6. Unfortunately, since one of the actions being replayed moves the focus away
    from the editor, by the time the EndRepeat action is dispatched, its
    handler is not on the dispatch path
  7. As such, when Vim.repeat runs again, Vim.take_count will simply return
    the value from Vim.recorded_count and never touch Vim.pre_count again,
    leading to an ever growing pre_count, as new numbers get pushed onto it

LivioGama pushed a commit to LivioGama/zed that referenced this pull request Jan 20, 2026
…ing state (zed-industries#46376)

When a recorded action moves focus away from the editor (e.g.,
`buffer_search::Deploy`), the `EndRepeat` action handler is not invoked
because is node is no longer on the dispatch path. This left
`dot_replaying` set to `true`, causing subsequent repeats to malfunction
and the `VimGlobals.pre_count` value to never be reset.

Reset `dot_replaying` as a fail-safe when the replayer exhausts its
action queue, ensuring the state is always cleaned up regardless of
whether `EndRepeat` was handled.

Release Notes:

- Fixed vim repeat (`.`) breaking when the recorded action moves focus
away from the editor

Co-authored-by: neel <neel@chot.ai>
LivioGama pushed a commit to LivioGama/zed that referenced this pull request Jan 20, 2026
…ing state (zed-industries#46376)

When a recorded action moves focus away from the editor (e.g.,
`buffer_search::Deploy`), the `EndRepeat` action handler is not invoked
because is node is no longer on the dispatch path. This left
`dot_replaying` set to `true`, causing subsequent repeats to malfunction
and the `VimGlobals.pre_count` value to never be reset.

Reset `dot_replaying` as a fail-safe when the replayer exhausts its
action queue, ensuring the state is always cleaned up regardless of
whether `EndRepeat` was handled.

Release Notes:

- Fixed vim repeat (`.`) breaking when the recorded action moves focus
away from the editor

Co-authored-by: neel <neel@chot.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant