From 940068a4dd0d38fba295daa8086a24b8d4836b7e Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Fri, 2 Jan 2015 16:47:17 -0800 Subject: [PATCH] Fixed some bugs relating to text and cursor printing. --- src/buffer/line.rs | 47 +++++++++++++++++++++++++++++++++++++++++++- src/buffer/mod.rs | 20 +++++++++++++++++++ src/buffer/node.rs | 36 ++++++++++++++++++++++++++++++++++ src/term_ui.rs | 49 ++++++++++++++++++++++++++++++---------------- 4 files changed, 134 insertions(+), 18 deletions(-) diff --git a/src/buffer/line.rs b/src/buffer/line.rs index 69ec5e0..c82ec45 100644 --- a/src/buffer/line.rs +++ b/src/buffer/line.rs @@ -245,6 +245,42 @@ impl Line { } + pub fn grapheme_at_index<'a>(&'a self, index: uint) -> &'a str { + let mut iter = self.grapheme_iter(); + let mut i = 0; + + for g in iter { + if i == index { + return g; + } + else { + i += 1; + } + } + + // Should never get here + panic!("Line::grapheme_at_index(): index past end of line."); + } + + + pub fn grapheme_width_at_index(&self, index: uint) -> uint { + let mut iter = self.grapheme_vis_iter(); + let mut i = 0; + + for (_, _, width) in iter { + if i == index { + return width; + } + else { + i += 1; + } + } + + // Should never get here + panic!("Line::grapheme_at_index(): index past end of line."); + } + + /// Translates a grapheme index into a visual horizontal position pub fn grapheme_index_to_closest_vis_pos(&self, index: uint) -> uint { let mut pos = 0; @@ -604,7 +640,9 @@ impl<'a> LineGraphemeVisIter<'a> { } } - pub fn skip_vis_positions(&mut self, n: uint) { + // Skips at least n visual positions, and returns the number of excess + // skipped visual positions beyond n. + pub fn skip_vis_positions(&mut self, n: uint) -> uint { let mut i = 0; while i < n { if let Some((_, _, width)) = self.next() { @@ -614,6 +652,13 @@ impl<'a> LineGraphemeVisIter<'a> { break; } } + + if i > n { + return i - n; + } + else { + return 0; + } } } diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index fd631e4..1deb7a2 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -38,6 +38,26 @@ impl Buffer { } + pub fn get_grapheme<'a>(&'a self, index: uint) -> &'a str { + if index >= self.len() { + panic!("Buffer::get_grapheme(): index past last grapheme."); + } + else { + return self.root.get_grapheme_recursive(index); + } + } + + + pub fn get_grapheme_width(&self, index: uint) -> uint { + if index >= self.len() { + panic!("Buffer::get_grapheme_width(): index past last grapheme."); + } + else { + return self.root.get_grapheme_width_recursive(index); + } + } + + pub fn get_line<'a>(&'a self, index: uint) -> &'a Line { if index >= self.line_count() { panic!("get_line(): index out of bounds."); diff --git a/src/buffer/node.rs b/src/buffer/node.rs index 495e52e..2106f36 100644 --- a/src/buffer/node.rs +++ b/src/buffer/node.rs @@ -184,6 +184,42 @@ impl BufferNode { } + pub fn get_grapheme_recursive<'a>(&'a self, index: uint) -> &'a str { + match self.data { + BufferNodeData::Leaf(ref line) => { + return line.grapheme_at_index(index); + }, + + BufferNodeData::Branch(ref left, ref right) => { + if index < left.grapheme_count { + return left.get_grapheme_recursive(index); + } + else { + return right.get_grapheme_recursive(index - left.grapheme_count); + } + } + } + } + + + pub fn get_grapheme_width_recursive(&self, index: uint) -> uint { + match self.data { + BufferNodeData::Leaf(ref line) => { + return line.grapheme_width_at_index(index); + }, + + BufferNodeData::Branch(ref left, ref right) => { + if index < left.grapheme_count { + return left.get_grapheme_width_recursive(index); + } + else { + return right.get_grapheme_width_recursive(index - left.grapheme_count); + } + } + } + } + + pub fn get_line_recursive<'a>(&'a self, index: uint) -> &'a Line { match self.data { BufferNodeData::Leaf(ref line) => { diff --git a/src/term_ui.rs b/src/term_ui.rs index e828ee7..c5541dd 100644 --- a/src/term_ui.rs +++ b/src/term_ui.rs @@ -155,28 +155,32 @@ impl TermUI { pub fn draw_editor(&self, editor: &Editor, c1: (uint, uint), c2: (uint, uint)) { let mut line_iter = editor.buffer.line_iter_at_index(editor.view_pos.0); - let mut line_num = editor.view_pos.0; - let mut col_num = editor.view_pos.1; + let mut grapheme_index; + + let mut vis_line_num = editor.view_pos.0; + let mut vis_col_num = editor.view_pos.1; let mut print_line_num = c1.0; - let mut print_col_num; + let mut print_col_num = c1.1; let max_print_line = c2.0 - c1.0; let max_print_col = c2.1 - c1.1; - let cursor_pos = editor.buffer.pos_1d_to_closest_2d(editor.cursor.range.0); - let print_cursor_pos = (cursor_pos.0 + editor.view_pos.0, cursor_pos.1 + editor.view_pos.1); - loop { if let Some(line) = line_iter.next() { let mut g_iter = line.grapheme_vis_iter(); - g_iter.skip_vis_positions(editor.view_pos.1); + let excess = g_iter.skip_vis_positions(editor.view_pos.1); + + vis_col_num += excess; + print_col_num += excess; + + grapheme_index = editor.buffer.pos_vis_2d_to_closest_1d((vis_line_num, vis_col_num)); for (g, pos, width) in g_iter { print_col_num = pos - editor.view_pos.1; if is_line_ending(g) { - if (line_num, col_num) == cursor_pos { + if grapheme_index == editor.cursor.range.0 { self.rb.print(print_col_num, print_line_num, rustbox::RB_NORMAL, Color::Black, Color::White, " "); } } @@ -185,12 +189,12 @@ impl TermUI { self.rb.print(i, print_line_num, rustbox::RB_NORMAL, Color::White, Color::Black, " "); } - if (line_num, col_num) == cursor_pos { + if grapheme_index == editor.cursor.range.0 { self.rb.print(print_col_num, print_line_num, rustbox::RB_NORMAL, Color::Black, Color::White, " "); } } else { - if (line_num, col_num) == cursor_pos { + if grapheme_index == editor.cursor.range.0 { self.rb.print(print_col_num, print_line_num, rustbox::RB_NORMAL, Color::Black, Color::White, g); } else { @@ -198,7 +202,8 @@ impl TermUI { } } - col_num += 1; + vis_col_num += width; + grapheme_index += 1; print_col_num += width; if print_col_num > max_print_col { @@ -206,21 +211,31 @@ impl TermUI { } } } - else if print_cursor_pos.0 >= c1.0 && print_cursor_pos.0 < c2.0 && print_cursor_pos.1 >= c1.1 && print_cursor_pos.1 < c2.1 { - if editor.cursor.range.0 >= editor.buffer.len() { - self.rb.print(print_cursor_pos.1, print_cursor_pos.0, rustbox::RB_NORMAL, Color::Black, Color::White, " "); - } + else { break; } - line_num += 1; + vis_line_num += 1; print_line_num += 1; - col_num = editor.view_pos.1; + vis_col_num = editor.view_pos.1; if print_line_num > max_print_line { break; } } + + // Print cursor if it's at the end of the text, and thus wasn't printed + // already. + if editor.cursor.range.0 >= editor.buffer.len() { + let vis_cursor_pos = editor.buffer.pos_1d_to_closest_vis_2d(editor.cursor.range.0); + if (vis_cursor_pos.0 >= editor.view_pos.0) && (vis_cursor_pos.1 >= editor.view_pos.1) { + let print_cursor_pos = (vis_cursor_pos.0 - editor.view_pos.0, vis_cursor_pos.1 - editor.view_pos.1); + + if print_cursor_pos.0 >= c1.0 && print_cursor_pos.0 <= c2.0 && print_cursor_pos.1 >= c1.1 && print_cursor_pos.1 <= c2.1 { + self.rb.print(print_cursor_pos.1, print_cursor_pos.0, rustbox::RB_NORMAL, Color::Black, Color::White, " "); + } + } + } }