mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
Respect max line limit for invisible character replacements (#57137)
This change makes sure that `LineWithInvisibles::from_chunks` applies the max line length limit to invisible character replacements as it does to normal text chunks. Without this change, pathological lines containing many invisible characters could produce unbounded number of line fragments. Closes FR-6. Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - Fixed a rare panic that could occur when lines in the editor contained many invisible characters.
This commit is contained in:
parent
bc363322af
commit
d33a3186aa
1 changed files with 77 additions and 2 deletions
|
|
@ -9001,6 +9001,15 @@ impl LineWithInvisibles {
|
|||
replacement: None,
|
||||
}]) {
|
||||
if let Some(replacement) = highlighted_chunk.replacement {
|
||||
if line_exceeded_max_len {
|
||||
continue;
|
||||
}
|
||||
|
||||
if len + line.len() + highlighted_chunk.text.len() > max_line_len {
|
||||
line_exceeded_max_len = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if !line.is_empty() {
|
||||
let segments = bg_segments_per_row.get(row).map(|v| &v[..]).unwrap_or(&[]);
|
||||
let text_runs: &[TextRun] = if segments.is_empty() {
|
||||
|
|
@ -9132,8 +9141,9 @@ impl LineWithInvisibles {
|
|||
Cow::Borrowed(text_style)
|
||||
};
|
||||
|
||||
if line.len() + line_chunk.len() > max_line_len {
|
||||
let mut chunk_len = max_line_len - line.len();
|
||||
let current_line_len = len + line.len();
|
||||
if current_line_len + line_chunk.len() > max_line_len {
|
||||
let mut chunk_len = max_line_len - current_line_len;
|
||||
while !line_chunk.is_char_boundary(chunk_len) {
|
||||
chunk_len -= 1;
|
||||
}
|
||||
|
|
@ -9141,6 +9151,10 @@ impl LineWithInvisibles {
|
|||
line_exceeded_max_len = true;
|
||||
}
|
||||
|
||||
if line_chunk.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
styles.push(TextRun {
|
||||
len: line_chunk.len(),
|
||||
font: text_style.font(),
|
||||
|
|
@ -13573,6 +13587,67 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_replacement_chunks_are_clipped_to_max_line_len(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let window = cx.add_window(|window, cx| {
|
||||
let buffer = MultiBuffer::build_simple("", cx);
|
||||
Editor::new(EditorMode::full(), buffer, None, window, cx)
|
||||
});
|
||||
let cx = &mut VisualTestContext::from_window(*window, cx);
|
||||
let editor = window.root(cx).unwrap();
|
||||
let style = cx.update(|_, cx| editor.update(cx, |editor, cx| editor.style(cx).clone()));
|
||||
let editor_mode = EditorMode::full();
|
||||
let max_line_len = "\u{00a0}abcdef".len();
|
||||
|
||||
window
|
||||
.update(cx, |_, window, cx| {
|
||||
let chunks = std::iter::once(HighlightedChunk {
|
||||
text: "\u{00a0}",
|
||||
style: None,
|
||||
is_tab: false,
|
||||
is_inlay: false,
|
||||
replacement: Some(ChunkReplacement::Str("\u{2007}".into())),
|
||||
})
|
||||
.chain(std::iter::once(HighlightedChunk {
|
||||
text: "abcdefghi",
|
||||
style: None,
|
||||
is_tab: false,
|
||||
is_inlay: false,
|
||||
replacement: None,
|
||||
}))
|
||||
.chain(
|
||||
std::iter::repeat_with(|| HighlightedChunk {
|
||||
text: "\u{00a0}",
|
||||
style: None,
|
||||
is_tab: false,
|
||||
is_inlay: false,
|
||||
replacement: Some(ChunkReplacement::Str("\u{2007}".into())),
|
||||
})
|
||||
.take(8),
|
||||
);
|
||||
|
||||
let layouts = LineWithInvisibles::from_chunks(
|
||||
chunks,
|
||||
&style,
|
||||
max_line_len,
|
||||
1,
|
||||
&editor_mode,
|
||||
px(500.),
|
||||
|_| false,
|
||||
&[],
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
||||
assert_eq!(layouts.len(), 1);
|
||||
assert_eq!(layouts[0].len, max_line_len);
|
||||
assert!(layouts[0].fragments.len() <= max_line_len);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_invisibles_dont_appear_in_certain_editors(cx: &mut TestAppContext) {
|
||||
init_test(cx, |s| {
|
||||
|
|
|
|||
Loading…
Reference in a new issue