Skip to content

Fix precedence of ui.virtual.whitespace #8733

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions helix-term/src/ui/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,6 @@ pub fn render_text<'t>(
pub struct TextRenderer<'a> {
pub surface: &'a mut Surface,
pub text_style: Style,
pub whitespace_style: Style,
pub indent_guide_char: String,
pub indent_guide_style: Style,
pub newline: String,
Expand Down Expand Up @@ -374,7 +373,6 @@ impl<'a> TextRenderer<'a> {
space,
tab,
virtual_tab,
whitespace_style: theme.get("ui.virtual.whitespace"),
indent_width,
starting_indent: col_offset / indent_width as usize
+ (col_offset % indent_width as usize != 0) as usize
Expand All @@ -395,20 +393,14 @@ impl<'a> TextRenderer<'a> {
pub fn draw_grapheme(
&mut self,
grapheme: Grapheme,
mut style: Style,
style: Style,
is_virtual: bool,
last_indent_level: &mut usize,
is_in_indent_area: &mut bool,
position: Position,
) {
let cut_off_start = self.col_offset.saturating_sub(position.col);
let is_whitespace = grapheme.is_whitespace();

// TODO is it correct to apply the whitespace style to all unicode white spaces?
if is_whitespace {
style = style.patch(self.whitespace_style);
}

let width = grapheme.width();
let space = if is_virtual { " " } else { &self.space };
let nbsp = if is_virtual { " " } else { &self.nbsp };
Expand Down
62 changes: 62 additions & 0 deletions helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ impl EditorView {
highlights = Box::new(syntax::merge(highlights, overlay_highlights));
}

let whitespace_highlights =
Self::doc_whitespace_highlights(doc, view.offset.anchor, inner.height, theme);
highlights = Box::new(syntax::merge(highlights, whitespace_highlights));

for diagnostic in Self::doc_diagnostics_highlights(doc, theme) {
// Most of the `diagnostic` Vecs are empty most of the time. Skipping
// a merge for any empty Vec saves a significant amount of work.
Expand Down Expand Up @@ -393,6 +397,64 @@ impl EditorView {
[default_vec, info_vec, hint_vec, warning_vec, error_vec]
}

/// Get highlight spans for whitespace in a document view.
pub fn doc_whitespace_highlights(
doc: &Document,
anchor: usize,
height: u16,
theme: &Theme,
) -> Vec<(usize, std::ops::Range<usize>)> {
let whitespace_scope = match theme.find_scope_index_exact("ui.virtual.whitespace") {
Some(scope) => scope,
None => return Vec::new(),
};

let text = doc.text().slice(..);
let row = text.char_to_line(anchor.min(text.len_chars()));

let range = {
// Calculate viewport char 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_char(row.min(last_line));
let end = text.line_to_char(last_visible_line + 1);

start..end
};

let mut spans: Vec<(usize, std::ops::Range<usize>)> =
Vec::with_capacity(10 * height as usize);

// Aggregate adjacent whitespace characters into a single span
// Necessary to avoid splitting \r\n, which would result in highlighting offset mismatches
let mut cur_span: Option<std::ops::Range<usize>> = None;
for i in range {
let c = text.char(i);
if c.is_whitespace() {
match cur_span {
None => {
cur_span = Some(i..i + 1);
}
Some(span) => {
if span.end == i {
// Current span is adjacent to previous span
cur_span = Some(span.start..i + 1);
} else {
spans.push((whitespace_scope, span));
cur_span = Some(i..i + 1);
}
}
}
}
}
if let Some(span) = cur_span {
spans.push((whitespace_scope, span));
}

spans
}

/// Get highlight spans for selections in a document view.
pub fn doc_selection_highlights(
mode: Mode,
Expand Down
7 changes: 7 additions & 0 deletions helix-term/src/ui/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,13 @@ impl<T: Item + 'static> Picker<T> {
area.height,
&cx.editor.theme,
);
let whitespace_highlights = EditorView::doc_whitespace_highlights(
doc,
offset.anchor,
area.height,
&cx.editor.theme,
);
highlights = Box::new(helix_core::syntax::merge(highlights, whitespace_highlights));
for spans in EditorView::doc_diagnostics_highlights(doc, &cx.editor.theme) {
if spans.is_empty() {
continue;
Expand Down