From 1d0f5d7e262f44d7720bf6b07f89458cec43a14b Mon Sep 17 00:00:00 2001 From: SoraTenshi Date: Wed, 9 Aug 2023 22:59:11 +0200 Subject: [PATCH] Refactor rendering (+ make it more correct) --- helix-term/src/ui/context.rs | 167 +++++++++++++++++++---------------- helix-term/src/ui/editor.rs | 14 +-- 2 files changed, 92 insertions(+), 89 deletions(-) diff --git a/helix-term/src/ui/context.rs b/helix-term/src/ui/context.rs index 0fda166fd..5b5278ad3 100644 --- a/helix-term/src/ui/context.rs +++ b/helix-term/src/ui/context.rs @@ -1,15 +1,19 @@ +#[allow(deprecated)] +use helix_core::visual_coords_at_pos; + use helix_core::{ syntax::RopeProvider, text_annotations::TextAnnotations, tree_sitter::{QueryCursor, QueryMatch}, - visual_offset_from_block, Position, + Position, }; -use helix_view::{Document, Theme, View}; + +use helix_view::{view::ViewPosition, Document, Theme, View}; use tui::buffer::Buffer as Surface; use super::{ - document::{render_text, LineDecoration, TextRenderer, TranslatedPosition}, + document::{render_text, TextRenderer}, EditorView, }; @@ -211,8 +215,6 @@ pub fn render_sticky_context( view: &View, surface: &mut Surface, context: &Option>, - line_decoration: &mut [Box], - translated_positions: &mut [TranslatedPosition], theme: &Theme, ) { let Some(context) = context else { @@ -238,17 +240,18 @@ pub fn render_sticky_context( let mut context_area = viewport; context_area.height = 1; + const DOTS: &str = "..."; + for node in context { surface.clear_with(context_area, context_style); - let mut new_offset = view.offset; - let mut line_context_area = context_area; + let mut view_offset = view.offset; if let Some(indicator) = node.indicator.as_deref() { // set the indicator surface.set_stringn( - line_context_area.x, - line_context_area.y, + context_area.x, + context_area.y, indicator, indicator.len(), indicator_style, @@ -256,99 +259,107 @@ pub fn render_sticky_context( continue; } - // get the len of bytes of the text that will be written (the "definition" line) - let line = text.line(node.line); - let already_written = line.len_bytes() as u16; - let dots = "..."; + let node_start = text.byte_to_char(node.byte_range.start); + view_offset.anchor = node_start; - let virtual_text_annotations = TextAnnotations::default(); + let first_node_line = text.line(text.char_to_line(node_start)); + let first_node_width = first_node_line.len_chars(); - // if the definition of the function contains multiple lines - if node.has_context_end { - let line = text.byte_to_line(node.byte_range.end); - let line_start = text.line_to_char(line); - let anchor = text.byte_to_char(node.byte_range.end); - // TODO: we could avoid this when text rendering supports starting at - // a byte/char offset (doesn't work because of syntax highlighting atm) - let Position { col: whitespace_offset, .. } = pos_at_visual_coords( - text.slice(line_start..), - anchor - line_start, - ); - // calculation of the correct space where the end of the signature - // should be drawn at - let mut additional_area = line_context_area; - additional_area.x +=(already_written + dots.len() as u16); + // calculate the reserved space for the basic render + let start_node_width = first_node_width.saturating_sub( + first_node_line + .chars() + .reversed() + .position(|c| !c.is_whitespace()) + .unwrap_or(1), + ); + + #[allow(deprecated)] + let Position { + row: _, + col: start_vis_offset, + } = visual_coords_at_pos(first_node_line, start_node_width, doc.tab_width()); - // render the end of the function definition + // get the highlighting of the basic capture + let highlights = EditorView::doc_syntax_highlights(doc, node_start, 1, theme); + + let mut offset_area = context_area; + + // Limit scope of borrowed surface + { let mut renderer = TextRenderer::new( surface, doc, theme, - whitespace_offset as u16, - additional_area, - ) - let highlights = EditorView::doc_syntax_highlights(doc, new_offset.anchor, 1, theme); - let mut text_format = doc.text_format(additional_area.width.saturting_sub(already_written + dots.len() as u16), Some(theme)); - text_format.soft_wrap = false; + view.offset.horizontal_offset, + context_area, + ); + + // create the formatting for the basic node render + let mut formatting = doc.text_format(context_area.width, Some(theme)); + formatting.soft_wrap = false; render_text( &mut renderer, text, - ViewPosition { anchor, .. ViewPosition::default() }, - &text_format, - &virtual_text_annotations, + ViewPosition { + anchor: node_start, + ..ViewPosition::default() + }, + &formatting, + &TextAnnotations::default(), highlights, theme, &mut [], &mut [], ); + offset_area.x += start_vis_offset as u16; + } - // draw the "..." with the keyword.operator style - let new_x_location = - (already_written + line_context_area.x).saturating_sub(match doc.line_ending { - helix_core::LineEnding::Crlf => 2, - helix_core::LineEnding::LF => 1, - }); + if node.has_context_end { + let node_end = text.byte_to_char(node.byte_range.end); + let end_node_line = text.line(text.char_to_line(node_end)); + let whitespace_offset = end_node_line + .chars() + .position(|c| !c.is_whitespace()) + .unwrap_or(0); + + #[allow(deprecated)] + let Position { + col: end_vis_offset, + row: _, + } = visual_coords_at_pos(end_node_line, whitespace_offset, doc.tab_width()); surface.set_stringn( - new_x_location, - additional_area.y, - dots, - dots.len(), + offset_area.x, + offset_area.y, + DOTS, + DOTS.len(), theme.get("keyword.operator"), ); - } - - new_offset.anchor = text.byte_to_char(node.byte_range.start); + offset_area.x += DOTS.len() as u16; - // get all highlights from the latest point - let highlights = EditorView::doc_syntax_highlights(doc, new_offset.anchor, 1, theme); + let mut renderer = TextRenderer::new(surface, doc, theme, end_vis_offset, offset_area); - let mut renderer = TextRenderer::new( - surface, - doc, - theme, - view.offset.horizontal_offset, - line_context_area, - ); + let highlights = EditorView::doc_syntax_highlights(doc, node_end, 1, theme); + let mut formatting = doc.text_format(offset_area.width, Some(theme)); + formatting.soft_wrap = false; - // limit the width to its size - 1, so that it won't draw trailing whitespace characters - line_context_area.width = already_written - 1; - - let mut text_format = doc.text_format(line_context_area.width, Some(theme)); - text_format.soft_wrap = false; - - render_text( - &mut renderer, - text, - new_offset, - &text_format, - &virtual_text_annotations, - highlights, - theme, - line_decoration, - translated_positions, - ); + render_text( + &mut renderer, + text, + ViewPosition { + anchor: node_end, + ..ViewPosition::default() + }, + &formatting, + &TextAnnotations::default(), + highlights, + theme, + &mut [], + &mut [], + ); + } // next node context_area.y += 1; diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 650028a00..7cdc1335b 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -35,7 +35,7 @@ use tui::{buffer::Buffer as Surface, text::Span}; use super::{ completion::CompletionItem, - context::{calculate_sticky_nodes, render_sticky_context, StickyNode}, + context::{self, StickyNode}, statusline, }; use super::{document::LineDecoration, lsp::SignatureHelp}; @@ -204,7 +204,7 @@ impl EditorView { ); if config.sticky_context.enable { - self.sticky_nodes = calculate_sticky_nodes( + self.sticky_nodes = context::calculate_sticky_nodes( &self.sticky_nodes, doc, view, @@ -212,15 +212,7 @@ impl EditorView { &editor.cursor_cache.get(), ); - render_sticky_context( - doc, - view, - surface, - &self.sticky_nodes, - &mut line_decorations, - &mut translated_positions, - theme, - ); + context::render_sticky_context(doc, view, surface, &self.sticky_nodes, theme); } Self::render_rulers(editor, doc, view, inner, surface, theme);