mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-22 09:26:19 +04:00
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
This commit is contained in:
parent
8b0ae3d279
commit
8c68074fa6
@ -303,7 +303,7 @@ #### 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 {
|
||||||
if let Some(highlight) = highlight {
|
let mut style = renderer.text_style;
|
||||||
style.patch(theme.highlight(highlight.0))
|
if let Some(highlight) = highlight {
|
||||||
|
style = style.patch(theme.highlight(highlight.0))
|
||||||
|
}
|
||||||
|
(style, Style::default())
|
||||||
} else {
|
} else {
|
||||||
style
|
(syntax_style_span.0, overlay_style_span.0)
|
||||||
}
|
};
|
||||||
} else {
|
|
||||||
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 @@ pub fn new(
|
|||||||
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 @@ pub fn draw_grapheme(
|
|||||||
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 @@ pub fn render_view(
|
|||||||
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 @@ pub fn render_view(
|
|||||||
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 @@ pub fn render_view(
|
|||||||
);
|
);
|
||||||
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 @@ pub fn render_view(
|
|||||||
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,27 +260,39 @@ pub fn render_rulers(
|
|||||||
.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(
|
||||||
|
text: helix_core::RopeSlice,
|
||||||
|
row: usize,
|
||||||
|
height: u16,
|
||||||
|
) -> std::ops::Range<usize> {
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn empty_highlight_iter(
|
||||||
doc: &Document,
|
doc: &Document,
|
||||||
anchor: usize,
|
anchor: usize,
|
||||||
height: u16,
|
height: u16,
|
||||||
text_annotations: &TextAnnotations,
|
) -> Box<dyn Iterator<Item = HighlightEvent>> {
|
||||||
) -> Vec<(usize, std::ops::Range<usize>)> {
|
|
||||||
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 = {
|
// 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 range = Self::viewport_byte_range(text, row, height);
|
||||||
let last_line = text.len_lines().saturating_sub(1);
|
Box::new(
|
||||||
let last_visible_line = (row + height as usize).saturating_sub(1).min(last_line);
|
[HighlightEvent::Source {
|
||||||
let start = text.line_to_byte(row.min(last_line));
|
start: text.byte_to_char(range.start),
|
||||||
let end = text.line_to_byte(last_visible_line + 1);
|
end: text.byte_to_char(range.end),
|
||||||
|
}]
|
||||||
start..end
|
.into_iter(),
|
||||||
};
|
)
|
||||||
|
|
||||||
text_annotations.collect_overlay_highlights(range)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 @@ pub fn doc_syntax_highlights<'doc>(
|
|||||||
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 @@ pub fn doc_syntax_highlights<'doc>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 @@ fn render_preview(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 @@ fn render_preview(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context
|
|||||||
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…
Reference in New Issue
Block a user