From a9d342f8cd27094e8b94daf1670237c3f05d07a9 Mon Sep 17 00:00:00 2001 From: Filip Dutescu Date: Fri, 17 Feb 2023 23:52:13 +0200 Subject: [PATCH] chore(debug): refactor line highlight, keep working on cursor and sel Signed-off-by: Filip Dutescu --- helix-term/src/ui/editor.rs | 229 ++++++++++++------------------------ 1 file changed, 73 insertions(+), 156 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index a384606f45af8..f790422199469 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -99,6 +99,38 @@ impl EditorView { Self::highlight_cursorcolumn(doc, view, surface, theme, inner, &text_annotations); } + // DAP: Highlight current stack frame position + let dap_line = if let Some(frame) = editor.current_stack_frame() { + if doc.path().is_some() + && frame + .source + .as_ref() + .and_then(|source| source.path.as_ref()) + == doc.path() + { + let line = frame.line - 1; // convert to 0-indexing + let dap_current_style = theme.get("ui.debug.current"); + let line_decoration = move |renderer: &mut TextRenderer, pos: LinePos| { + if pos.doc_line != line { + return; + } + + renderer.surface.set_style( + Rect::new(inner.x, inner.y + pos.visual_line, inner.width, 1), + dap_current_style, + ); + }; + + // This adds the line background. + line_decorations.push(Box::new(line_decoration)); + Some(line) + } else { + None + } + } else { + None + }; + let mut highlights = Self::doc_syntax_highlights(doc, view.offset.anchor, inner.height, theme); let overlay_highlights = Self::overlay_syntax_highlights( @@ -121,6 +153,22 @@ impl EditorView { } let highlights: Box> = if is_focused { + // This ensures foreground, cursor and selections are highlighted properly for DAP. + let highlights = if let Some(dap_line) = dap_line { + let dap_current_index = theme.find_scope_index("ui.debug.current").expect( + "Could not find scope `ui.debug.current` or any suitable fallback in theme!", + ); + let text = doc.text(); + let dap_line_start = text.line_to_char(dap_line); + let dap_line_end = text.line_to_char(dap_line + 1); + let highlights = Box::new(syntax::merge( + highlights, + vec![(dap_current_index, dap_line_start..dap_line_end)], + )); + highlights + } else { + highlights + }; let highlights = syntax::merge( highlights, Self::doc_selection_highlights( @@ -153,7 +201,10 @@ impl EditorView { == doc.path() { let line = frame.line - 1; // convert to 0-indexing - let style = theme.get("ui.debug.current"); + let dap_current_index = theme.find_scope_index("ui.debug.current").expect( + "Could not find scope `ui.debug.current` or any suitable fallback in theme!", + ); + let dap_current_style = theme.get("ui.debug.current"); let line_decoration = move |renderer: &mut TextRenderer, pos: LinePos| { if pos.doc_line != line { return; @@ -161,44 +212,27 @@ impl EditorView { renderer.surface.set_style( Rect::new(inner.x, inner.y + pos.visual_line, inner.width, 1), - style, + dap_current_style, ); }; // This adds the line background. line_decorations.push(Box::new(line_decoration)); - // This ensures foreground, cursor and selections are highlighted properly. - - let mut dap_range = Range::new(0, 0); - for (i, l) in doc.text().lines().enumerate() { - if i == line { - dap_range.head += l.len_chars(); - break; - } - dap_range.anchor += l.len_chars(); - dap_range.head += l.len_chars(); - } - let current_scope = theme.find_scope_index("ui.debug.current").expect( - "No fallback defined for the `ui.debug.current` scope in the theme!", - ); - let highlights = Box::new(syntax::merge( - highlights, - vec![(current_scope, dap_range.anchor..dap_range.head)], - )); - let dap_highlights = Self::doc_dap_highlights( - editor.mode(), - doc, - view, - theme, - &config.cursor_shape, - dap_range, - ); - Box::new(syntax::merge(highlights, dap_highlights)) + // let dap_highlights = Self::doc_dap_highlights( + // editor.mode(), + // doc, + // view, + // theme, + // &config.cursor_shape, + // Range::new(dap_line_start, dap_line_end), + // ); + // Box::new(syntax::merge(highlights, dap_highlights)) + highlights } else { - Box::new(highlights) + highlights } } else { - Box::new(highlights) + highlights }; Self::render_gutter( @@ -452,101 +486,11 @@ impl EditorView { let base_primary_cursor_scope = theme .find_scope_index("ui.cursor.primary") .unwrap_or(base_cursor_scope); - - let cursor_scope = mode.cursor_scope(theme).unwrap_or(base_cursor_scope); - - let primary_cursor_scope = mode - .primary_cursor_scope(theme) - .unwrap_or(base_primary_cursor_scope); - - let mut spans: Vec<(usize, std::ops::Range)> = Vec::new(); - for (i, range) in selection.iter().enumerate() { - let selection_is_primary = i == primary_idx; - let (cursor_scope, selection_scope) = if selection_is_primary { - (primary_cursor_scope, primary_selection_scope) - } else { - (cursor_scope, selection_scope) - }; - - // Special-case: cursor at end of the rope. - if range.head == range.anchor && range.head == text.len_chars() { - if !selection_is_primary || cursor_is_block { - // Bar and underline cursors are drawn by the terminal - // BUG: If the editor area loses focus while having a bar or - // underline cursor (eg. when a regex prompt has focus) then - // the primary cursor will be invisible. This doesn't happen - // with block cursors since we manually draw *all* cursors. - spans.push((cursor_scope, range.head..range.head + 1)); - } - continue; - } - - let range = range.min_width_1(text); - if range.head > range.anchor { - // Standard case. - let cursor_start = prev_grapheme_boundary(text, range.head); - // non block cursors look like they exclude the cursor - let selection_end = - if selection_is_primary && !cursor_is_block && mode != Mode::Insert { - range.head - } else { - cursor_start - }; - spans.push((selection_scope, range.anchor..selection_end)); - if !selection_is_primary || cursor_is_block { - spans.push((cursor_scope, cursor_start..range.head)); - } - } else { - // Reverse case. - let cursor_end = next_grapheme_boundary(text, range.head); - if !selection_is_primary || cursor_is_block { - spans.push((cursor_scope, range.head..cursor_end)); - } - // non block cursors look like they exclude the cursor - let selection_start = if selection_is_primary - && !cursor_is_block - && !(mode == Mode::Insert && cursor_end == range.anchor) - { - range.head - } else { - cursor_end - }; - spans.push((selection_scope, selection_start..range.anchor)); - } - } - - spans - } - - /// Highlight current debug line text (concretely, override all other highlights), and selection and colour cursor if any. - pub fn doc_dap_highlights( - mode: Mode, - doc: &Document, - view: &View, - theme: &Theme, - cursor_shape_config: &CursorShapeConfig, - dap_current_range: Range, - ) -> Vec<(usize, std::ops::Range)> { - let mut spans: Vec<(usize, std::ops::Range)> = Vec::new(); - - let text = doc.text().slice(..); - let selection = doc.selection(view.id); - let primary_idx = selection.primary_index(); - - let cursorkind = cursor_shape_config.from_mode(mode); - let cursor_is_block = cursorkind == CursorKind::Block; - - let selection_scope = theme - .find_scope_index_exact("ui.selection") - .expect("could not find `ui.selection` scope in the theme!"); let dap_selection_scope = theme .find_scope_index_exact("ui.debug.selection") .unwrap_or(selection_scope); - let base_cursor_scope = theme - .find_scope_index_exact("ui.cursor") - .unwrap_or(selection_scope); - let base_primary_cursor_scope = theme - .find_scope_index("ui.cursor.primary") + let dap_cursor_scope = theme + .find_scope_index_exact("ui.debug.cursor") .unwrap_or(base_cursor_scope); let cursor_scope = mode.cursor_scope(theme).unwrap_or(base_cursor_scope); @@ -555,16 +499,13 @@ impl EditorView { .primary_cursor_scope(theme) .unwrap_or(base_primary_cursor_scope); + let mut spans: Vec<(usize, std::ops::Range)> = Vec::new(); for (i, range) in selection.iter().enumerate() { - if Self::is_selection_outside_dap_line(&dap_current_range, &range) { - continue; - } - let selection_is_primary = i == primary_idx; let (cursor_scope, selection_scope) = if selection_is_primary { - (primary_cursor_scope, dap_selection_scope) + (primary_cursor_scope, primary_selection_scope) } else { - (cursor_scope, dap_selection_scope) + (cursor_scope, selection_scope) }; // Special-case: cursor at end of the rope. @@ -583,18 +524,6 @@ impl EditorView { let range = range.min_width_1(text); if range.head > range.anchor { // Standard case. - let dap_anchor = if range.anchor < dap_current_range.anchor { - dap_current_range.anchor - } else { - range.anchor - }; - let dap_head = if range.head > dap_current_range.head { - dap_current_range.head - } else { - range.head - }; - let range = Range::new(dap_anchor, dap_head); - let cursor_start = prev_grapheme_boundary(text, range.head); // non block cursors look like they exclude the cursor let selection_end = @@ -609,18 +538,6 @@ impl EditorView { } } else { // Reverse case. - let dap_anchor = if range.anchor < dap_current_range.head { - dap_current_range.head - } else { - range.anchor - }; - let dap_head = if range.head > dap_current_range.anchor { - dap_current_range.anchor - } else { - range.head - }; - let range = Range::new(dap_anchor, dap_head); - let cursor_end = next_grapheme_boundary(text, range.head); if !selection_is_primary || cursor_is_block { spans.push((cursor_scope, range.head..cursor_end)); @@ -641,9 +558,9 @@ impl EditorView { spans } - pub fn is_selection_outside_dap_line(dap_range: &Range, selection_range: &Range) -> bool { - (selection_range.anchor < dap_range.anchor && selection_range.head < dap_range.anchor) - || (selection_range.anchor > dap_range.head && selection_range.head > dap_range.head) + pub fn is_range_outside_another(range1: &Range, range2: &Range) -> bool { + (range2.anchor < range1.anchor && range2.head < range1.anchor) + || (range2.anchor > range1.head && range2.head > range1.head) } /// Render brace match, etc (meant for the focused view only)