Skip to content

Added switchable relative line numbers #432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/bin/edit/documents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ impl DocumentManager {
{
let mut tb = buffer.borrow_mut();
tb.set_insert_final_newline(!cfg!(windows)); // As mandated by POSIX.
tb.set_margin_enabled(true);
tb.set_line_numbers(true);
tb.set_line_highlight_enabled(true);
}
Ok(buffer)
Expand Down
10 changes: 10 additions & 0 deletions src/bin/edit/draw_menubar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ fn draw_menu_view(ctx: &mut Context, state: &mut State) {

if let Some(doc) = state.documents.active() {
let mut tb = doc.buffer.borrow_mut();
let relative_numbers = tb.is_relative_line_numbers();
let line_number = tb.is_line_numbers_enabled();
let word_wrap = tb.is_word_wrap_enabled();

if ctx.menubar_menu_button(loc(LocId::ViewDocumentPicker), 'P', kbmod::CTRL | vk::P) {
Expand All @@ -113,6 +115,14 @@ fn draw_menu_view(ctx: &mut Context, state: &mut State) {
if ctx.menubar_menu_button(loc(LocId::FileGoto), 'G', kbmod::CTRL | vk::G) {
state.wants_goto = true;
}
if ctx.menubar_menu_checkbox(loc(LocId::ViewLineNumbers), 'N', kbmod::ALT | vk::L, line_number) {
tb.set_line_numbers(!line_number);
ctx.needs_rerender();
}
if line_number && ctx.menubar_menu_checkbox(loc(LocId::ViewRelativeLineNumbers), 'R', kbmod::ALT | vk::R, relative_numbers) {
tb.set_relative_line_numbers(!relative_numbers);
ctx.needs_rerender();
}
if ctx.menubar_menu_checkbox(loc(LocId::ViewWordWrap), 'W', kbmod::ALT | vk::Z, word_wrap) {
tb.set_word_wrap(!word_wrap);
ctx.needs_rerender();
Expand Down
30 changes: 30 additions & 0 deletions src/bin/edit/localization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub enum LocId {
ViewFocusStatusbar,
ViewWordWrap,
ViewDocumentPicker,
ViewLineNumbers,
ViewRelativeLineNumbers,

// Help menu
Help,
Expand Down Expand Up @@ -527,6 +529,34 @@ const S_LANG_LUT: [[&str; LangId::Count as usize]; LocId::Count as usize] = [
/* zh_hans */ "文档选择器…",
/* zh_hant */ "文件選擇器…",
],
// ViewLineNumbers
[
/* en */ "Show Line Numbers",
/* de */ "Zeilennummern anzeigen",
/* es */ "Mostrar números de línea",
/* fr */ "Afficher les numéros de ligne",
/* it */ "Mostra numeri di riga",
/* ja */ "行番号を表示する",
/* ko */ "줄 번호 표시",
/* pt_br */ "Mostrar números de linha",
/* ru */ "Показать номера строк",
/* zh_hans */ "显示行号",
/* zh_hant */ "顯示行號",
],
// ViewRelativeLineNumbers
[
/* en */ "Use Relative Line Numbers",
/* de */ "Verwende relative Zeilennummern",
/* es */ "Utiliza números de línea relativos",
/* fr */ "Utilisez des numéros de ligne relatifs",
/* it */ "Utilizza numeri di riga relativi",
/* ja */ "相対行番号を使用してください",
/* ko */ "상대 행 번호를 사용하십시오.",
/* pt_br */ "Use números relativos de linhas",
/* ru */ "Используйте относительные номера строк",
/* zh_hans */ "使用相对行号",
/* zh_hant */ "使用相对行号",
],

// Help (a menu bar item)
[
Expand Down
77 changes: 57 additions & 20 deletions src/buffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ enum HistoryType {
Delete,
}

/// The line number type controls how the line numbers are rendered.
#[derive(Default, Copy, Clone, Eq, PartialEq)]
enum LineNumber {
Absent,
#[default]
Present,
Relative,
}

/// An undo/redo entry.
struct HistoryEntry {
/// [`TextBuffer::cursor`] position before the change was made.
Expand Down Expand Up @@ -195,12 +204,12 @@ pub struct TextBuffer {

width: CoordType,
margin_width: CoordType,
margin_enabled: bool,
word_wrap_column: CoordType,
word_wrap_enabled: bool,
tab_size: CoordType,
indent_with_tabs: bool,
line_highlight_enabled: bool,
line_numbers: LineNumber,
ruler: CoordType,
encoding: &'static str,
newlines_are_crlf: bool,
Expand Down Expand Up @@ -242,12 +251,12 @@ impl TextBuffer {

width: 0,
margin_width: 0,
margin_enabled: false,
word_wrap_column: 0,
word_wrap_enabled: false,
tab_size: 4,
indent_with_tabs: false,
line_highlight_enabled: false,
line_numbers: LineNumber::Relative,
ruler: 0,
encoding: "UTF-8",
newlines_are_crlf: cfg!(windows), // Windows users want CRLF
Expand Down Expand Up @@ -421,17 +430,6 @@ impl TextBuffer {
self.margin_width
}

/// Is the left margin enabled?
pub fn set_margin_enabled(&mut self, enabled: bool) -> bool {
if self.margin_enabled == enabled {
false
} else {
self.margin_enabled = enabled;
self.reflow();
true
}
}

/// Gets the width of the text contents for layout.
pub fn text_width(&self) -> CoordType {
self.width - self.margin_width
Expand Down Expand Up @@ -504,6 +502,11 @@ impl TextBuffer {
}
}

/// Sets a ruler column, e.g. 80.
pub fn set_ruler(&mut self, column: CoordType) {
self.ruler = column;
}

/// Returns whether tabs are used for indentation.
pub fn indent_with_tabs(&self) -> bool {
self.indent_with_tabs
Expand All @@ -519,16 +522,37 @@ impl TextBuffer {
self.line_highlight_enabled = enabled;
}

/// Sets a ruler column, e.g. 80.
pub fn set_ruler(&mut self, column: CoordType) {
self.ruler = column;
/// Returns whether line numbers are visible.
pub fn is_line_numbers_enabled(&self) -> bool {
self.line_numbers != LineNumber::Absent
}

/// Returns whether line numbers are visible and relative.
pub fn is_relative_line_numbers(&self) -> bool {
self.line_numbers == LineNumber::Relative
}

/// Sets the visibility of row numbers.
pub fn set_line_numbers(&mut self, enabled: bool) {
self.line_numbers = if enabled { LineNumber::Present } else { LineNumber::Absent };
self.reflow();
}

/// Sets the visibility of relative row numbers.
pub fn set_relative_line_numbers(&mut self, enabled: bool) {
self.line_numbers = if enabled {
LineNumber::Relative
} else {
LineNumber::Present
};
self.reflow();
}

pub fn reflow(&mut self) {
// +1 onto logical_lines, because line numbers are 1-based.
// +1 onto log10, because we want the digit width and not the actual log10.
// +3 onto log10, because we append " | " to the line numbers to form the margin.
self.margin_width = if self.margin_enabled {
self.margin_width = if self.line_numbers != LineNumber::Absent {
self.stats.logical_lines.ilog10() as CoordType + 4
} else {
0
Expand Down Expand Up @@ -1513,12 +1537,17 @@ impl TextBuffer {
let scratch = scratch_arena(None);
let width = destination.width();
let height = destination.height();
let line_number_width = self.margin_width.max(3) as usize - 3;
let text_width = width - self.margin_width;
let mut visualizer_buf = [0xE2, 0x90, 0x80]; // U+2400 in UTF8
let mut line = ArenaString::new_in(&scratch);
let mut visual_pos_x_max = 0;

let line_number_width = if self.line_numbers != LineNumber::Absent {
self.margin_width.max(3) as usize - 3
} else {
0
};

// Pick the cursor closer to the `origin.y`.
let mut cursor = {
let a = self.cursor;
Expand Down Expand Up @@ -1552,6 +1581,14 @@ impl TextBuffer {
}

if line_number_width != 0 {
let line_number = cursor_beg.logical_pos.y + 1;
let mut print_number = line_number;
if self.line_numbers == LineNumber::Relative {
let cursor_position = self.cursor.logical_pos.y + 1;
let relative_postion = (line_number - cursor_position).abs();
print_number = if relative_postion == 0 { line_number } else { relative_postion };
};

if visual_line >= self.stats.visual_lines {
// Past the end of the buffer? Place " | " in the margin.
// Since we know that we won't see line numbers greater than i64::MAX (9223372036854775807)
Expand All @@ -1562,10 +1599,10 @@ impl TextBuffer {
line.push_str(&MARGIN_TEMPLATE[off..]);
} else if self.word_wrap_column <= 0 || cursor_beg.logical_pos.x == 0 {
// Regular line? Place "123 | " in the margin.
_ = write!(line, "{:1$} │ ", cursor_beg.logical_pos.y + 1, line_number_width);
_ = write!(line, "{:1$} │ ", print_number, line_number_width);
} else {
// Wrapped line? Place " ... | " in the margin.
let number_width = (cursor_beg.logical_pos.y + 1).ilog10() as usize + 1;
let number_width = print_number.ilog10() as usize + 1;
_ = write!(
line,
"{0:1$}{0:∙<2$} │ ",
Expand Down