Line numbers are now displayed in left-hand gutter.
This commit is contained in:
parent
9b24b2b4f2
commit
902d93e957
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
34
src/utils.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
1
todo.md
1
todo.md
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user