diff --git a/Cargo.lock b/Cargo.lock index c5b54272b59c..7118ca4068ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,9 +31,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "2da1976d75adbe5fbc88130ecd119529cf1cc6a93ae1546d8696ee66f0d21af1" [[package]] name = "bstr" @@ -313,7 +313,6 @@ dependencies = [ "arc-swap", "etcetera", "helix-syntax", - "log", "once_cell", "quickcheck", "regex", diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 8c46eef900d6..5e1e8f5065a4 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -17,6 +17,7 @@ use helix_core::{ }; use helix_view::{ document::Mode, + editor::LineNumber, graphics::{CursorKind, Modifier, Rect, Style}, info::Info, input::KeyEvent, @@ -71,6 +72,7 @@ impl EditorView { theme: &Theme, is_focused: bool, loader: &syntax::Loader, + config: &helix_view::editor::Config, ) { let area = Rect::new( view.area.x + GUTTER_OFFSET, @@ -93,7 +95,7 @@ impl EditorView { }; Self::render_text_highlights(doc, offset, area, surface, theme, highlights); - Self::render_gutter(doc, view, area, surface, theme); + Self::render_gutter(doc, view, area, surface, theme, config); if is_focused { Self::render_focused_view_elements(view, doc, area, theme, surface); @@ -459,6 +461,7 @@ impl EditorView { viewport: Rect, surface: &mut Surface, theme: &Theme, + config: &helix_view::editor::Config, ) { let text = doc.text().slice(..); let last_line = view.last_line(doc); @@ -473,6 +476,9 @@ impl EditorView { // 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(); + let current_line = doc + .text() + .char_to_line(doc.selection(view.id).primary().anchor); for (i, line) in (view.first_line..(last_line + 1)).enumerate() { use helix_core::diagnostic::Severity; if let Some(diagnostic) = doc.diagnostics().iter().find(|d| d.line == line) { @@ -495,7 +501,13 @@ impl EditorView { let line_number_text = if line == last_line && !draw_last { " ~".into() } else { - format!("{:>5}", line + 1) + match config.line_number { + LineNumber::Absolute => format!("{:>5}", line + 1), + LineNumber::Relative => { + let relative_line = abs_diff(current_line, line); + format!("{:>5}", relative_line) + } + } }; surface.set_stringn( viewport.x + 1 - GUTTER_OFFSET, @@ -1042,6 +1054,7 @@ impl Component for EditorView { &cx.editor.theme, is_focused, loader, + &cx.editor.config, ); } @@ -1115,3 +1128,12 @@ fn canonicalize_key(key: &mut KeyEvent) { key.modifiers.remove(KeyModifiers::SHIFT) } } + +#[inline] +fn abs_diff(a: usize, b: usize) -> usize { + if a > b { + a - b + } else { + b - a + } +} diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 413b7913fe7c..32f5fe866c0d 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -33,16 +33,29 @@ pub struct Config { pub scroll_lines: isize, /// Mouse support. Defaults to true. pub mouse: bool, + /// Line number mode. + pub line_number: LineNumber, /// Middle click paste support. Defaults to true pub middle_click_paste: bool, } +#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum LineNumber { + /// Show absolute line number + Absolute, + + /// Show relative line number to the primary cursor + Relative, +} + impl Default for Config { fn default() -> Self { Self { scrolloff: 5, scroll_lines: 3, mouse: true, + line_number: LineNumber::Absolute, middle_click_paste: true, } }