Skip to content

Conversation

@edlsh
Copy link
Contributor

@edlsh edlsh commented Dec 15, 2025

Summary

Fixes #44812

The hover highlight for clickable inlay hints was not covering the last character when the label contained multi-byte UTF-8 characters (e.g., ).

Problem

When hovering over an inlay hint like → app/Livewire/UserProfile.php, the highlight/underline stopped one character short, leaving the final character unhighlighted.

Root cause: find_hovered_hint_part() in hover_popover.rs used part.value.chars().count() (character count) but InlayOffset wraps MultiBufferOffset(pub usize) which is byte-based.

For a label like → app/Livewire/UserProfile.php:

  • Byte length: 32 (the character is 3 bytes in UTF-8)
  • Character count: 30

This mismatch caused the calculated highlight range to end 2 bytes short.

Changes

  1. Use byte length instead of character count (line 112):

    // Before (buggy)
    let part_len = part.value.chars().count();
    
    // After (correct)
    let part_len = part.value.len();
  2. Fix boundary condition (line 113): Changed > to >= for correct [start, end) range semantics when hovering at part boundaries.

  3. Rename variable for clarity: hovered_characteroffset_in_hint since it's a byte offset, not a character position.

  4. Add unit test reproducing the exact scenario from the issue with multi-byte UTF-8 characters.

Testing

Added test_find_hovered_hint_part_with_multibyte_characters which:

  • Verifies the label → app/Livewire/UserProfile.php has 32 bytes but 30 characters
  • Tests hovering at the last byte correctly returns the full range
  • Tests boundary behavior with multiple label parts containing multi-byte characters

Release Notes:

  • Fixed inlay hint hover highlight not covering the last character when the label contains multi-byte UTF-8 characters
@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Dec 15, 2025
Fixes zed-industries#44812

The hover highlight for clickable inlay hints was not covering the last
character when the label contained multi-byte UTF-8 characters (e.g., "→").

Root cause: `find_hovered_hint_part()` used `chars().count()` (character
count) but `InlayOffset` is byte-based. For a label like
"→ app/Livewire/UserProfile.php" (32 bytes, 30 chars), the calculated
highlight range ended 2 bytes short.

Changes:
- Use `part.value.len()` (bytes) instead of `chars().count()`
- Change boundary condition from `>` to `>=` for correct [start, end) semantics
- Rename `hovered_character` to `offset_in_hint` for clarity
- Add unit test with multi-byte characters reproducing the reported issue

Release Notes:

- Fixed inlay hint hover highlight not covering the last character when the label contains multi-byte UTF-8 characters (e.g., "→").
@edlsh edlsh force-pushed the fix/inlay-hint-hover-multibyte-chars branch from 18102a0 to ba7fbea Compare December 15, 2025 12:37
Copy link
Member

@Veykril Veykril left a comment

Choose a reason for hiding this comment

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

Thanks!

@Veykril Veykril merged commit 848d3cc into zed-industries:main Jan 4, 2026
26 checks passed
rtfeldman pushed a commit that referenced this pull request Jan 5, 2026
## Summary

Fixes #44812

The hover highlight for clickable inlay hints was not covering the last
character when the label contained multi-byte UTF-8 characters (e.g.,
`→`).

## Problem

When hovering over an inlay hint like `→ app/Livewire/UserProfile.php`,
the highlight/underline stopped one character short, leaving the final
character unhighlighted.

**Root cause:** `find_hovered_hint_part()` in `hover_popover.rs` used
`part.value.chars().count()` (character count) but `InlayOffset` wraps
`MultiBufferOffset(pub usize)` which is byte-based.

For a label like `→ app/Livewire/UserProfile.php`:
- Byte length: 32 (the `→` character is 3 bytes in UTF-8)
- Character count: 30

This mismatch caused the calculated highlight range to end 2 bytes
short.

## Changes

1. **Use byte length instead of character count** (line 112):
   ```rust
   // Before (buggy)
   let part_len = part.value.chars().count();
   
   // After (correct)
   let part_len = part.value.len();
   ```

2. **Fix boundary condition** (line 113): Changed `>` to `>=` for
correct `[start, end)` range semantics when hovering at part boundaries.

3. **Rename variable** for clarity: `hovered_character` →
`offset_in_hint` since it's a byte offset, not a character position.

