Do not print invisibles in non-full mode editors

This commit is contained in:
Kirill Bulatov 2023-05-05 18:32:10 +03:00 committed by Kirill Bulatov
parent ab6b3adb2b
commit d2b2dc39d9

View File

@ -1382,6 +1382,7 @@ impl EditorElement {
MAX_LINE_LEN,
rows.len() as usize,
line_number_layouts,
snapshot.mode,
)
}
}
@ -1728,6 +1729,7 @@ fn layout_highlighted_chunks<'a>(
max_line_len: usize,
max_line_count: usize,
line_number_layouts: &[Option<Line>],
editor_mode: EditorMode,
) -> Vec<LineWithInvisibles> {
let mut layouts = Vec::with_capacity(max_line_count);
let mut line = String::new();
@ -1787,30 +1789,37 @@ fn layout_highlighted_chunks<'a>(
},
));
// Line wrap pads its contents with fake whitespaces,
// avoid printing them
let inside_wrapped_string = line_number_layouts[row].is_none();
if highlighted_chunk.is_tab {
if non_whitespace_added || !inside_wrapped_string {
invisibles.push(Invisible::Tab {
line_start_offset: line.len(),
});
if editor_mode == EditorMode::Full {
// Line wrap pads its contents with fake whitespaces,
// avoid printing them
let inside_wrapped_string = line_number_layouts
.get(row)
.and_then(|layout| layout.as_ref())
.is_none();
if highlighted_chunk.is_tab {
if non_whitespace_added || !inside_wrapped_string {
invisibles.push(Invisible::Tab {
line_start_offset: line.len(),
});
}
} else {
invisibles.extend(
line_chunk
.chars()
.enumerate()
.filter(|(_, line_char)| {
let is_whitespace = line_char.is_whitespace();
non_whitespace_added |= !is_whitespace;
is_whitespace
&& (non_whitespace_added || !inside_wrapped_string)
})
.map(|(whitespace_index, _)| Invisible::Whitespace {
line_offset: line.len() + whitespace_index,
}),
)
}
} else {
invisibles.extend(
line_chunk
.chars()
.enumerate()
.filter(|(_, line_char)| {
let is_whitespace = line_char.is_whitespace();
non_whitespace_added |= !is_whitespace;
is_whitespace && (non_whitespace_added || !inside_wrapped_string)
})
.map(|(whitespace_index, _)| Invisible::Whitespace {
line_offset: line.len() + whitespace_index,
}),
)
}
line.push_str(line_chunk);
}
}
@ -2925,4 +2934,56 @@ mod tests {
assert_eq!(expected_invisibles, actual_invisibles);
}
#[gpui::test]
fn test_invisibles_dont_appear_in_certain_editors(cx: &mut TestAppContext) {
cx.update(|cx| {
let mut test_settings = Settings::test(cx);
test_settings.editor_defaults.show_whitespaces = Some(ShowWhitespaces::All);
test_settings.editor_defaults.tab_size = Some(NonZeroU32::new(4).unwrap());
cx.set_global(test_settings);
});
for editor_mode_without_invisibles in [
EditorMode::SingleLine,
EditorMode::AutoHeight { max_lines: 100 },
] {
let (_, editor) = cx.add_window(|cx| {
let buffer = MultiBuffer::build_simple("\t\t\t| | a b", cx);
Editor::new(editor_mode_without_invisibles, buffer, None, None, cx)
});
let mut element =
EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
let (_, layout_state) = editor.update(cx, |editor, cx| {
let mut new_parents = Default::default();
let mut notify_views_if_parents_change = Default::default();
let mut layout_cx = LayoutContext::new(
cx,
&mut new_parents,
&mut notify_views_if_parents_change,
false,
);
element.layout(
SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)),
editor,
&mut layout_cx,
)
});
let line_layouts = &layout_state.position_map.line_layouts;
let invisibles = line_layouts
.iter()
.map(|line_with_invisibles| &line_with_invisibles.invisibles)
.flatten()
.sorted_by(|invisible_1, invisible_2| {
invisible_1.offset().cmp(&invisible_2.offset())
})
.cloned()
.collect::<Vec<_>>();
assert!(invisibles.is_empty(),
"For editor mode {editor_mode_without_invisibles:?} no invisibles was expected but got {invisibles:?}");
}
}
}