Console drawing is almost back up to snuff.

Just missing drawing the cursors if it's at the end of the text buffer.
This commit is contained in:
Nathan Vegdahl 2015-01-24 21:00:30 -08:00
parent c69ebc240f
commit 4caad17e56
5 changed files with 140 additions and 54 deletions

View File

@ -288,7 +288,7 @@ impl<T: LineFormatter> Buffer<T> {
/// If the index is off the end of the text, returns the line and column /// If the index is off the end of the text, returns the line and column
/// number of the last valid text position. /// number of the last valid text position.
pub fn index_to_line_col(&self, pos: usize) -> (usize, usize) { pub fn index_to_line_col(&self, pos: usize) -> (usize, usize) {
return self.text.pos_1d_to_closest_2d_recursive(pos); return self.text.index_to_line_col_recursive(pos);
} }
@ -300,7 +300,7 @@ impl<T: LineFormatter> Buffer<T> {
/// beyond the end of the buffer, returns the index of the buffer's last /// beyond the end of the buffer, returns the index of the buffer's last
/// valid position. /// valid position.
pub fn line_col_to_index(&self, pos: (usize, usize)) -> usize { pub fn line_col_to_index(&self, pos: (usize, usize)) -> usize {
return self.text.pos_2d_to_closest_1d_recursive(pos); return self.text.line_col_to_index_recursive(pos);
} }
@ -309,11 +309,11 @@ impl<T: LineFormatter> Buffer<T> {
/// If the index is off the end of the text, returns the visual line and /// If the index is off the end of the text, returns the visual line and
/// column number of the last valid text position. /// column number of the last valid text position.
pub fn index_to_v2d(&self, pos: usize) -> (usize, usize) { pub fn index_to_v2d(&self, pos: usize) -> (usize, usize) {
// TODO: update this to use the new LineFormatter stuff let mut index = pos;
//let (v, h) = self.text.pos_1d_to_closest_2d_recursive(pos); if index > self.grapheme_count() {
//let vis_h = self.get_line(v).grapheme_index_to_closest_vis_pos(h, self.tab_width); index = self.grapheme_count();
//return (v, vis_h); }
return (0, 0); return self.text.index_to_v2d_recursive(&self.formatter, index);
} }
@ -324,16 +324,7 @@ impl<T: LineFormatter> Buffer<T> {
/// number given is beyond the end of the buffer, returns the index of /// number given is beyond the end of the buffer, returns the index of
/// the buffer's last valid position. /// the buffer's last valid position.
pub fn v2d_to_index(&self, pos: (usize, usize), rounding: (RoundingBehavior, RoundingBehavior)) -> usize { pub fn v2d_to_index(&self, pos: (usize, usize), rounding: (RoundingBehavior, RoundingBehavior)) -> usize {
// TODO: update this to use the new LineFormatter stuff return self.text.v2d_to_index_recursive(&self.formatter, pos, rounding);
//if pos.0 >= self.line_count() {
// return self.grapheme_count();
//}
//else {
// let gs = self.line_col_to_index((pos.0, 0));
// let h = self.get_line(pos.0).vis_pos_to_closest_grapheme_index(pos.1, self.tab_width);
// return gs + h;
//}
return 0;
} }

View File

@ -1,7 +1,7 @@
use std::mem; use std::mem;
use std::cmp::{min, max}; use std::cmp::{min, max};
use line_formatter::LineFormatter; use line_formatter::{LineFormatter, RoundingBehavior};
use string_utils::is_line_ending; use string_utils::is_line_ending;
use super::line::{Line, LineEnding, LineGraphemeIter, str_to_line_ending}; use super::line::{Line, LineEnding, LineGraphemeIter, str_to_line_ending};
@ -234,7 +234,26 @@ impl BufferNode {
} }
pub fn pos_2d_to_closest_1d_recursive(&self, pos: (usize, usize)) -> usize { pub fn index_to_line_col_recursive(&self, index: usize) -> (usize, usize) {
match self.data {
BufferNodeData::Leaf(_) => {
return (0, min(index, self.grapheme_count));
},
BufferNodeData::Branch(ref left, ref right) => {
if index < left.grapheme_count {
return left.index_to_line_col_recursive(index);
}
else {
let (v, h) = right.index_to_line_col_recursive((index - left.grapheme_count));
return (v + left.line_count, h);
}
}
}
}
pub fn line_col_to_index_recursive(&self, pos: (usize, usize)) -> usize {
match self.data { match self.data {
BufferNodeData::Leaf(ref line) => { BufferNodeData::Leaf(ref line) => {
if pos.0 != 0 { if pos.0 != 0 {
@ -256,29 +275,60 @@ impl BufferNode {
BufferNodeData::Branch(ref left, ref right) => { BufferNodeData::Branch(ref left, ref right) => {
if pos.0 < left.line_count { if pos.0 < left.line_count {
return left.pos_2d_to_closest_1d_recursive(pos); return left.line_col_to_index_recursive(pos);
} }
else { else {
return left.grapheme_count + right.pos_2d_to_closest_1d_recursive((pos.0 - left.line_count, pos.1)); return left.grapheme_count + right.line_col_to_index_recursive((pos.0 - left.line_count, pos.1));
} }
} }
} }
} }
pub fn pos_1d_to_closest_2d_recursive(&self, pos: usize) -> (usize, usize) { pub fn index_to_v2d_recursive<T: LineFormatter>(&self, f: &T, index: usize) -> (usize, usize) {
match self.data { match self.data {
BufferNodeData::Leaf(_) => { BufferNodeData::Leaf(ref line) => {
return (0, min(pos, self.grapheme_count)); return f.index_to_v2d(line, index);
}, },
BufferNodeData::Branch(ref left, ref right) => { BufferNodeData::Branch(ref left, ref right) => {
if pos < left.grapheme_count { if index < left.grapheme_count {
return left.pos_1d_to_closest_2d_recursive(pos); return left.index_to_v2d_recursive(f, index);
} }
else { else {
let (v, h) = right.pos_1d_to_closest_2d_recursive((pos - left.grapheme_count)); let (y, x) = right.index_to_v2d_recursive(f, (index - left.grapheme_count));
return (v + left.line_count, h); return (y + left.vis_dim.0, x);
}
}
}
}
pub fn v2d_to_index_recursive<T: LineFormatter>(&self, f: &T, pos: (usize, usize), rounding: (RoundingBehavior, RoundingBehavior)) -> usize {
match self.data {
BufferNodeData::Leaf(ref line) => {
return f.v2d_to_index(line, pos, rounding);
},
BufferNodeData::Branch(ref left, ref right) => {
let lh = f.single_line_height();
if rounding.0 == RoundingBehavior::Round {
// TODO
return 0;
}
else if rounding.0 == RoundingBehavior::Floor {
if pos.0 < left.vis_dim.0 {
return left.v2d_to_index_recursive(f, pos, rounding);
}
else {
return left.grapheme_count + right.v2d_to_index_recursive(f, (pos.0 - left.vis_dim.0, pos.1), rounding);
}
}
else { // RoundingBehavior::Ceiling
// TODO
return 0;
} }
} }
} }

View File

@ -58,11 +58,11 @@ impl Editor {
}; };
// For multiple-cursor testing // For multiple-cursor testing
let mut cur = Cursor::new(); //let mut cur = Cursor::new();
cur.range.0 = 30; //cur.range.0 = 30;
cur.range.1 = 30; //cur.range.1 = 30;
cur.update_vis_start(&(ed.buffer)); //cur.update_vis_start(&(ed.buffer));
ed.cursors.add_cursor(cur); //ed.cursors.add_cursor(cur);
ed.auto_detect_indentation_style(); ed.auto_detect_indentation_style();

View File

@ -1,6 +1,7 @@
use buffer::line::{Line, LineGraphemeIter}; use buffer::line::{Line, LineGraphemeIter};
use string_utils::{is_line_ending}; use string_utils::{is_line_ending};
#[derive(Copy, PartialEq)]
pub enum RoundingBehavior { pub enum RoundingBehavior {
Round, Round,
Floor, Floor,
@ -8,6 +9,8 @@ pub enum RoundingBehavior {
} }
pub trait LineFormatter { pub trait LineFormatter {
fn single_line_height(&self) -> usize;
fn dimensions(&self, line: &Line) -> (usize, usize); fn dimensions(&self, line: &Line) -> (usize, usize);
fn index_to_v2d(&self, line: &Line, index: usize) -> (usize, usize); fn index_to_v2d(&self, line: &Line, index: usize) -> (usize, usize);
@ -36,8 +39,10 @@ impl<'a> Iterator for ConsoleLineFormatterVisIter<'a> {
fn next(&mut self) -> Option<(&'a str, usize, usize)> { fn next(&mut self) -> Option<(&'a str, usize, usize)> {
if let Some(g) = self.grapheme_iter.next() { if let Some(g) = self.grapheme_iter.next() {
let pos = self.pos; let pos = self.pos;
let width = grapheme_vis_width_at_vis_pos(g, self.pos.1, self.f.tab_width as usize); let width = grapheme_vis_width_at_vis_pos(g, self.pos.1, self.f.tab_width as usize);
self.pos = (self.pos.0, self.pos.1 + width); self.pos = (self.pos.0, self.pos.1 + width);
return Some((g, pos.0, pos.1)); return Some((g, pos.0, pos.1));
} }
else { else {
@ -84,6 +89,10 @@ impl ConsoleLineFormatter {
impl<'a> LineFormatter for ConsoleLineFormatter { impl<'a> LineFormatter for ConsoleLineFormatter {
fn single_line_height(&self) -> usize {
return 1;
}
fn dimensions(&self, line: &Line) -> (usize, usize) { fn dimensions(&self, line: &Line) -> (usize, usize) {
return (1, self.vis_width(line)); return (1, self.vis_width(line));
} }

View File

@ -7,7 +7,7 @@ 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 buffer::line::{line_ending_to_str, LineEnding}; use buffer::line::{line_ending_to_str, LineEnding};
use line_formatter::LineFormatter; use line_formatter::{LineFormatter, RoundingBehavior};
// Key codes // Key codes
const K_ENTER: u16 = 13; const K_ENTER: u16 = 13;
@ -335,32 +335,68 @@ impl TermUI {
fn draw_editor_text(&self, editor: &Editor, c1: (usize, usize), c2: (usize, usize)) { fn draw_editor_text(&self, editor: &Editor, c1: (usize, usize), c2: (usize, usize)) {
let mut line_iter = editor.buffer.line_iter_at_index(editor.view_pos.0); // Calculate all the starting info
let editor_corner_index = editor.buffer.v2d_to_index(editor.view_pos, (RoundingBehavior::Floor, RoundingBehavior::Floor));
let (starting_line, _) = editor.buffer.index_to_line_col(editor_corner_index);
let mut grapheme_index = editor.buffer.line_col_to_index((starting_line, 0));
let (vis_starting_line, _) = editor.buffer.index_to_v2d(grapheme_index);
//let mut grapheme_index; let mut screen_line = c1.0 as isize + vis_starting_line as isize;
let screen_col = c1.1 as isize;
let mut vis_line_num = editor.view_pos.0; let mut line_iter = editor.buffer.line_iter_at_index(starting_line);
let mut vis_col_num = editor.view_pos.1; for line in line_iter {
let mut print_line_num = c1.0;
let mut print_col_num = c1.1;
let max_print_line = c2.0;
let max_print_col = c2.1;
loop {
if let Some(line) = line_iter.next() {
let mut g_iter = editor.buffer.formatter.vis_grapheme_iter(line); let mut g_iter = editor.buffer.formatter.vis_grapheme_iter(line);
let mut last_y = 0;
// Loop through the graphemes of the line and print them to
// the screen.
for (g, pos_y, pos_x) in g_iter { for (g, pos_y, pos_x) in g_iter {
self.rb.print(pos_x, pos_y, rustbox::RB_NORMAL, Color::White, Color::Black, g); last_y = pos_y;
// Calculate the cell coordinates at which to draw the grapheme
let px = pos_x as isize + screen_col - editor.view_pos.1 as isize;
let py = pos_y as isize + screen_line - editor.view_pos.0 as isize;
// If we're off the bottom, we're done
if py > c2.0 as isize {
return;
}
// Draw the grapheme to the screen if it's in bounds
if (px >= c1.1 as isize) && (py >= c1.0 as isize) && (px <= c2.1 as isize) {
// Check if the character is within a cursor
let mut at_cursor = false;
for c in editor.cursors.iter() {
if grapheme_index >= c.range.0 && grapheme_index <= c.range.1 {
at_cursor = true;
}
}
// Actually print the character
if is_line_ending(g) || g == "\t" {
if at_cursor {
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " ");
} }
} }
else { else {
break; if at_cursor {
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, g);
}
else {
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::White, Color::Black, g);
} }
} }
} }
grapheme_index += 1;
}
screen_line += last_y as isize + 1;
}
// TODO: handle printing the cursor when it's at the end of the buffer.
}
} }