Line numbers are now displayed in left-hand gutter.

This commit is contained in:
Nathan Vegdahl 2015-02-08 19:17:48 -08:00
parent 9b24b2b4f2
commit 902d93e957
5 changed files with 79 additions and 7 deletions

View File

@ -7,6 +7,7 @@ use formatter::RoundingBehavior::*;
use std::old_path::Path; use std::old_path::Path;
use std::cmp::{min, max}; use std::cmp::{min, max};
use string_utils::grapheme_count; use string_utils::grapheme_count;
use utils::digit_count;
use self::cursor::CursorSet; use self::cursor::CursorSet;
mod cursor; mod cursor;
@ -21,7 +22,11 @@ pub struct Editor<T: LineFormatter> {
pub soft_tab_width: u8, pub soft_tab_width: u8,
pub dirty: bool, pub dirty: bool,
// The dimensions and position of the editor's view within the buffer // The dimensions of the total editor in screen space, including the
// header, gutter, etc.
pub editor_dim: (usize, usize),
// The dimensions and position of just the text view portion of the editor
pub view_dim: (usize, usize), // (height, width) pub view_dim: (usize, usize), // (height, width)
pub view_pos: (usize, usize), // (grapheme index, visual horizontal offset) pub view_pos: (usize, usize), // (grapheme index, visual horizontal offset)
@ -41,6 +46,7 @@ impl<T: LineFormatter> Editor<T> {
soft_tabs: false, soft_tabs: false,
soft_tab_width: 4, soft_tab_width: 4,
dirty: false, dirty: false,
editor_dim: (0, 0),
view_dim: (0, 0), view_dim: (0, 0),
view_pos: (0, 0), view_pos: (0, 0),
cursors: CursorSet::new(), cursors: CursorSet::new(),
@ -63,6 +69,7 @@ impl<T: LineFormatter> Editor<T> {
soft_tabs: false, soft_tabs: false,
soft_tab_width: 4, soft_tab_width: 4,
dirty: false, dirty: false,
editor_dim: (0, 0),
view_dim: (0, 0), view_dim: (0, 0),
view_pos: (0, 0), view_pos: (0, 0),
cursors: CursorSet::new(), cursors: CursorSet::new(),
@ -255,7 +262,19 @@ impl<T: LineFormatter> Editor<T> {
pub fn update_dim(&mut self, h: usize, w: usize) { pub fn update_dim(&mut self, h: usize, w: usize) {
self.view_dim = (h, w); self.editor_dim = (h, w);
self.update_view_dim();
}
pub fn update_view_dim(&mut self) {
// TODO: generalize for non-terminal UI. Maybe this isn't where it
// belongs, in fact. But for now, this is the easiest place to put
// it.
let line_count_digits = digit_count(self.buffer.line_count() as u32, 10) as usize;
// Minus 1 vertically for the header, minus one more than the digits in
// the line count for the gutter.
self.view_dim = (self.editor_dim.0 - 1, self.editor_dim.1 - line_count_digits - 1);
} }

View File

@ -20,6 +20,7 @@ use term_ui::formatter::ConsoleLineFormatter;
//use gui::formatter::GUILineFormatter; //use gui::formatter::GUILineFormatter;
mod string_utils; mod string_utils;
mod utils;
mod buffer; mod buffer;
mod formatter; mod formatter;
mod editor; mod editor;

View File

@ -7,6 +7,7 @@ use formatter::LineFormatter;
use std::char; use std::char;
use std::time::duration::Duration; use std::time::duration::Duration;
use string_utils::{is_line_ending}; use string_utils::{is_line_ending};
use utils::digit_count;
use buffer::line::{line_ending_to_str, LineEnding}; use buffer::line::{line_ending_to_str, LineEnding};
use self::formatter::ConsoleLineFormatter; use self::formatter::ConsoleLineFormatter;
@ -88,6 +89,8 @@ impl TermUI {
loop { loop {
// Draw the editor to screen // Draw the editor to screen
self.editor.update_view_dim();
self.editor.formatter.wrap_width = self.editor.view_dim.1;
self.rb.clear(); self.rb.clear();
self.draw_editor(&self.editor, (0, 0), (self.height-1, self.width-1)); self.draw_editor(&self.editor, (0, 0), (self.height-1, self.width-1));
self.rb.present(); self.rb.present();
@ -195,9 +198,7 @@ impl TermUI {
if let Some((h, w)) = resize { if let Some((h, w)) = resize {
self.width = w as usize; self.width = w as usize;
self.height = h as usize; self.height = h as usize;
self.editor.update_dim(self.height-1, self.width); self.editor.update_dim(self.height, self.width);
self.editor.formatter.wrap_width = self.width;
println!("Resized window!");
} }
resize = None; resize = None;
@ -220,6 +221,8 @@ impl TermUI {
loop { loop {
// Draw the editor to screen // Draw the editor to screen
self.editor.update_view_dim();
self.editor.formatter.wrap_width = self.editor.view_dim.1;
self.rb.clear(); self.rb.clear();
self.draw_editor(&self.editor, (0, 0), (self.height-1, self.width-1)); self.draw_editor(&self.editor, (0, 0), (self.height-1, self.width-1));
for i in 0..self.width { for i in 0..self.width {
@ -353,14 +356,29 @@ impl TermUI {
fn draw_editor_text(&self, editor: &Editor<ConsoleLineFormatter>, c1: (usize, usize), c2: (usize, usize)) { fn draw_editor_text(&self, editor: &Editor<ConsoleLineFormatter>, c1: (usize, usize), c2: (usize, usize)) {
// Calculate all the starting info // Calculate all the starting info
let gutter_width = editor.editor_dim.1 - editor.view_dim.1;
let (starting_line, _) = editor.buffer.index_to_line_col(editor.view_pos.0); let (starting_line, _) = editor.buffer.index_to_line_col(editor.view_pos.0);
let mut grapheme_index = editor.buffer.line_col_to_index((starting_line, 0)); let mut grapheme_index = editor.buffer.line_col_to_index((starting_line, 0));
let (vis_line_offset, _) = editor.formatter.index_to_v2d(editor.buffer.get_line(starting_line), editor.view_pos.0 - grapheme_index); let (vis_line_offset, _) = editor.formatter.index_to_v2d(editor.buffer.get_line(starting_line), editor.view_pos.0 - grapheme_index);
let mut screen_line = c1.0 as isize - vis_line_offset as isize; let mut screen_line = c1.0 as isize - vis_line_offset as isize;
let screen_col = c1.1 as isize; let screen_col = c1.1 as isize + gutter_width as isize;
// Fill in the gutter with the appropriate background
for y in c1.0..(c2.0+1) {
for x in c1.1..(c1.1+gutter_width-1) {
self.rb.print(x, y, rustbox::RB_NORMAL, Color::White, Color::Blue, " ");
}
}
let mut line_num = starting_line + 1;
for line in editor.buffer.line_iter_at_index(starting_line) { for line in editor.buffer.line_iter_at_index(starting_line) {
// Print line number
let lnx = c1.1 + (gutter_width - 1 - digit_count(line_num as u32, 10) as usize);
let lny = screen_line as usize;
if lny >= c1.0 && lny <= c2.0 {
self.rb.print(lnx, lny, rustbox::RB_NORMAL, Color::White, Color::Blue, format!("{}", line_num).as_slice());
}
// Loop through the graphemes of the line and print them to // Loop through the graphemes of the line and print them to
// the screen. // the screen.
@ -417,6 +435,7 @@ impl TermUI {
let (dim_y, _) = editor.formatter.dimensions(line); let (dim_y, _) = editor.formatter.dimensions(line);
screen_line += dim_y as isize; screen_line += dim_y as isize;
line_num += 1;
} }

34
src/utils.rs Normal file
View File

@ -0,0 +1,34 @@
pub fn digit_count(mut n: u32, b: u32) -> u32 {
let mut d = 0;
loop {
n /= b;
d += 1;
if n == 0 {
return d;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn digit_count_base_10() {
assert_eq!(digit_count(0, 10), 1);
assert_eq!(digit_count(9, 10), 1);
assert_eq!(digit_count(10, 10), 2);
assert_eq!(digit_count(99, 10), 2);
assert_eq!(digit_count(100, 10), 3);
assert_eq!(digit_count(999, 10), 3);
assert_eq!(digit_count(1000, 10), 4);
assert_eq!(digit_count(9999, 10), 4);
assert_eq!(digit_count(10000, 10), 5);
assert_eq!(digit_count(99999, 10), 5);
assert_eq!(digit_count(100000, 10), 6);
assert_eq!(digit_count(999999, 10), 6);
assert_eq!(digit_count(1000000, 10), 7);
assert_eq!(digit_count(9999999, 10), 7);
}
}

View File

@ -17,7 +17,6 @@
- Word wrap. - Word wrap.
- Get non-wrapping text working again. - Get non-wrapping text working again.
- Line number display
- File opening by entering path - File opening by entering path
- UI that wraps editors, for split view. - UI that wraps editors, for split view.
- Persistent infinite undo - Persistent infinite undo