Skip to content

fix(cli): make vim cc clear non-last and astral-character lines#27554

Open
Pluviobyte wants to merge 1 commit into
google-gemini:mainfrom
Pluviobyte:fix/vim-cc-multiline-change
Open

fix(cli): make vim cc clear non-last and astral-character lines#27554
Pluviobyte wants to merge 1 commit into
google-gemini:mainfrom
Pluviobyte:fix/vim-cc-multiline-change

Conversation

@Pluviobyte
Copy link
Copy Markdown

Summary

Vim cc (change-line) silently does nothing on any non-last line of a multi-line buffer, and on a single line containing an astral character (e.g. an emoji). It clears the line correctly only when the cursor is on the buffer's last line and the line is ASCII/BMP-only.

Details

vim_change_line derived the end of the range with two helpers (getLineRangeOffsets / getPositionFromOffsets) that:

  1. counted a trailing newline after the last changed line (when it isn't the buffer's last line), and
  2. measured columns in UTF-16 code units.

So the computed end column landed one position past the end of the line (e.g. endCol = 12 for "hello world"), or split a surrogate pair (endCol = 2 for "😀"). replaceRangeInternal rejects a range whose endCol > cpLen(line) and returns the state unchanged — a silent no-op, while the UI still switched to INSERT mode.

The fix computes the range directly in code points: from column 0 of the first line to cpLen(lastChangedLine). This clears single lines, non-last lines, multi-line counts (collapsing them into a single empty line, matching Vim), and astral characters. The two offset helpers were only used here, so they are removed.

Before / after on ['hello world', 'foo'] with the cursor on line 0:

  • before: cc['hello world', 'foo'] (unchanged)
  • after: cc['', 'foo']

Related Issues

None — found while reviewing the text-buffer vim handlers. Happy to file a tracking issue if preferred.

How to Validate

cd packages/cli
npm run typecheck
npx vitest run src/ui/components/shared/vim-buffer-actions.test.ts src/ui/components/shared/text-buffer.test.ts

New tests in vim-buffer-actions.test.ts cover cc on a non-last line, on a single-line emoji buffer, and with a count (2cc). They fail on the previous implementation (the buffer is unchanged) and pass with this fix. Existing single-line cc, dd, and all text-buffer tests continue to pass (427 tests).

Pre-Merge Checklist

  • Updated relevant documentation and README (not needed — behavior fix)
  • Added/updated tests (regression tests for non-last line, emoji, and multi-count cc)
  • Noted breaking changes (none — only fixes the broken no-op cases)
  • Validated on required platforms/methods:
    • Linux
      • npm run (vitest + tsc --noEmit)

Note: platform-independent editor-logic fix covered by automated unit tests, validated via the package test suite on Linux.

Made with Cursor

`cc` (change-line) silently did nothing on any non-last line of a multi-line
buffer, and on a single line containing an astral character (e.g. an emoji).

The change-line handler derived the end of the range with two helpers that
(a) counted a trailing newline after the last changed line and (b) measured
columns in UTF-16 code units. The resulting end column landed one past the end
of the line (or split a surrogate pair), so `replaceRangeInternal` treated the
range as invalid and returned the state unchanged — while the UI still switched
to INSERT mode.

Compute the range directly in code points instead: from column 0 of the first
line to the code-point length of the last changed line. This correctly clears
single lines, non-last lines, multi-line counts (collapsing them into one empty
line) and astral characters. The now-unused getLineRangeOffsets /
getPositionFromOffsets helpers (only used here) are removed. Adds regression
tests for the multi-line, emoji and multi-count cases.
@Pluviobyte Pluviobyte requested a review from a team as a code owner May 29, 2026 08:02
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a bug in the Vim emulation layer where the cc command failed to execute correctly in several edge cases. By replacing an overly complex, offset-based range calculation with a direct code-point approach, the fix ensures that lines are cleared reliably regardless of their position in the buffer or the presence of multi-byte characters. This change improves editor stability and aligns the behavior more closely with standard Vim expectations.

Highlights

  • Vim cc Command Fix: Resolved an issue where the cc (change-line) command would silently fail on non-last lines or lines containing astral characters (e.g., emojis) due to incorrect range calculations.
  • Code Cleanup: Removed redundant getLineRangeOffsets and getPositionFromOffsets helper functions, simplifying the logic by calculating ranges directly in code points.
  • Regression Testing: Added comprehensive unit tests to vim-buffer-actions.test.ts covering non-last line clearing, emoji support, and multi-line count operations.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the vim_change_line action in the text buffer to correctly handle astral characters (such as emojis) and non-last lines of multi-line buffers. It removes the offset-based helper functions getPositionFromOffsets and getLineRangeOffsets from text-buffer.ts and instead computes the target range directly using code point lengths (cpLen). Additionally, comprehensive unit tests have been added to verify these scenarios. There are no review comments, and I have no additional feedback to provide.

@gemini-cli gemini-cli Bot added the status/need-issue Pull requests that need to have an associated issue. label May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status/need-issue Pull requests that need to have an associated issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant