Skip to content

Maintenance: CommandBuilder - Fix isRegisterPending not considered in isEmpty, clone, equals, hashCode#1595

Open
claude[bot] wants to merge 1 commit intomasterfrom
maintenance/fix-command-builder-is-register-pending
Open

Maintenance: CommandBuilder - Fix isRegisterPending not considered in isEmpty, clone, equals, hashCode#1595
claude[bot] wants to merge 1 commit intomasterfrom
maintenance/fix-command-builder-is-register-pending

Conversation

@claude
Copy link

@claude claude bot commented Mar 3, 2026

Summary

  • Area inspected: vim-engine/.../command/CommandBuilder.kt
  • Issues found: isRegisterPending was missing from isEmpty, clone(), equals(), and hashCode()
  • Changes made: Added isRegisterPending to all four methods + regression test

Details

CommandBuilder tracks whether the user has typed " to begin a register selection via the isRegisterPending field. However, this field was not included in several key methods:

isEmpty bug (observable)

isEmpty returned true even while isRegisterPending = true (i.e., after the user typed " but before selecting a register character). This caused EditorResetConsumer to treat the partially-built command as empty when processing <Esc>, potentially triggering an incorrect error indicator (beep) when cancelling register selection in Normal mode. In Vim, pressing <Esc> to cancel a partially-built command should not produce an error.

clone() bug (latent)

clone() did not copy isRegisterPending, so a cloned CommandBuilder would lose its pending-register state. This is a latent bug that would affect AsyncKeyProcessBuilder if it were ever used.

equals() / hashCode() bug (correctness)

Two CommandBuilder instances differing only in isRegisterPending were incorrectly considered equal.

Test

Added a regression test in CopyActionTest that:

  1. Types " to start register selection
  2. Asserts commandBuilder.isEmpty == false (would fail before fix)
  3. Types <Esc> to cancel
  4. Asserts commandBuilder.isEmpty == true

…gisterPending

The `isRegisterPending` field was not considered in several methods of
`CommandBuilder`, causing subtle bugs:

- `isEmpty` returned `true` while waiting for a register character
  (after typing `"`), which caused `EditorResetConsumer` to treat the
  partially-built command as if no command was in progress. This could
  trigger an incorrect error indicator (beep) when pressing `<Esc>` to
  cancel register selection in Normal mode, instead of silently resetting.

- `clone()` did not copy `isRegisterPending`, meaning a cloned builder
  would lose pending register state. This is a latent bug affecting the
  unused `AsyncKeyProcessBuilder`.

- `equals()` and `hashCode()` did not include `isRegisterPending`, so
  two builders differing only in pending-register state were considered
  equal, which is incorrect.

Add a regression test that verifies `isEmpty` returns `false` while a
register selection is pending, and `true` after cancelling with Escape.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

0 participants