From 56c857f4b797292b7f2d825596e7119575af1aeb Mon Sep 17 00:00:00 2001 From: SoraTenshi Date: Thu, 2 Mar 2023 17:52:44 +0100 Subject: [PATCH] Redo sticky note configuration, improve the caching --- helix-term/src/ui/editor.rs | 43 ++++++++++++++++++++++--------------- helix-view/src/editor.rs | 33 +++++++++++++++++++++++----- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 1500c67a75cfd..6ce1d6c73b23c 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -185,7 +185,10 @@ impl EditorView { Box::new(highlights) }; - self.sticky_nodes = Self::calculate_sticky_nodes(&self.sticky_nodes, doc, view, &config); + if config.sticky_context.enable { + self.sticky_nodes = + Self::calculate_sticky_nodes(&self.sticky_nodes, doc, view, &config); + } if is_focused { let cursor = doc @@ -221,7 +224,7 @@ impl EditorView { &mut translated_positions, ); - if config.sticky_context { + if config.sticky_context.enable { Self::render_sticky_context( doc, view, @@ -735,6 +738,7 @@ impl EditorView { } /// Render the sticky context + #[allow(clippy::too_many_arguments)] pub fn render_sticky_context( doc: &Document, view: &View, @@ -765,13 +769,14 @@ impl EditorView { surface.clear_with(context_area, context_style); if let Some(indicator) = node.indicator.as_deref() { + // set the indicator surface.set_string(context_area.x, context_area.y, indicator, indicator_style); continue; } let line_num_anchor = text.line_to_char(node.line_nr); - // get all highlights from the latest points + // get all highlights from the latest point let highlights = Self::doc_syntax_highlights(doc, line_num_anchor, 1, theme); let mut renderer = TextRenderer::new( @@ -807,9 +812,6 @@ impl EditorView { view: &View, config: &helix_view::editor::Config, ) -> Option> { - if !config.sticky_context { - return None; - } let syntax = doc.syntax()?; let tree = syntax.tree(); let text = doc.text().slice(..); @@ -821,15 +823,6 @@ impl EditorView { let top_first_byte = text.line_to_byte(anchor_line + nodes.as_deref().map_or(0, |v| v.len())); - if let Some(nodes) = nodes { - if nodes - .iter() - .any(|node| node.top_first_byte == top_first_byte) - { - return Some(nodes.to_vec()); - } - } - let visual_cursor_pos = view .screen_coords_at_pos(doc, text, cursor_line) .unwrap_or_default() @@ -839,6 +832,14 @@ impl EditorView { return None; } + if let Some(nodes) = nodes { + if nodes.iter().any(|node| { + node.top_first_byte == top_first_byte && (visual_cursor_pos as usize) >= nodes.len() + }) { + return Some(nodes.to_vec()); + } + } + let context_nodes = doc .language_config() .and_then(|lc| lc.sticky_context_nodes.as_ref()); @@ -885,11 +886,19 @@ impl EditorView { return None; } + let max_lines = config.sticky_context.max_lines; + let max_nodes_amount = if max_lines == 0 { + viewport.height as usize / 3 + } else { + max_lines.min(viewport.height) as usize + }; + // we render from top most (last in the list) context = context .into_iter() .rev() - .take(viewport.height as usize / 3) // only take the nodes until 1 / 3 of the viewport is reached + // only take the nodes until 1 / 3 of the viewport is reached or the maximum amount of sticky nodes .take(viewport.height as usize / 3) + .take(max_nodes_amount) .enumerate() .take_while(|(i, _)| *i + 1 != visual_cursor_pos as usize) // also only nodes that don't overlap with the visual cursor position .map(|(i, node)| { @@ -899,7 +908,7 @@ impl EditorView { }) .collect(); - if config.sticky_context_indicator { + if config.sticky_context.indicator { let mut str = String::new(); let message = "┤Sticky Context├"; let side_placeholder = (viewport.width as usize) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 28e057ed3ea38..7ae861eb53370 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -274,12 +274,36 @@ pub struct Config { /// Whether to color modes with different colors. Defaults to `false`. pub color_modes: bool, pub soft_wrap: SoftWrap, + /// Contextual information on top of the viewport + pub sticky_context: StickyContextConfig, +} - /// Display context of current top view if it is outside the view. - pub sticky_context: bool, +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(default, rename_all = "kebab-case", deny_unknown_fields)] +pub struct StickyContextConfig { + /// Display context of current top view if it is outside the view. Default to off + pub enable: bool, /// Display an indicator whether to indicate if the sticky context is active - pub sticky_context_indicator: bool, + /// Eventually making this a string so that it is configurable. + pub indicator: bool, + + /// The max amount of lines to be displayed. (including indicator!) + /// The viewport is taken into account when changing this value. + /// So if the configured amount is more than the viewport height. + /// + /// Default: 0, which means that it is a fixed size based on the viewport + pub max_lines: u16, +} + +impl Default for StickyContextConfig { + fn default() -> Self { + Self { + enable: false, + indicator: false, + max_lines: 0, + } + } } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -778,8 +802,7 @@ impl Default for Config { indent_guides: IndentGuidesConfig::default(), color_modes: false, soft_wrap: SoftWrap::default(), - sticky_context: false, - sticky_context_indicator: false, + sticky_context: StickyContextConfig::default(), } } }