google-gemini / google-gemini/gemini-cli
Reverse search highlights the wrong substring when a history entry contains a character whose lowercase form is longer (e.g. İ)
- Dominant language
- TypeScript
- Stars
- 107k
- Forks
- 14.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 45
Description
### What happened?
Reverse search (Ctrl+R history search) can highlight the wrong substring. `useReverseSearchCompletion` computes `matchedIndex` against the *lowercased* command, but `ExpandableText` applies that index to the *original-case* label.
In `packages/cli/src/ui/hooks/useReverseSearchCompletion.ts` (lines 76-78 at revision `9c1b0a610`):
```ts
const idx = cmd.toLowerCase().indexOf(query);
if (idx !== -1) {
out.push({ label: cmd, value: cmd, matchedIndex: idx });
}
```
Most lowercasing is length-preserving, so the two indexes coincide. However, some characters change UTF-16 length when lowercased — notably `İ` (U+0130), which lowercases to two code units (`i` + U+0307). Every index after such a character is shifted by one in the lowercased copy, so the highlight lands one position too late.
Repro:
```js
const cmd = 'echo İ abc';
const query = 'abc';
const matchedIndex = cmd.toLowerCase().indexOf(query); // 8 — index into "echo i̇ abc"
cmd.slice(matchedIndex, matchedIndex + query.length); // "bc" — wrong highlight target
// 'abc' actually starts at index 7 in the original cmd
```
Component-level confirmation: rendering `SuggestionsDisplay` in reverse mode with exactly the values the hook produces for history entry `echo İ abc` and query `abc` renders the line `echo İ abc` with the inverse-video highlight on `bc` instead of `abc`.
### What did you expect to happen?
The highlight should cover the matched substring in the displayed (original-case) string — here `abc`.
### Client information
Component-level reproduction; no Gemini API request, login session, or account is involved. Verified against a working tree based on main revision `9c1b0a610534d6f8120964cf2672c07807d8fc90`; `useReverseSearchCompletion.tsx` is unmodified from that revision. Package version reports `0.61.0-nightly.20260908.gc647533d6`.
### Login information
Not applicable. No provider, API key, Google account, or network request is used by the reproducer.
### Anything else we need to know?
A fix would compute the match index against the original string (for example a case-insensitive search on `cmd` itself) instead of reusing an index from the lowercased copy, since `matchedIndex` is consumed as a UTF-16 offset into the original label. Cosmetic severity: the highlight is display-only — selection inserts the full `value`, so nothing beyond the highlight position is affected.
Contributor guide
Research direction
Start in packages/cli/src/ui/hooks/useReverseSearchCompletion.ts at the matching logic around lines 76-78, then inspect how matchedIndex is consumed by ExpandableText and SuggestionsDisplay. Reproduce the reverse search case with `echo İ abc` and query `abc`; done when the highlight covers the original-case match and the component-level reproduction passes without changing selection behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 86/100