diff options
| author | bors <bors@rust-lang.org> | 2024-06-19 08:13:18 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-06-19 08:13:18 +0000 |
| commit | cbbdf1e8b1e96cd022028bfd7be87ea1c54778c4 (patch) | |
| tree | c90f2387ec9f2d366339ca5a3ded343b47ba619a /src | |
| parent | cf50b298bfbc90f9645abc0f6ef7d363aac9f41e (diff) | |
| parent | 9ce8a96755aa56bd73c74f106195ac5abf97fd67 (diff) | |
| download | rust-cbbdf1e8b1e96cd022028bfd7be87ea1c54778c4.tar.gz rust-cbbdf1e8b1e96cd022028bfd7be87ea1c54778c4.zip | |
Auto merge of #17426 - roife:fix-issue-17420, r=Veykril
fix: handle character boundaries for wide chars in extend_selection fix #17420. When calling 'extend_selection' within a string, r-a attempts to locate the current word at the cursor. This is done by finding the first char before the cursor which is not a letter, digit, or underscore. The position of this character is referred to as `start_idx`, and the word is considered to start from `start_idx + 1`. However, for wide characters, `start_idx + 1` is not character boundaries, which leading to panic. We should use `ceil_char_boundary` to ensure that the idx is always on character boundaries.
Diffstat (limited to 'src')
| -rw-r--r-- | src/tools/rust-analyzer/crates/ide/src/extend_selection.rs | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs index b706e959d34..e8d6dc97341 100644 --- a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs +++ b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs @@ -210,7 +210,13 @@ fn extend_single_word_in_comment_or_string( let start_idx = before.rfind(non_word_char)? as u32; let end_idx = after.find(non_word_char).unwrap_or(after.len()) as u32; - let from: TextSize = (start_idx + 1).into(); + // FIXME: use `ceil_char_boundary` from `std::str` when it gets stable + // https://github.com/rust-lang/rust/issues/93743 + fn ceil_char_boundary(text: &str, index: u32) -> u32 { + (index..).find(|&index| text.is_char_boundary(index as usize)).unwrap_or(text.len() as u32) + } + + let from: TextSize = ceil_char_boundary(text, start_idx + 1).into(); let to: TextSize = (cursor_position + end_idx).into(); let range = TextRange::new(from, to); @@ -662,4 +668,18 @@ fn main() { let ( ], ); } + + #[test] + fn extend_selection_inside_str_with_wide_char() { + // should not panic + do_check( + r#"fn main() { let x = "═$0═══════"; }"#, + &[ + r#""════════""#, + r#"let x = "════════";"#, + r#"{ let x = "════════"; }"#, + r#"fn main() { let x = "════════"; }"#, + ], + ); + } } |
