perf: fast-path grapheme counts and cache terminal layouts

This commit is contained in:
2026-10-10 00:41:29 +02:00
parent 05c044bd02
commit 455108a909
5 changed files with 47 additions and 3 deletions
+35 -1
View File
@@ -4516,7 +4516,12 @@ fn split_lines(text: &str) -> Vec<String> {
}
fn grapheme_count(line: &str) -> usize {
line.graphemes(true).count()
if line.is_ascii() {
// CRLF is the only multi-byte ASCII grapheme.
line.len() - line.matches("\r\n").count()
} else {
line.graphemes(true).count()
}
}
fn grapheme_byte(line: &str, column: usize) -> usize {
line.grapheme_indices(true)
@@ -5525,6 +5530,35 @@ mod tests {
assert!(editor.semantic_tokens().is_empty());
}
#[test]
fn semantic_column_bounds_preserve_ascii_tabs_and_unicode_graphemes() {
use crate::plugin::SemanticTokenKind;
for text in ["a\tb", "e\u{301}界👩‍🚀"] {
let mut editor = editor();
editor.apply(vec![Effect::Replace(text.into())]).unwrap();
let token = SemanticToken {
start: TextPosition { row: 0, column: 0 },
end: TextPosition { row: 0, column: 3 },
kind: SemanticTokenKind::Variable,
modifiers: 0,
};
editor
.replace_semantic_tokens(1, editor.text_revision(), Some(Arc::from([token])))
.unwrap();
let outside = SemanticToken {
end: TextPosition { row: 0, column: 4 },
..token
};
assert!(
editor
.replace_semantic_tokens(1, editor.text_revision(), Some(Arc::from([outside])))
.is_err(),
"{text:?}",
);
assert_eq!(editor.semantic_tokens(), &[token]);
}
}
#[test]
fn hover_scroll_and_escape_preserve_carets_and_edits_dismiss_normally() {
let mut editor = editor();