4. **Add unit test** reproducing the exact scenario from the issue with
multi-byte UTF-8 characters.

## Testing

Added `test_find_hovered_hint_part_with_multibyte_characters` which:
- Verifies the label `→ app/Livewire/UserProfile.php` has 32 bytes but
30 characters
- Tests hovering at the last byte correctly returns the full range
- Tests boundary behavior with multiple label parts containing
multi-byte characters

Release Notes:

- Fixed inlay hint hover highlight not covering the last character when
the label contains multi-byte UTF-8 characters
LivioGama pushed a commit to LivioGama/zed that referenced this pull request Jan 20, 2026
…ndustries#44872)

## Summary

Fixes zed-industries#44812

The hover highlight for clickable inlay hints was not covering the last
character when the label contained multi-byte UTF-8 characters (e.g.,
`→`).

## Problem

When hovering over an inlay hint like `→ app/Livewire/UserProfile.php`,
the highlight/underline stopped one character short, leaving the final
character unhighlighted.

**Root cause:** `find_hovered_hint_part()` in `hover_popover.rs` used
`part.value.chars().count()` (character count) but `InlayOffset` wraps
`MultiBufferOffset(pub usize)` which is byte-based.

For a label like `→ app/Livewire/UserProfile.php`:
- Byte length: 32 (the `→` character is 3 bytes in UTF-8)
- Character count: 30

This mismatch caused the calculated highlight range to end 2 bytes
short.

## Changes

1. **Use byte length instead of character count** (line 112):
   ```rust
   // Before (buggy)
   let part_len = part.value.chars().count();
   
   // After (correct)
   let part_len = part.value.len();
   ```

2. **Fix boundary condition** (line 113): Changed `>` to `>=` for
correct `[start, end)` range semantics when hovering at part boundaries.

3. **Rename variable** for clarity: `hovered_character` →
`offset_in_hint` since it's a byte offset, not a character position.

4. **Add unit test** reproducing the exact scenario from the issue with
multi-byte UTF-8 characters.

## Testing

Added `test_find_hovered_hint_part_with_multibyte_characters` which:
- Verifies the label `→ app/Livewire/UserProfile.php` has 32 bytes but
30 characters
- Tests hovering at the last byte correctly returns the full range
- Tests boundary behavior with multiple label parts containing
multi-byte characters

Release Notes:

- Fixed inlay hint hover highlight not covering the last character when
the label contains multi-byte UTF-8 characters
LivioGama pushed a commit to LivioGama/zed that referenced this pull request Jan 20, 2026
…ndustries#44872)

## Summary

Fixes zed-industries#44812

The hover highlight for clickable inlay hints was not covering the last
character when the label contained multi-byte UTF-8 characters (e.g.,
`→`).

## Problem

When hovering over an inlay hint like `→ app/Livewire/UserProfile.php`,
the highlight/underline stopped one character short, leaving the final
character unhighlighted.

**Root cause:** `find_hovered_hint_part()` in `hover_popover.rs` used
`part.value.chars().count()` (character count) but `InlayOffset` wraps
`MultiBufferOffset(pub usize)` which is byte-based.

For a label like `→ app/Livewire/UserProfile.php`:
- Byte length: 32 (the `→` character is 3 bytes in UTF-8)
- Character count: 30

This mismatch caused the calculated highlight range to end 2 bytes
short.

## Changes

1. **Use byte length instead of character count** (line 112):
   ```rust
   // Before (buggy)
   let part_len = part.value.chars().count();
   
   // After (correct)
   let part_len = part.value.len();
   ```

2. **Fix boundary condition** (line 113): Changed `>` to `>=` for
correct `[start, end)` range semantics when hovering at part boundaries.

3. **Rename variable** for clarity: `hovered_character` →
`offset_in_hint` since it's a byte offset, not a character position.

4. **Add unit test** reproducing the exact scenario from the issue with
multi-byte UTF-8 characters.

## Testing

Added `test_find_hovered_hint_part_with_multibyte_characters` which:
- Verifies the label `→ app/Livewire/UserProfile.php` has 32 bytes but
30 characters
- Tests hovering at the last byte correctly returns the full range
- Tests boundary behavior with multiple label parts containing
multi-byte characters

Release Notes:

- Fixed inlay hint hover highlight not covering the last character when
the label contains multi-byte UTF-8 characters
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

2 participants