diff options
Diffstat (limited to 'helix-term/src/ui')
-rw-r--r-- | helix-term/src/ui/completion.rs | 2 | ||||
-rw-r--r-- | helix-term/src/ui/editor.rs | 160 |
2 files changed, 61 insertions, 101 deletions
diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index 985d4e48..90657764 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -314,7 +314,7 @@ impl Component for Completion { let half = area.height / 2; let height = 15.min(half); // we want to make sure the cursor is visible (not hidden behind the documentation) - let y = if cursor_pos + view.area.y + let y = if cursor_pos + area.y >= (cx.editor.tree.area().height - height - 2/* statusline + commandline */) { 0 diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 98462e26..21e6cd9b 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -38,8 +38,6 @@ pub struct EditorView { autoinfo: Option<Info>, } -pub const GUTTER_OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter - impl Default for EditorView { fn default() -> Self { Self::new(Keymaps::default()) @@ -74,15 +72,10 @@ impl EditorView { loader: &syntax::Loader, config: &helix_view::editor::Config, ) { - let area = Rect::new( - view.area.x + GUTTER_OFFSET, - view.area.y, - view.area.width - GUTTER_OFFSET, - view.area.height.saturating_sub(1), - ); // - 1 for statusline - let height = view.area.height.saturating_sub(1); // - 1 for statusline - - let highlights = Self::doc_syntax_highlights(doc, view.offset, height, theme, loader); + let inner = view.inner_area(); + let area = view.area; + + let highlights = Self::doc_syntax_highlights(doc, view.offset, inner.height, theme, loader); let highlights = syntax::merge(highlights, Self::doc_diagnostics_highlights(doc, theme)); let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused { Box::new(syntax::merge( @@ -93,11 +86,11 @@ impl EditorView { Box::new(highlights) }; - Self::render_text_highlights(doc, view.offset, area, surface, theme, highlights); - Self::render_gutter(doc, view, area, surface, theme, config); + Self::render_text_highlights(doc, view.offset, inner, surface, theme, highlights); + Self::render_gutter(doc, view, view.area, surface, theme, is_focused, config); if is_focused { - Self::render_focused_view_elements(view, doc, area, theme, surface); + Self::render_focused_view_elements(view, doc, inner, theme, surface); } // if we're not at the edge of the screen, draw a right border @@ -113,7 +106,7 @@ impl EditorView { } } - self.render_diagnostics(doc, view, area, surface, theme); + self.render_diagnostics(doc, view, inner, surface, theme); let area = Rect::new( view.area.x, @@ -369,7 +362,7 @@ impl EditorView { } } - /// Render brace match, selected line numbers, etc (meant for the focused view only) + /// Render brace match, etc (meant for the focused view only) pub fn render_focused_view_elements( view: &View, doc: &Document, @@ -377,77 +370,29 @@ impl EditorView { theme: &Theme, surface: &mut Surface, ) { - let text = doc.text().slice(..); - let selection = doc.selection(view.id); - let last_line = view.last_line(doc); - let screen = { - let start = text.line_to_char(view.offset.row); - let end = text.line_to_char(last_line + 1) + 1; // +1 for cursor at end of text. - Range::new(start, end) - }; - - // render selected linenr(s) - let linenr_select: Style = theme - .try_get("ui.linenr.selected") - .unwrap_or_else(|| theme.get("ui.linenr")); - - // Whether to draw the line number for the last line of the - // document or not. We only draw it if it's not an empty line. - let draw_last = text.line_to_byte(last_line) < text.len_bytes(); - - for selection in selection.iter().filter(|range| range.overlaps(&screen)) { - let head = view.screen_coords_at_pos( - doc, - text, - if selection.head > selection.anchor { - selection.head - 1 - } else { - selection.head - }, - ); - if let Some(head) = head { - // Highlight line number for selected lines. - let line_number = view.offset.row + head.row; - let line_number_text = if line_number == last_line && !draw_last { - " ~".into() - } else { - format!("{:>5}", line_number + 1) - }; - surface.set_stringn( - viewport.x - GUTTER_OFFSET + 1, - viewport.y + head.row as u16, - line_number_text, - 5, - linenr_select, - ); + // Highlight matching braces + if let Some(syntax) = doc.syntax() { + let text = doc.text().slice(..); + use helix_core::match_brackets; + let pos = doc.selection(view.id).primary().cursor(text); + + let pos = match_brackets::find(syntax, doc.text(), pos) + .and_then(|pos| view.screen_coords_at_pos(doc, text, pos)); + + if let Some(pos) = pos { + // ensure col is on screen + if (pos.col as u16) < viewport.width + view.offset.col as u16 + && pos.col >= view.offset.col + { + let style = theme.try_get("ui.cursor.match").unwrap_or_else(|| { + Style::default() + .add_modifier(Modifier::REVERSED) + .add_modifier(Modifier::DIM) + }); - // Highlight matching braces - // TODO: set cursor position for IME - if let Some(syntax) = doc.syntax() { - use helix_core::match_brackets; - let pos = doc - .selection(view.id) - .primary() - .cursor(doc.text().slice(..)); - let pos = match_brackets::find(syntax, doc.text(), pos) - .and_then(|pos| view.screen_coords_at_pos(doc, text, pos)); - - if let Some(pos) = pos { - // ensure col is on screen - if (pos.col as u16) < viewport.width + view.offset.col as u16 - && pos.col >= view.offset.col - { - let style = theme.try_get("ui.cursor.match").unwrap_or_else(|| { - Style::default() - .add_modifier(Modifier::REVERSED) - .add_modifier(Modifier::DIM) - }); - - surface - .get_mut(viewport.x + pos.col as u16, viewport.y + pos.row as u16) - .set_style(style); - } - } + surface + .get_mut(viewport.x + pos.col as u16, viewport.y + pos.row as u16) + .set_style(style); } } } @@ -460,12 +405,15 @@ impl EditorView { viewport: Rect, surface: &mut Surface, theme: &Theme, + is_focused: bool, config: &helix_view::editor::Config, ) { let text = doc.text().slice(..); let last_line = view.last_line(doc); let linenr = theme.get("ui.linenr"); + let linenr_select: Style = theme.try_get("ui.linenr.selected").unwrap_or(linenr); + let warning = theme.get("warning"); let error = theme.get("error"); let info = theme.get("info"); @@ -478,11 +426,21 @@ impl EditorView { let current_line = doc .text() .char_to_line(doc.selection(view.id).primary().anchor); + + // it's used inside an iterator so the collect isn't needless: + // https://github.com/rust-lang/rust-clippy/issues/6164 + #[allow(clippy::clippy::needless_collect)] + let cursors: Vec<_> = doc + .selection(view.id) + .iter() + .map(|range| range.cursor_line(text)) + .collect(); + for (i, line) in (view.offset.row..(last_line + 1)).enumerate() { use helix_core::diagnostic::Severity; if let Some(diagnostic) = doc.diagnostics().iter().find(|d| d.line == line) { surface.set_stringn( - viewport.x - GUTTER_OFFSET, + viewport.x, viewport.y + i as u16, "●", 1, @@ -495,25 +453,27 @@ impl EditorView { ); } - // Line numbers having selections are rendered - // differently, further below. - let line_number_text = if line == last_line && !draw_last { + let selected = cursors.contains(&line); + + let text = if line == last_line && !draw_last { " ~".into() } else { - match config.line_number { - LineNumber::Absolute => format!("{:>5}", line + 1), - LineNumber::Relative => { - let relative_line = abs_diff(current_line, line); - format!("{:>5}", relative_line) - } - } + let line = match config.line_number { + LineNumber::Absolute => line + 1, + LineNumber::Relative => abs_diff(current_line, line), + }; + format!("{:>5}", line) }; surface.set_stringn( - viewport.x + 1 - GUTTER_OFFSET, + viewport.x + 1, viewport.y + i as u16, - line_number_text, + text, 5, - linenr, + if selected && is_focused { + linenr_select + } else { + linenr + }, ); } } |