Fix precedence of ui.virtual.whitespace (#8879)

* Revert "Revert "Fix precedence of ui.virtual.whitespace (#8750)""

This reverts commit 811d62d3b3.

* Fix ui.text overwriting the syntax highlighting

Adjust ui.text description
pull/8908/head^2
chtenb 1 year ago committed by GitHub
parent 8b0ae3d279
commit 8c68074fa6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -303,7 +303,7 @@ These scopes are used for theming the editor interface:
| `ui.popup.info` | Prompt for multiple key options | | `ui.popup.info` | Prompt for multiple key options |
| `ui.window` | Borderlines separating splits | | `ui.window` | Borderlines separating splits |
| `ui.help` | Description box for commands | | `ui.help` | Description box for commands |
| `ui.text` | Command prompts, popup text, etc. | | `ui.text` | Default text style, command prompts, popup text, etc. |
| `ui.text.focus` | The currently selected line in the picker | | `ui.text.focus` | The currently selected line in the picker |
| `ui.text.inactive` | Same as `ui.text` but when the text is inactive (e.g. suggestions) | | `ui.text.inactive` | Same as `ui.text` but when the text is inactive (e.g. suggestions) |
| `ui.text.info` | The key: command text in `ui.popup.info` boxes | | `ui.text.info` | The key: command text in `ui.popup.info` boxes |

@ -97,7 +97,8 @@ pub fn render_document(
doc: &Document, doc: &Document,
offset: ViewPosition, offset: ViewPosition,
doc_annotations: &TextAnnotations, doc_annotations: &TextAnnotations,
highlight_iter: impl Iterator<Item = HighlightEvent>, syntax_highlight_iter: impl Iterator<Item = HighlightEvent>,
overlay_highlight_iter: impl Iterator<Item = HighlightEvent>,
theme: &Theme, theme: &Theme,
line_decoration: &mut [Box<dyn LineDecoration + '_>], line_decoration: &mut [Box<dyn LineDecoration + '_>],
translated_positions: &mut [TranslatedPosition], translated_positions: &mut [TranslatedPosition],
@ -109,7 +110,8 @@ pub fn render_document(
offset, offset,
&doc.text_format(viewport.width, Some(theme)), &doc.text_format(viewport.width, Some(theme)),
doc_annotations, doc_annotations,
highlight_iter, syntax_highlight_iter,
overlay_highlight_iter,
theme, theme,
line_decoration, line_decoration,
translated_positions, translated_positions,
@ -157,7 +159,8 @@ pub fn render_text<'t>(
offset: ViewPosition, offset: ViewPosition,
text_fmt: &TextFormat, text_fmt: &TextFormat,
text_annotations: &TextAnnotations, text_annotations: &TextAnnotations,
highlight_iter: impl Iterator<Item = HighlightEvent>, syntax_highlight_iter: impl Iterator<Item = HighlightEvent>,
overlay_highlight_iter: impl Iterator<Item = HighlightEvent>,
theme: &Theme, theme: &Theme,
line_decorations: &mut [Box<dyn LineDecoration + '_>], line_decorations: &mut [Box<dyn LineDecoration + '_>],
translated_positions: &mut [TranslatedPosition], translated_positions: &mut [TranslatedPosition],
@ -178,10 +181,16 @@ pub fn render_text<'t>(
let (mut formatter, mut first_visible_char_idx) = let (mut formatter, mut first_visible_char_idx) =
DocumentFormatter::new_at_prev_checkpoint(text, text_fmt, text_annotations, offset.anchor); DocumentFormatter::new_at_prev_checkpoint(text, text_fmt, text_annotations, offset.anchor);
let mut styles = StyleIter { let mut syntax_styles = StyleIter {
text_style: renderer.text_style, text_style: renderer.text_style,
active_highlights: Vec::with_capacity(64), active_highlights: Vec::with_capacity(64),
highlight_iter, highlight_iter: syntax_highlight_iter,
theme,
};
let mut overlay_styles = StyleIter {
text_style: Style::default(),
active_highlights: Vec::with_capacity(64),
highlight_iter: overlay_highlight_iter,
theme, theme,
}; };
@ -193,7 +202,10 @@ pub fn render_text<'t>(
}; };
let mut is_in_indent_area = true; let mut is_in_indent_area = true;
let mut last_line_indent_level = 0; let mut last_line_indent_level = 0;
let mut style_span = styles let mut syntax_style_span = syntax_styles
.next()
.unwrap_or_else(|| (Style::default(), usize::MAX));
let mut overlay_style_span = overlay_styles
.next() .next()
.unwrap_or_else(|| (Style::default(), usize::MAX)); .unwrap_or_else(|| (Style::default(), usize::MAX));
@ -221,9 +233,16 @@ pub fn render_text<'t>(
// skip any graphemes on visual lines before the block start // skip any graphemes on visual lines before the block start
if pos.row < row_off { if pos.row < row_off {
if char_pos >= style_span.1 { if char_pos >= syntax_style_span.1 {
style_span = if let Some(style_span) = styles.next() { syntax_style_span = if let Some(syntax_style_span) = syntax_styles.next() {
style_span syntax_style_span
} else {
break;
}
}
if char_pos >= overlay_style_span.1 {
overlay_style_span = if let Some(overlay_style_span) = overlay_styles.next() {
overlay_style_span
} else { } else {
break; break;
} }
@ -260,8 +279,15 @@ pub fn render_text<'t>(
} }
// acquire the correct grapheme style // acquire the correct grapheme style
if char_pos >= style_span.1 { if char_pos >= syntax_style_span.1 {
style_span = styles.next().unwrap_or((Style::default(), usize::MAX)); syntax_style_span = syntax_styles
.next()
.unwrap_or((Style::default(), usize::MAX));
}
if char_pos >= overlay_style_span.1 {
overlay_style_span = overlay_styles
.next()
.unwrap_or((Style::default(), usize::MAX));
} }
char_pos += grapheme.doc_chars(); char_pos += grapheme.doc_chars();
@ -275,22 +301,25 @@ pub fn render_text<'t>(
pos, pos,
); );
let grapheme_style = if let GraphemeSource::VirtualText { highlight } = grapheme.source { let (syntax_style, overlay_style) =
let style = renderer.text_style; if let GraphemeSource::VirtualText { highlight } = grapheme.source {
let mut style = renderer.text_style;
if let Some(highlight) = highlight { if let Some(highlight) = highlight {
style.patch(theme.highlight(highlight.0)) style = style.patch(theme.highlight(highlight.0))
} else {
style
} }
(style, Style::default())
} else { } else {
style_span.0 (syntax_style_span.0, overlay_style_span.0)
}; };
let virt = grapheme.is_virtual(); let is_virtual = grapheme.is_virtual();
renderer.draw_grapheme( renderer.draw_grapheme(
grapheme.grapheme, grapheme.grapheme,
grapheme_style, GraphemeStyle {
virt, syntax_style,
overlay_style,
},
is_virtual,
&mut last_line_indent_level, &mut last_line_indent_level,
&mut is_in_indent_area, &mut is_in_indent_area,
pos, pos,
@ -322,6 +351,11 @@ pub struct TextRenderer<'a> {
pub viewport: Rect, pub viewport: Rect,
} }
pub struct GraphemeStyle {
syntax_style: Style,
overlay_style: Style,
}
impl<'a> TextRenderer<'a> { impl<'a> TextRenderer<'a> {
pub fn new( pub fn new(
surface: &'a mut Surface, surface: &'a mut Surface,
@ -395,7 +429,7 @@ impl<'a> TextRenderer<'a> {
pub fn draw_grapheme( pub fn draw_grapheme(
&mut self, &mut self,
grapheme: Grapheme, grapheme: Grapheme,
mut style: Style, grapheme_style: GraphemeStyle,
is_virtual: bool, is_virtual: bool,
last_indent_level: &mut usize, last_indent_level: &mut usize,
is_in_indent_area: &mut bool, is_in_indent_area: &mut bool,
@ -405,9 +439,11 @@ impl<'a> TextRenderer<'a> {
let is_whitespace = grapheme.is_whitespace(); let is_whitespace = grapheme.is_whitespace();
// TODO is it correct to apply the whitespace style to all unicode white spaces? // TODO is it correct to apply the whitespace style to all unicode white spaces?
let mut style = grapheme_style.syntax_style;
if is_whitespace { if is_whitespace {
style = style.patch(self.whitespace_style); style = style.patch(self.whitespace_style);
} }
style = style.patch(grapheme_style.overlay_style);
let width = grapheme.width(); let width = grapheme.width();
let space = if is_virtual { " " } else { &self.space }; let space = if is_virtual { " " } else { &self.space };

@ -124,16 +124,20 @@ impl EditorView {
line_decorations.push(Box::new(line_decoration)); line_decorations.push(Box::new(line_decoration));
} }
let mut highlights = let syntax_highlights =
Self::doc_syntax_highlights(doc, view.offset.anchor, inner.height, theme); Self::doc_syntax_highlights(doc, view.offset.anchor, inner.height, theme);
let overlay_highlights = Self::overlay_syntax_highlights(
let mut overlay_highlights =
Self::empty_highlight_iter(doc, view.offset.anchor, inner.height);
let overlay_syntax_highlights = Self::overlay_syntax_highlights(
doc, doc,
view.offset.anchor, view.offset.anchor,
inner.height, inner.height,
&text_annotations, &text_annotations,
); );
if !overlay_highlights.is_empty() { if !overlay_syntax_highlights.is_empty() {
highlights = Box::new(syntax::merge(highlights, overlay_highlights)); overlay_highlights =
Box::new(syntax::merge(overlay_highlights, overlay_syntax_highlights));
} }
for diagnostic in Self::doc_diagnostics_highlights(doc, theme) { for diagnostic in Self::doc_diagnostics_highlights(doc, theme) {
@ -142,12 +146,12 @@ impl EditorView {
if diagnostic.is_empty() { if diagnostic.is_empty() {
continue; continue;
} }
highlights = Box::new(syntax::merge(highlights, diagnostic)); overlay_highlights = Box::new(syntax::merge(overlay_highlights, diagnostic));
} }
let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused { if is_focused {
let highlights = syntax::merge( let highlights = syntax::merge(
highlights, overlay_highlights,
Self::doc_selection_highlights( Self::doc_selection_highlights(
editor.mode(), editor.mode(),
doc, doc,
@ -158,13 +162,11 @@ impl EditorView {
); );
let focused_view_elements = Self::highlight_focused_view_elements(view, doc, theme); let focused_view_elements = Self::highlight_focused_view_elements(view, doc, theme);
if focused_view_elements.is_empty() { if focused_view_elements.is_empty() {
Box::new(highlights) overlay_highlights = Box::new(highlights)
} else { } else {
Box::new(syntax::merge(highlights, focused_view_elements)) overlay_highlights = Box::new(syntax::merge(highlights, focused_view_elements))
}
} }
} else {
Box::new(highlights)
};
let gutter_overflow = view.gutter_offset(doc) == 0; let gutter_overflow = view.gutter_offset(doc) == 0;
if !gutter_overflow { if !gutter_overflow {
@ -197,7 +199,8 @@ impl EditorView {
doc, doc,
view.offset, view.offset,
&text_annotations, &text_annotations,
highlights, syntax_highlights,
overlay_highlights,
theme, theme,
&mut line_decorations, &mut line_decorations,
&mut translated_positions, &mut translated_positions,
@ -257,16 +260,11 @@ impl EditorView {
.for_each(|area| surface.set_style(area, ruler_theme)) .for_each(|area| surface.set_style(area, ruler_theme))
} }
pub fn overlay_syntax_highlights( fn viewport_byte_range(
doc: &Document, text: helix_core::RopeSlice,
anchor: usize, row: usize,
height: u16, height: u16,
text_annotations: &TextAnnotations, ) -> std::ops::Range<usize> {
) -> Vec<(usize, std::ops::Range<usize>)> {
let text = doc.text().slice(..);
let row = text.char_to_line(anchor.min(text.len_chars()));
let range = {
// Calculate viewport byte ranges: // Calculate viewport byte ranges:
// Saturating subs to make it inclusive zero indexing. // Saturating subs to make it inclusive zero indexing.
let last_line = text.len_lines().saturating_sub(1); let last_line = text.len_lines().saturating_sub(1);
@ -275,9 +273,26 @@ impl EditorView {
let end = text.line_to_byte(last_visible_line + 1); let end = text.line_to_byte(last_visible_line + 1);
start..end start..end
}; }
text_annotations.collect_overlay_highlights(range) pub fn empty_highlight_iter(
doc: &Document,
anchor: usize,
height: u16,
) -> Box<dyn Iterator<Item = HighlightEvent>> {
let text = doc.text().slice(..);
let row = text.char_to_line(anchor.min(text.len_chars()));
// Calculate viewport byte ranges:
// Saturating subs to make it inclusive zero indexing.
let range = Self::viewport_byte_range(text, row, height);
Box::new(
[HighlightEvent::Source {
start: text.byte_to_char(range.start),
end: text.byte_to_char(range.end),
}]
.into_iter(),
)
} }
/// Get syntax highlights for a document in a view represented by the first line /// Get syntax highlights for a document in a view represented by the first line
@ -292,16 +307,7 @@ impl EditorView {
let text = doc.text().slice(..); let text = doc.text().slice(..);
let row = text.char_to_line(anchor.min(text.len_chars())); let row = text.char_to_line(anchor.min(text.len_chars()));
let range = { let range = Self::viewport_byte_range(text, row, height);
// Calculate viewport byte ranges:
// Saturating subs to make it inclusive zero indexing.
let last_line = text.len_lines().saturating_sub(1);
let last_visible_line = (row + height as usize).saturating_sub(1).min(last_line);
let start = text.line_to_byte(row.min(last_line));
let end = text.line_to_byte(last_visible_line + 1);
start..end
};
match doc.syntax() { match doc.syntax() {
Some(syntax) => { Some(syntax) => {
@ -334,6 +340,20 @@ impl EditorView {
} }
} }
pub fn overlay_syntax_highlights(
doc: &Document,
anchor: usize,
height: u16,
text_annotations: &TextAnnotations,
) -> Vec<(usize, std::ops::Range<usize>)> {
let text = doc.text().slice(..);
let row = text.char_to_line(anchor.min(text.len_chars()));
let range = Self::viewport_byte_range(text, row, height);
text_annotations.collect_overlay_highlights(range)
}
/// Get highlight spans for document diagnostics /// Get highlight spans for document diagnostics
pub fn doc_diagnostics_highlights( pub fn doc_diagnostics_highlights(
doc: &Document, doc: &Document,

@ -736,17 +736,20 @@ impl<T: Item + 'static> Picker<T> {
} }
} }
let mut highlights = EditorView::doc_syntax_highlights( let syntax_highlights = EditorView::doc_syntax_highlights(
doc, doc,
offset.anchor, offset.anchor,
area.height, area.height,
&cx.editor.theme, &cx.editor.theme,
); );
let mut overlay_highlights =
EditorView::empty_highlight_iter(doc, offset.anchor, area.height);
for spans in EditorView::doc_diagnostics_highlights(doc, &cx.editor.theme) { for spans in EditorView::doc_diagnostics_highlights(doc, &cx.editor.theme) {
if spans.is_empty() { if spans.is_empty() {
continue; continue;
} }
highlights = Box::new(helix_core::syntax::merge(highlights, spans)); overlay_highlights = Box::new(helix_core::syntax::merge(overlay_highlights, spans));
} }
let mut decorations: Vec<Box<dyn LineDecoration>> = Vec::new(); let mut decorations: Vec<Box<dyn LineDecoration>> = Vec::new();
@ -777,7 +780,8 @@ impl<T: Item + 'static> Picker<T> {
offset, offset,
// TODO: compute text annotations asynchronously here (like inlay hints) // TODO: compute text annotations asynchronously here (like inlay hints)
&TextAnnotations::default(), &TextAnnotations::default(),
highlights, syntax_highlights,
overlay_highlights,
&cx.editor.theme, &cx.editor.theme,
&mut decorations, &mut decorations,
&mut [], &mut [],

Loading…
Cancel
Save