diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 0605e2c7c263..1b504f845f64 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -411,6 +411,12 @@ impl EditorView { ) { let text = doc.text().slice(..); let last_line = view.last_line(doc); + let last_line_width = match config.line_number { + LineNumber::Absolute | LineNumber::Relative => { + (last_line + 1).to_string().chars().count() + } + LineNumber::None => 0, + }; let linenr = theme.get("ui.linenr"); let linenr_select: Style = theme.try_get("ui.linenr.selected").unwrap_or(linenr); @@ -457,25 +463,26 @@ impl EditorView { let selected = cursors.contains(&line); let text = if line == last_line && !draw_last { - " ~".into() + format!("{:>1$}", "~", last_line_width) } else { - let line = match config.line_number { - LineNumber::Absolute => line + 1, + match config.line_number { + LineNumber::Absolute => format!("{:>1$}", line + 1, last_line_width), LineNumber::Relative => { if current_line == line { - line + 1 + format!("{:>1$}", line + 1, last_line_width) } else { - abs_diff(current_line, line) + format!("{:>1$}", abs_diff(current_line, line), last_line_width) } } - }; - format!("{:>5}", line) + // if the line numbers are disabled we can entirely ignore the line width and return nothing + LineNumber::None => String::new(), + } }; surface.set_stringn( viewport.x + 1, viewport.y + i as u16, text, - 5, + last_line_width, if selected && is_focused { linenr_select } else { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index b08a2df20fba..d04f99758e3f 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -53,6 +53,9 @@ pub enum LineNumber { /// Show relative line number to the primary cursor Relative, + + /// Do not show the line number + None, } impl Default for Config { @@ -215,14 +218,14 @@ impl Editor { return; } Action::HorizontalSplit => { - let view = View::new(id); + let view = View::new(id, self.config.clone()); let view_id = self.tree.split(view, Layout::Horizontal); // initialize selection for view let doc = &mut self.documents[id]; doc.selections.insert(view_id, Selection::point(0)); } Action::VerticalSplit => { - let view = View::new(id); + let view = View::new(id, self.config.clone()); let view_id = self.tree.split(view, Layout::Vertical); // initialize selection for view let doc = &mut self.documents[id]; diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 01f18c71951a..da0b13cc8eae 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use crate::{graphics::Rect, Document, DocumentId, ViewId}; +use crate::{editor::LineNumber, graphics::Rect, Document, DocumentId, ViewId}; use helix_core::{ coords_at_pos, graphemes::{grapheme_width, RopeGraphemes}, @@ -66,10 +66,11 @@ pub struct View { pub jumps: JumpList, /// the last accessed file before the current one pub last_accessed_doc: Option, + pub config: crate::editor::Config, } impl View { - pub fn new(doc: DocumentId) -> Self { + pub fn new(doc: DocumentId, config: crate::editor::Config) -> Self { Self { id: ViewId::default(), doc, @@ -77,13 +78,20 @@ impl View { area: Rect::default(), // will get calculated upon inserting into tree jumps: JumpList::new((doc, Selection::point(0))), // TODO: use actual sel last_accessed_doc: None, + config, } } pub fn inner_area(&self) -> Rect { - // TODO: not ideal - const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter - self.area.clip_left(OFFSET).clip_bottom(1) // -1 for statusline + const OFFSET: usize = 1 + 1; // 1 diagnostic + 1 gutter + let last_line = self.offset.row + self.area.height as usize - 1; // -1 for statusline + let offset = match self.config.line_number { + LineNumber::Absolute | LineNumber::Relative => { + last_line.to_string().chars().count() + OFFSET + } + LineNumber::None => OFFSET, + }; + self.area.clip_left(offset as u16).clip_bottom(1) // -1 for statusline } pub fn ensure_cursor_in_view(&mut self, doc: &Document, scrolloff: usize) { @@ -242,13 +250,15 @@ impl View { #[cfg(test)] mod tests { + use crate::editor::Config; + use super::*; use helix_core::Rope; const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter #[test] fn test_text_pos_at_screen_coords() { - let mut view = View::new(DocumentId::default()); + let mut view = View::new(DocumentId::default(), Config::default()); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("abc\n\tdef"); let text = rope.slice(..); @@ -281,7 +291,7 @@ mod tests { assert_eq!( view.text_pos_at_screen_coords(&text, 41, 40 + OFFSET + 4, 4), - Some(5) + Some(8) ); assert_eq!( @@ -294,67 +304,67 @@ mod tests { #[test] fn test_text_pos_at_screen_coords_cjk() { - let mut view = View::new(DocumentId::default()); + let mut view = View::new(DocumentId::default(), Config::default()); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("Hi! こんにちは皆さん"); let text = rope.slice(..); assert_eq!( view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET + 0, 4), - Some(0) + Some(3) ); assert_eq!( view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET + 5, 4), - Some(5) + Some(6) ); assert_eq!( view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET + 6, 4), - Some(5) + Some(7) ); assert_eq!( view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET + 7, 4), - Some(6) + Some(7) ); assert_eq!( view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET + 8, 4), - Some(6) + Some(8) ); } #[test] fn test_text_pos_at_screen_coords_graphemes() { - let mut view = View::new(DocumentId::default()); + let mut view = View::new(DocumentId::default(), Config::default()); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("Hèl̀l̀ò world!"); let text = rope.slice(..); assert_eq!( view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET + 0, 4), - Some(0) + Some(5) ); assert_eq!( view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET + 1, 4), - Some(1) + Some(7) ); assert_eq!( view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET + 2, 4), - Some(3) + Some(9) ); assert_eq!( view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET + 3, 4), - Some(5) + Some(10) ); assert_eq!( view.text_pos_at_screen_coords(&text, 40, 40 + OFFSET + 4, 4), - Some(7) + Some(11) ); } }