First step in pulling formatters out of the text buffer.

This commit pulls the formatter out of the text buffer and
puts it in the editor instead.  However, there is a lot of
commented code utlizing the buffer and formatter that still
needs to be updated.

In short, the editor is pretty non-functional in this commit.
This commit is contained in:
Nathan Vegdahl 2015-02-06 19:47:52 -08:00
parent e29777e33c
commit 8319033ae5
8 changed files with 411 additions and 525 deletions

View File

@ -9,11 +9,9 @@ use self::line::Line;
use self::node::{BufferNode, BufferNodeGraphemeIter, BufferNodeLineIter}; use self::node::{BufferNode, BufferNodeGraphemeIter, BufferNodeLineIter};
use self::undo_stack::{UndoStack}; use self::undo_stack::{UndoStack};
use self::undo_stack::Operation::*; use self::undo_stack::Operation::*;
use self::line_formatter::{LineFormatter, RoundingBehavior};
use string_utils::{is_line_ending, grapheme_count}; use string_utils::{is_line_ending, grapheme_count};
pub mod line; pub mod line;
pub mod line_formatter;
mod node; mod node;
mod undo_stack; mod undo_stack;
@ -23,33 +21,30 @@ mod undo_stack;
//============================================================= //=============================================================
/// A text buffer /// A text buffer
pub struct Buffer<T: LineFormatter> { pub struct Buffer {
text: BufferNode, text: BufferNode,
file_path: Option<Path>, file_path: Option<Path>,
undo_stack: UndoStack, undo_stack: UndoStack,
pub formatter: T,
} }
impl<T: LineFormatter> Buffer<T> { impl Buffer {
pub fn new(formatter: T) -> Buffer<T> { pub fn new() -> Buffer {
Buffer { Buffer {
text: BufferNode::new(&formatter), text: BufferNode::new(),
file_path: None, file_path: None,
undo_stack: UndoStack::new(), undo_stack: UndoStack::new(),
formatter: formatter,
} }
} }
pub fn new_from_file(formatter: T, path: &Path) -> IoResult<Buffer<T>> { pub fn new_from_file(path: &Path) -> IoResult<Buffer> {
let mut f = BufferedReader::new(try!(File::open(path))); let mut f = BufferedReader::new(try!(File::open(path)));
let mut buf = Buffer { let mut buf = Buffer {
text: BufferNode::new(&formatter), text: BufferNode::new(),
file_path: Some(path.clone()), file_path: Some(path.clone()),
undo_stack: UndoStack::new(), undo_stack: UndoStack::new(),
formatter: formatter,
}; };
let string = f.read_to_string().unwrap(); let string = f.read_to_string().unwrap();
@ -77,7 +72,7 @@ impl<T: LineFormatter> Buffer<T> {
if a != b { if a != b {
let substr = &string[a..b]; let substr = &string[a..b];
let line = Line::new_from_str_unchecked(substr); let line = Line::new_from_str_unchecked(substr);
let node = BufferNode::new_from_line_with_count_unchecked(&buf.formatter, line, count); let node = BufferNode::new_from_line_with_count_unchecked(line, count);
buf.append_leaf_node_unchecked(node); buf.append_leaf_node_unchecked(node);
} }
@ -92,6 +87,7 @@ impl<T: LineFormatter> Buffer<T> {
//------------------------------------------------------------------------ //------------------------------------------------------------------------
// Functions for getting information about the buffer. // Functions for getting information about the buffer.
//------------------------------------------------------------------------ //------------------------------------------------------------------------
@ -106,10 +102,6 @@ impl<T: LineFormatter> Buffer<T> {
} }
pub fn dimensions(&self) -> (usize, usize) {
self.text.vis_dim
}
//------------------------------------------------------------------------ //------------------------------------------------------------------------
@ -124,7 +116,7 @@ impl<T: LineFormatter> Buffer<T> {
} }
fn _insert_text(&mut self, text: &str, pos: usize) { fn _insert_text(&mut self, text: &str, pos: usize) {
self.text.insert_text(&self.formatter, text, pos); self.text.insert_text(text, pos);
} }
@ -168,15 +160,15 @@ impl<T: LineFormatter> Buffer<T> {
} }
// Complete removal of all text // Complete removal of all text
else if pos_a == 0 && pos_b == self.text.grapheme_count { else if pos_a == 0 && pos_b == self.text.grapheme_count {
let mut temp_node = BufferNode::new(&self.formatter); let mut temp_node = BufferNode::new();
mem::swap(&mut (self.text), &mut temp_node); mem::swap(&mut (self.text), &mut temp_node);
} }
// All other cases // All other cases
else { else {
if self.text.remove_text_recursive(&self.formatter, pos_a, pos_b, true) { if self.text.remove_text_recursive(pos_a, pos_b, true) {
panic!("Buffer::_remove_text(): dangling left side remains. This should never happen!"); panic!("Buffer::_remove_text(): dangling left side remains. This should never happen!");
} }
self.text.set_last_line_ending_recursive(&self.formatter); self.text.set_last_line_ending_recursive();
} }
} }
@ -241,13 +233,13 @@ impl<T: LineFormatter> Buffer<T> {
} }
// Complete removal of all lines // Complete removal of all lines
else if line_a == 0 && line_b == self.text.line_count { else if line_a == 0 && line_b == self.text.line_count {
let mut temp_node = BufferNode::new(&self.formatter); let mut temp_node = BufferNode::new();
mem::swap(&mut (self.text), &mut temp_node); mem::swap(&mut (self.text), &mut temp_node);
} }
// All other cases // All other cases
else { else {
self.text.remove_lines_recursive(&self.formatter, line_a, line_b); self.text.remove_lines_recursive(line_a, line_b);
self.text.set_last_line_ending_recursive(&self.formatter); self.text.set_last_line_ending_recursive();
} }
} }
@ -256,19 +248,12 @@ impl<T: LineFormatter> Buffer<T> {
/// doing any sanity checks. This is primarily for efficient /// doing any sanity checks. This is primarily for efficient
/// file loading. /// file loading.
pub fn append_line_unchecked(&mut self, line: Line) { pub fn append_line_unchecked(&mut self, line: Line) {
self.text.append_line_unchecked_recursive(&self.formatter, line); self.text.append_line_unchecked_recursive(line);
} }
fn append_leaf_node_unchecked(&mut self, node: BufferNode) { fn append_leaf_node_unchecked(&mut self, node: BufferNode) {
self.text.append_leaf_node_unchecked_recursive(&self.formatter, node); self.text.append_leaf_node_unchecked_recursive(node);
}
/// Runs the formatter on all of the text. Should be run whenever the
/// formatter has been changed.
pub fn reformat(&mut self) {
self.text.reformat_recursive(&self.formatter);
} }
@ -376,31 +361,6 @@ impl<T: LineFormatter> Buffer<T> {
} }
/// Converts a grapheme index into a visual line and column number.
///
/// If the index is off the end of the text, returns the visual line and
/// column number of the last valid text position.
pub fn index_to_v2d(&self, pos: usize) -> (usize, usize) {
let mut index = pos;
if index > self.grapheme_count() {
index = self.grapheme_count();
}
return self.text.index_to_v2d_recursive(&self.formatter, index);
}
/// Converts a visual line and column number into a grapheme index.
///
/// If the visual column number given is outside of the text, returns the
/// index of the horizontally-closest valid position. If the visual line
/// number given is beyond the end of the buffer, returns the index of
/// the buffer's last valid position.
pub fn v2d_to_index(&self, pos: (usize, usize), rounding: (RoundingBehavior, RoundingBehavior)) -> usize {
return self.text.v2d_to_index_recursive(&self.formatter, pos, rounding);
}
//------------------------------------------------------------------------ //------------------------------------------------------------------------
// Text reading functions // Text reading functions
//------------------------------------------------------------------------ //------------------------------------------------------------------------
@ -575,12 +535,11 @@ impl<'a> Iterator for BufferLineIter<'a> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::line_formatter::TestLineFormatter;
use super::{Buffer, BufferGraphemeIter, BufferLineIter}; use super::{Buffer, BufferGraphemeIter, BufferLineIter};
#[test] #[test]
fn insert_text() { fn insert_text() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hello 世界!", 0); buf.insert_text("Hello 世界!", 0);
@ -603,7 +562,7 @@ mod tests {
#[test] #[test]
fn insert_text_with_newlines() { fn insert_text_with_newlines() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hello\n 世界\r\n!", 0); buf.insert_text("Hello\n 世界\r\n!", 0);
@ -628,7 +587,7 @@ mod tests {
#[test] #[test]
fn insert_text_in_non_empty_buffer_1() { fn insert_text_in_non_empty_buffer_1() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hello\n 世界\r\n!", 0); buf.insert_text("Hello\n 世界\r\n!", 0);
buf.insert_text("Again ", 0); buf.insert_text("Again ", 0);
@ -660,7 +619,7 @@ mod tests {
#[test] #[test]
fn insert_text_in_non_empty_buffer_2() { fn insert_text_in_non_empty_buffer_2() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hello\n 世界\r\n!", 0); buf.insert_text("Hello\n 世界\r\n!", 0);
buf.insert_text(" again", 5); buf.insert_text(" again", 5);
@ -692,7 +651,7 @@ mod tests {
#[test] #[test]
fn insert_text_in_non_empty_buffer_3() { fn insert_text_in_non_empty_buffer_3() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hello\n 世界\r\n!", 0); buf.insert_text("Hello\n 世界\r\n!", 0);
buf.insert_text("again", 6); buf.insert_text("again", 6);
@ -723,7 +682,7 @@ mod tests {
#[test] #[test]
fn insert_text_in_non_empty_buffer_4() { fn insert_text_in_non_empty_buffer_4() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hello\n 世界\r\n!", 0); buf.insert_text("Hello\n 世界\r\n!", 0);
buf.insert_text("again", 11); buf.insert_text("again", 11);
@ -754,7 +713,7 @@ mod tests {
#[test] #[test]
fn insert_text_in_non_empty_buffer_5() { fn insert_text_in_non_empty_buffer_5() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hello\n 世界\r\n!", 0); buf.insert_text("Hello\n 世界\r\n!", 0);
buf.insert_text("again", 2); buf.insert_text("again", 2);
@ -786,7 +745,7 @@ mod tests {
#[test] #[test]
fn insert_text_in_non_empty_buffer_6() { fn insert_text_in_non_empty_buffer_6() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hello\n 世界\r\n!", 0); buf.insert_text("Hello\n 世界\r\n!", 0);
buf.insert_text("again", 8); buf.insert_text("again", 8);
@ -818,7 +777,7 @@ mod tests {
#[test] #[test]
fn insert_text_in_non_empty_buffer_7() { fn insert_text_in_non_empty_buffer_7() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hello\n 世界\r\n!", 0); buf.insert_text("Hello\n 世界\r\n!", 0);
buf.insert_text("\nag\n\nain\n", 2); buf.insert_text("\nag\n\nain\n", 2);
@ -854,7 +813,7 @@ mod tests {
#[test] #[test]
fn remove_text_1() { fn remove_text_1() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.grapheme_count() == 29); assert!(buf.grapheme_count() == 29);
@ -898,7 +857,7 @@ mod tests {
#[test] #[test]
fn remove_text_2() { fn remove_text_2() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.grapheme_count() == 29); assert!(buf.grapheme_count() == 29);
@ -933,7 +892,7 @@ mod tests {
#[test] #[test]
fn remove_text_3() { fn remove_text_3() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.grapheme_count() == 29); assert!(buf.grapheme_count() == 29);
@ -968,7 +927,7 @@ mod tests {
#[test] #[test]
fn remove_text_4() { fn remove_text_4() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.grapheme_count() == 29); assert!(buf.grapheme_count() == 29);
@ -1009,7 +968,7 @@ mod tests {
#[test] #[test]
fn remove_text_5() { fn remove_text_5() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.grapheme_count() == 29); assert!(buf.grapheme_count() == 29);
@ -1044,7 +1003,7 @@ mod tests {
#[test] #[test]
fn remove_text_6() { fn remove_text_6() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hello\nworld!", 0); buf.insert_text("Hello\nworld!", 0);
assert!(buf.grapheme_count() == 12); assert!(buf.grapheme_count() == 12);
@ -1065,7 +1024,7 @@ mod tests {
#[test] #[test]
fn remove_text_7() { fn remove_text_7() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\nworld!", 0); buf.insert_text("Hi\nthere\nworld!", 0);
assert!(buf.grapheme_count() == 15); assert!(buf.grapheme_count() == 15);
@ -1088,7 +1047,7 @@ mod tests {
#[test] #[test]
fn remove_text_8() { fn remove_text_8() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hello\nworld!", 0); buf.insert_text("Hello\nworld!", 0);
assert!(buf.grapheme_count() == 12); assert!(buf.grapheme_count() == 12);
@ -1110,7 +1069,7 @@ mod tests {
#[test] #[test]
fn remove_text_9() { fn remove_text_9() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hello\nworld!", 0); buf.insert_text("Hello\nworld!", 0);
assert!(buf.grapheme_count() == 12); assert!(buf.grapheme_count() == 12);
@ -1136,7 +1095,7 @@ mod tests {
#[test] #[test]
fn remove_text_10() { fn remove_text_10() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("12\n34\n56\n78", 0); buf.insert_text("12\n34\n56\n78", 0);
assert!(buf.grapheme_count() == 11); assert!(buf.grapheme_count() == 11);
@ -1158,7 +1117,7 @@ mod tests {
#[test] #[test]
fn remove_text_11() { fn remove_text_11() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("1234567890", 0); buf.insert_text("1234567890", 0);
assert!(buf.grapheme_count() == 10); assert!(buf.grapheme_count() == 10);
@ -1185,7 +1144,7 @@ mod tests {
#[test] #[test]
fn move_text_1() { fn move_text_1() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
@ -1230,7 +1189,7 @@ mod tests {
#[test] #[test]
fn move_text_2() { fn move_text_2() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
@ -1275,7 +1234,7 @@ mod tests {
#[test] #[test]
fn move_text_3() { fn move_text_3() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
@ -1320,7 +1279,7 @@ mod tests {
#[test] #[test]
fn move_text_4() { fn move_text_4() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
@ -1365,7 +1324,7 @@ mod tests {
#[test] #[test]
fn move_text_5() { fn move_text_5() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
@ -1410,7 +1369,7 @@ mod tests {
#[test] #[test]
fn remove_lines_1() { fn remove_lines_1() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.grapheme_count() == 29); assert!(buf.grapheme_count() == 29);
@ -1441,7 +1400,7 @@ mod tests {
#[test] #[test]
fn remove_lines_2() { fn remove_lines_2() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.grapheme_count() == 29); assert!(buf.grapheme_count() == 29);
@ -1472,7 +1431,7 @@ mod tests {
#[test] #[test]
fn remove_lines_3() { fn remove_lines_3() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.grapheme_count() == 29); assert!(buf.grapheme_count() == 29);
@ -1505,7 +1464,7 @@ mod tests {
#[test] #[test]
fn line_col_to_index_1() { fn line_col_to_index_1() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
let pos = buf.line_col_to_index((2, 3)); let pos = buf.line_col_to_index((2, 3));
@ -1516,7 +1475,7 @@ mod tests {
#[test] #[test]
fn line_col_to_index_2() { fn line_col_to_index_2() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
let pos = buf.line_col_to_index((2, 10)); let pos = buf.line_col_to_index((2, 10));
@ -1526,7 +1485,7 @@ mod tests {
#[test] #[test]
fn line_col_to_index_3() { fn line_col_to_index_3() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
let pos = buf.line_col_to_index((10, 2)); let pos = buf.line_col_to_index((10, 2));
@ -1537,7 +1496,7 @@ mod tests {
#[test] #[test]
fn index_to_line_col_1() { fn index_to_line_col_1() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
let pos = buf.index_to_line_col(5); let pos = buf.index_to_line_col(5);
@ -1548,7 +1507,7 @@ mod tests {
#[test] #[test]
fn index_to_line_col_2() { fn index_to_line_col_2() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
let pos = buf.index_to_line_col(50); let pos = buf.index_to_line_col(50);
@ -1559,7 +1518,7 @@ mod tests {
#[test] #[test]
fn string_from_range_1() { fn string_from_range_1() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
let s = buf.string_from_range(1, 12); let s = buf.string_from_range(1, 12);
@ -1570,7 +1529,7 @@ mod tests {
#[test] #[test]
fn string_from_range_2() { fn string_from_range_2() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
let s = buf.string_from_range(0, 29); let s = buf.string_from_range(0, 29);
@ -1581,7 +1540,7 @@ mod tests {
#[test] #[test]
fn grapheme_iter_at_index_1() { fn grapheme_iter_at_index_1() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
let mut iter = buf.grapheme_iter_at_index(16); let mut iter = buf.grapheme_iter_at_index(16);
@ -1605,7 +1564,7 @@ mod tests {
#[test] #[test]
fn grapheme_iter_at_index_2() { fn grapheme_iter_at_index_2() {
let mut buf = Buffer::new(TestLineFormatter::new()); let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
let mut iter = buf.grapheme_iter_at_index(29); let mut iter = buf.grapheme_iter_at_index(29);

View File

@ -1,7 +1,6 @@
use std::mem; use std::mem;
use std::cmp::{min, max}; use std::cmp::{min, max};
use super::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};
@ -16,46 +15,39 @@ pub struct BufferNode {
pub grapheme_count: usize, pub grapheme_count: usize,
pub line_count: usize, pub line_count: usize,
pub vis_dim: (usize, usize), // Height, width
} }
impl BufferNode { impl BufferNode {
pub fn new<T: LineFormatter>(f: &T) -> BufferNode { pub fn new() -> BufferNode {
let line = Line::new(); let line = Line::new();
let dim = f.dimensions(&line);
BufferNode { BufferNode {
data: BufferNodeData::Leaf(line), data: BufferNodeData::Leaf(line),
tree_height: 1, tree_height: 1,
grapheme_count: 0, grapheme_count: 0,
line_count: 1, line_count: 1,
vis_dim: dim,
} }
} }
pub fn new_from_line<T: LineFormatter>(f: &T, line: Line) -> BufferNode { pub fn new_from_line(line: Line) -> BufferNode {
let gc = line.grapheme_count(); let gc = line.grapheme_count();
let dim = f.dimensions(&line);
BufferNode { BufferNode {
data: BufferNodeData::Leaf(line), data: BufferNodeData::Leaf(line),
tree_height: 1, tree_height: 1,
grapheme_count: gc, grapheme_count: gc,
line_count: 1, line_count: 1,
vis_dim: dim,
} }
} }
pub fn new_from_line_with_count_unchecked<T: LineFormatter>(_: &T, line: Line, grapheme_count: usize) -> BufferNode { pub fn new_from_line_with_count_unchecked(line: Line, grapheme_count: usize) -> BufferNode {
BufferNode { BufferNode {
data: BufferNodeData::Leaf(line), data: BufferNodeData::Leaf(line),
tree_height: 1, tree_height: 1,
grapheme_count: grapheme_count, grapheme_count: grapheme_count,
line_count: 1, line_count: 1,
vis_dim: (1, grapheme_count),
} }
} }
@ -73,28 +65,26 @@ impl BufferNode {
} }
fn update_stats<T: LineFormatter>(&mut self, f: &T) { fn update_stats(&mut self) {
self.update_height(); self.update_height();
match self.data { match self.data {
BufferNodeData::Leaf(ref line) => { BufferNodeData::Leaf(ref line) => {
self.grapheme_count = line.grapheme_count(); self.grapheme_count = line.grapheme_count();
self.line_count = 1; self.line_count = 1;
self.vis_dim = f.dimensions(line);
}, },
BufferNodeData::Branch(ref left, ref right) => { BufferNodeData::Branch(ref left, ref right) => {
self.grapheme_count = left.grapheme_count + right.grapheme_count; self.grapheme_count = left.grapheme_count + right.grapheme_count;
self.line_count = left.line_count + right.line_count; self.line_count = left.line_count + right.line_count;
self.vis_dim = (left.vis_dim.0 + right.vis_dim.0, max(left.vis_dim.1, right.vis_dim.1));
} }
} }
} }
/// Rotates the tree under the node left /// Rotates the tree under the node left
fn rotate_left<T: LineFormatter>(&mut self, f: &T) { fn rotate_left(&mut self) {
let mut temp = BufferNode::new(f); let mut temp = BufferNode::new();
if let BufferNodeData::Branch(_, ref mut right) = self.data { if let BufferNodeData::Branch(_, ref mut right) = self.data {
mem::swap(&mut temp, &mut (**right)); mem::swap(&mut temp, &mut (**right));
@ -112,17 +102,17 @@ impl BufferNode {
if let BufferNodeData::Branch(ref mut left, _) = temp.data { if let BufferNodeData::Branch(ref mut left, _) = temp.data {
mem::swap(&mut (**left), self); mem::swap(&mut (**left), self);
left.update_stats(f); left.update_stats();
} }
mem::swap(&mut temp, self); mem::swap(&mut temp, self);
self.update_stats(f); self.update_stats();
} }
/// Rotates the tree under the node right /// Rotates the tree under the node right
fn rotate_right<T: LineFormatter>(&mut self, f: &T) { fn rotate_right(&mut self) {
let mut temp = BufferNode::new(f); let mut temp = BufferNode::new();
if let BufferNodeData::Branch(ref mut left, _) = self.data { if let BufferNodeData::Branch(ref mut left, _) = self.data {
mem::swap(&mut temp, &mut (**left)); mem::swap(&mut temp, &mut (**left));
@ -140,16 +130,16 @@ impl BufferNode {
if let BufferNodeData::Branch(_, ref mut right) = temp.data { if let BufferNodeData::Branch(_, ref mut right) = temp.data {
mem::swap(&mut (**right), self); mem::swap(&mut (**right), self);
right.update_stats(f); right.update_stats();
} }
mem::swap(&mut temp, self); mem::swap(&mut temp, self);
self.update_stats(f); self.update_stats();
} }
/// Rebalances the tree under the node /// Rebalances the tree under the node
fn rebalance<T: LineFormatter>(&mut self, f: &T) { fn rebalance(&mut self) {
loop { loop {
let mut rot: isize; let mut rot: isize;
@ -166,7 +156,7 @@ impl BufferNode {
} }
if child_rot { if child_rot {
left.rotate_left(f); left.rotate_left();
} }
rot = 1; rot = 1;
@ -181,7 +171,7 @@ impl BufferNode {
} }
if child_rot { if child_rot {
right.rotate_right(f); right.rotate_right();
} }
rot = -1; rot = -1;
@ -197,25 +187,10 @@ impl BufferNode {
} }
if rot == 1 { if rot == 1 {
self.rotate_right(f); self.rotate_right();
} }
else if rot == -1 { else if rot == -1 {
self.rotate_left(f); self.rotate_left();
}
}
}
pub fn reformat_recursive<T: LineFormatter>(&mut self, f: &T) {
match self.data {
BufferNodeData::Branch(ref mut left, ref mut right) => {
left.reformat_recursive(f);
right.reformat_recursive(f);
self.vis_dim = ((left.vis_dim.0 + right.vis_dim.0), max(left.vis_dim.1, right.vis_dim.1));
},
BufferNodeData::Leaf(ref line) => {
self.vis_dim = f.dimensions(line);
} }
} }
} }
@ -311,66 +286,8 @@ impl BufferNode {
} }
pub fn index_to_v2d_recursive<T: LineFormatter>(&self, f: &T, index: usize) -> (usize, usize) {
match self.data {
BufferNodeData::Leaf(ref line) => {
return f.index_to_v2d(line, index);
},
BufferNodeData::Branch(ref left, ref right) => {
if index < left.grapheme_count {
return left.index_to_v2d_recursive(f, index);
}
else {
let (y, x) = right.index_to_v2d_recursive(f, (index - left.grapheme_count));
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) => {
let mut r = f.v2d_to_index(line, pos, rounding);
// TODO: is this the right thing to do? The idea is that
// the non-leaf branch code should put us in the right leaf
// anyway, and returning an index equal to the leaf's
// grapheme count is putting it on the next line instead of
// this one.
if r == self.grapheme_count && self.grapheme_count > 0 {
r -= 1;
}
return r;
},
BufferNodeData::Branch(ref left, ref right) => {
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;
}
}
}
}
/// Insert 'text' at grapheme position 'pos'. /// Insert 'text' at grapheme position 'pos'.
pub fn insert_text<T: LineFormatter>(&mut self, f: &T, text: &str, pos: usize) { pub fn insert_text(&mut self, text: &str, pos: usize) {
// Byte indices // Byte indices
let mut b1: usize = 0; let mut b1: usize = 0;
let mut b2: usize = 0; let mut b2: usize = 0;
@ -383,14 +300,14 @@ impl BufferNode {
for grapheme in text.grapheme_indices(true) { for grapheme in text.grapheme_indices(true) {
if is_line_ending(grapheme.1) { if is_line_ending(grapheme.1) {
if g1 < g2 { if g1 < g2 {
self.insert_text_recursive(f, &text[b1..b2], pos + g1); self.insert_text_recursive(&text[b1..b2], pos + g1);
} }
g1 = g2; g1 = g2;
b2 += grapheme.1.len(); b2 += grapheme.1.len();
g2 += 1; g2 += 1;
self.insert_line_break_recursive(f, str_to_line_ending(grapheme.1), pos + g1); self.insert_line_break_recursive(str_to_line_ending(grapheme.1), pos + g1);
b1 = b2; b1 = b2;
g1 = g2; g1 = g2;
@ -402,22 +319,22 @@ impl BufferNode {
} }
if g1 < g2 { if g1 < g2 {
self.insert_text_recursive(f, &text[b1..b2], pos + g1); self.insert_text_recursive(&text[b1..b2], pos + g1);
} }
} }
/// Inserts the given text string at the given grapheme position. /// Inserts the given text string at the given grapheme position.
/// Note: this assumes the given text has no newline graphemes. /// Note: this assumes the given text has no newline graphemes.
pub fn insert_text_recursive<T: LineFormatter>(&mut self, f: &T, text: &str, pos: usize) { pub fn insert_text_recursive(&mut self, text: &str, pos: usize) {
match self.data { match self.data {
// Find node for text to be inserted into // Find node for text to be inserted into
BufferNodeData::Branch(ref mut left, ref mut right) => { BufferNodeData::Branch(ref mut left, ref mut right) => {
if pos < left.grapheme_count { if pos < left.grapheme_count {
left.insert_text_recursive(f, text, pos); left.insert_text_recursive(text, pos);
} }
else { else {
right.insert_text_recursive(f, text, pos - left.grapheme_count); right.insert_text_recursive(text, pos - left.grapheme_count);
} }
}, },
@ -428,12 +345,12 @@ impl BufferNode {
}, },
} }
self.update_stats(f); self.update_stats();
} }
/// Inserts a line break at the given grapheme position /// Inserts a line break at the given grapheme position
pub fn insert_line_break_recursive<T: LineFormatter>(&mut self, f: &T, ending: LineEnding, pos: usize) { pub fn insert_line_break_recursive(&mut self, ending: LineEnding, pos: usize) {
if ending == LineEnding::None { if ending == LineEnding::None {
return; return;
} }
@ -445,10 +362,10 @@ impl BufferNode {
// Find node for the line break to be inserted into // Find node for the line break to be inserted into
BufferNodeData::Branch(ref mut left, ref mut right) => { BufferNodeData::Branch(ref mut left, ref mut right) => {
if pos < left.grapheme_count { if pos < left.grapheme_count {
left.insert_line_break_recursive(f, ending, pos); left.insert_line_break_recursive(ending, pos);
} }
else { else {
right.insert_line_break_recursive(f, ending, pos - left.grapheme_count); right.insert_line_break_recursive(ending, pos - left.grapheme_count);
} }
do_split = false; do_split = false;
}, },
@ -464,16 +381,16 @@ impl BufferNode {
if do_split { if do_split {
// Insert line break // Insert line break
let new_line = old_line.split(ending, pos); let new_line = old_line.split(ending, pos);
let new_node_a = Box::new(BufferNode::new_from_line(f, old_line)); let new_node_a = Box::new(BufferNode::new_from_line(old_line));
let new_node_b = Box::new(BufferNode::new_from_line(f, new_line)); let new_node_b = Box::new(BufferNode::new_from_line(new_line));
self.data = BufferNodeData::Branch(new_node_a, new_node_b); self.data = BufferNodeData::Branch(new_node_a, new_node_b);
self.update_stats(f); self.update_stats();
} }
else { else {
self.update_stats(f); self.update_stats();
self.rebalance(f); self.rebalance();
} }
} }
@ -481,8 +398,8 @@ impl BufferNode {
/// Removes text between grapheme positions pos_a and pos_b. /// Removes text between grapheme positions pos_a and pos_b.
/// Returns true if a dangling left side remains from the removal. /// Returns true if a dangling left side remains from the removal.
/// Returns false otherwise. /// Returns false otherwise.
pub fn remove_text_recursive<T: LineFormatter>(&mut self, f: &T, pos_a: usize, pos_b: usize, is_last: bool) -> bool { pub fn remove_text_recursive(&mut self, pos_a: usize, pos_b: usize, is_last: bool) -> bool {
let mut temp_node = BufferNode::new(f); let mut temp_node = BufferNode::new();
let mut total_side_removal = false; let mut total_side_removal = false;
let mut dangling_line = false; let mut dangling_line = false;
let mut do_merge_fix = false; let mut do_merge_fix = false;
@ -500,7 +417,7 @@ impl BufferNode {
if pos_b > left.grapheme_count { if pos_b > left.grapheme_count {
let a = 0; let a = 0;
let b = pos_b - left.grapheme_count; let b = pos_b - left.grapheme_count;
right.remove_text_recursive(f, a, b, is_last); right.remove_text_recursive(a, b, is_last);
} }
total_side_removal = true; total_side_removal = true;
@ -511,7 +428,7 @@ impl BufferNode {
if pos_a < left.grapheme_count { if pos_a < left.grapheme_count {
let a = pos_a; let a = pos_a;
let b = left.grapheme_count; let b = left.grapheme_count;
dangling_line = left.remove_text_recursive(f, a, b, false); dangling_line = left.remove_text_recursive(a, b, false);
} }
if is_last && !dangling_line { if is_last && !dangling_line {
@ -532,14 +449,14 @@ impl BufferNode {
if pos_b > left.grapheme_count { if pos_b > left.grapheme_count {
let a = if pos_a > left.grapheme_count {pos_a - left.grapheme_count} else {0}; let a = if pos_a > left.grapheme_count {pos_a - left.grapheme_count} else {0};
let b = pos_b - left.grapheme_count; let b = pos_b - left.grapheme_count;
dangling_line = right.remove_text_recursive(f, a, b, is_last) && !is_last; dangling_line = right.remove_text_recursive(a, b, is_last) && !is_last;
} }
// Left side // Left side
if pos_a < left.grapheme_count { if pos_a < left.grapheme_count {
let a = pos_a; let a = pos_a;
let b = min(pos_b, left.grapheme_count); let b = min(pos_b, left.grapheme_count);
do_merge_fix = left.remove_text_recursive(f, a, b, false); do_merge_fix = left.remove_text_recursive(a, b, false);
merge_line_number = left.line_count - 1; merge_line_number = left.line_count - 1;
} }
} }
@ -560,7 +477,7 @@ impl BufferNode {
// Do the merge fix if necessary // Do the merge fix if necessary
if do_merge_fix { if do_merge_fix {
self.merge_line_with_next_recursive(f, merge_line_number, None); self.merge_line_with_next_recursive(merge_line_number, None);
} }
// If one of the sides was completely removed, replace self with the // If one of the sides was completely removed, replace self with the
// remaining side. // remaining side.
@ -568,54 +485,54 @@ impl BufferNode {
mem::swap(&mut temp_node, self); mem::swap(&mut temp_node, self);
} }
self.update_stats(f); self.update_stats();
self.rebalance(f); self.rebalance();
return dangling_line; return dangling_line;
} }
pub fn append_line_unchecked_recursive<T: LineFormatter>(&mut self, f: &T, line: Line) { pub fn append_line_unchecked_recursive(&mut self, line: Line) {
let mut other_line = Line::new(); let mut other_line = Line::new();
if let BufferNodeData::Branch(_, ref mut right) = self.data { if let BufferNodeData::Branch(_, ref mut right) = self.data {
right.append_line_unchecked_recursive(f, line); right.append_line_unchecked_recursive(line);
} }
else { else {
if let BufferNodeData::Leaf(ref mut this_line) = self.data { if let BufferNodeData::Leaf(ref mut this_line) = self.data {
mem::swap(this_line, &mut other_line); mem::swap(this_line, &mut other_line);
} }
let new_node_a = Box::new(BufferNode::new_from_line(f, other_line)); let new_node_a = Box::new(BufferNode::new_from_line(other_line));
let new_node_b = Box::new(BufferNode::new_from_line(f, line)); let new_node_b = Box::new(BufferNode::new_from_line(line));
self.data = BufferNodeData::Branch(new_node_a, new_node_b); self.data = BufferNodeData::Branch(new_node_a, new_node_b);
} }
self.update_stats(f); self.update_stats();
self.rebalance(f); self.rebalance();
} }
pub fn append_leaf_node_unchecked_recursive<T: LineFormatter>(&mut self, f: &T, node: BufferNode) { pub fn append_leaf_node_unchecked_recursive(&mut self, node: BufferNode) {
if let BufferNodeData::Branch(_, ref mut right) = self.data { if let BufferNodeData::Branch(_, ref mut right) = self.data {
right.append_leaf_node_unchecked_recursive(f, node); right.append_leaf_node_unchecked_recursive(node);
} }
else { else {
let mut new_left_node = BufferNode::new(f); let mut new_left_node = BufferNode::new();
mem::swap(self, &mut new_left_node); mem::swap(self, &mut new_left_node);
self.data = BufferNodeData::Branch(Box::new(new_left_node), Box::new(node)); self.data = BufferNodeData::Branch(Box::new(new_left_node), Box::new(node));
} }
self.update_stats(f); self.update_stats();
self.rebalance(f); self.rebalance();
} }
/// Removes lines in line number range [line_a, line_b) /// Removes lines in line number range [line_a, line_b)
pub fn remove_lines_recursive<T: LineFormatter>(&mut self, f: &T, line_a: usize, line_b: usize) { pub fn remove_lines_recursive(&mut self, line_a: usize, line_b: usize) {
let mut remove_left = false; let mut remove_left = false;
let mut remove_right = false; let mut remove_right = false;
let mut temp_node = BufferNode::new(f); let mut temp_node = BufferNode::new();
if let BufferNodeData::Branch(ref mut left, ref mut right) = self.data { if let BufferNodeData::Branch(ref mut left, ref mut right) = self.data {
// Right node completely removed // Right node completely removed
@ -626,7 +543,7 @@ impl BufferNode {
else if line_b > left.line_count { else if line_b > left.line_count {
let a = if line_a > left.line_count {line_a - left.line_count} else {0}; let a = if line_a > left.line_count {line_a - left.line_count} else {0};
let b = line_b - left.line_count; let b = line_b - left.line_count;
right.remove_lines_recursive(f, a, b); right.remove_lines_recursive(a, b);
} }
// Left node completely removed // Left node completely removed
@ -637,7 +554,7 @@ impl BufferNode {
else if line_a < left.line_count { else if line_a < left.line_count {
let a = line_a; let a = line_a;
let b = min(left.line_count, line_b); let b = min(left.line_count, line_b);
left.remove_lines_recursive(f, a, b); left.remove_lines_recursive(a, b);
} }
// Set up for node removal // Set up for node removal
@ -660,17 +577,17 @@ impl BufferNode {
mem::swap(&mut temp_node, self); mem::swap(&mut temp_node, self);
} }
self.update_stats(f); self.update_stats();
self.rebalance(f); self.rebalance();
} }
pub fn merge_line_with_next_recursive<T: LineFormatter>(&mut self, f: &T, line_number: usize, fetched_line: Option<&Line>) { pub fn merge_line_with_next_recursive(&mut self, line_number: usize, fetched_line: Option<&Line>) {
match fetched_line { match fetched_line {
None => { None => {
let line: Option<Line> = self.pull_out_line_recursive(f, line_number + 1); let line: Option<Line> = self.pull_out_line_recursive(line_number + 1);
if let Some(ref l) = line { if let Some(ref l) = line {
self.merge_line_with_next_recursive(f, line_number, Some(l)); self.merge_line_with_next_recursive(line_number, Some(l));
} }
}, },
@ -678,10 +595,10 @@ impl BufferNode {
match self.data { match self.data {
BufferNodeData::Branch(ref mut left, ref mut right) => { BufferNodeData::Branch(ref mut left, ref mut right) => {
if line_number < left.line_count { if line_number < left.line_count {
left.merge_line_with_next_recursive(f, line_number, Some(line)); left.merge_line_with_next_recursive(line_number, Some(line));
} }
else { else {
right.merge_line_with_next_recursive(f, line_number - left.line_count, Some(line)); right.merge_line_with_next_recursive(line_number - left.line_count, Some(line));
} }
}, },
@ -693,15 +610,15 @@ impl BufferNode {
} }
} }
self.update_stats(f); self.update_stats();
self.rebalance(f); self.rebalance();
} }
/// Removes a single line out of the text and returns it. /// Removes a single line out of the text and returns it.
pub fn pull_out_line_recursive<T: LineFormatter>(&mut self, f: &T, line_number: usize) -> Option<Line> { pub fn pull_out_line_recursive(&mut self, line_number: usize) -> Option<Line> {
let mut pulled_line = Line::new(); let mut pulled_line = Line::new();
let mut temp_node = BufferNode::new(f); let mut temp_node = BufferNode::new();
let mut side_removal = false; let mut side_removal = false;
match self.data { match self.data {
@ -713,7 +630,7 @@ impl BufferNode {
side_removal = true; side_removal = true;
} }
else { else {
pulled_line = left.pull_out_line_recursive(f, line_number).unwrap(); pulled_line = left.pull_out_line_recursive(line_number).unwrap();
} }
} }
else if line_number < self.line_count { else if line_number < self.line_count {
@ -723,7 +640,7 @@ impl BufferNode {
side_removal = true; side_removal = true;
} }
else { else {
pulled_line = right.pull_out_line_recursive(f, line_number - left.line_count).unwrap(); pulled_line = right.pull_out_line_recursive(line_number - left.line_count).unwrap();
} }
} }
else { else {
@ -741,8 +658,8 @@ impl BufferNode {
mem::swap(&mut temp_node, self); mem::swap(&mut temp_node, self);
} }
self.update_stats(f); self.update_stats();
self.rebalance(f); self.rebalance();
return Some(pulled_line); return Some(pulled_line);
} }
@ -750,10 +667,10 @@ impl BufferNode {
/// Ensures that the last line in the node tree has no /// Ensures that the last line in the node tree has no
/// ending line break. /// ending line break.
pub fn set_last_line_ending_recursive<T: LineFormatter>(&mut self, f: &T) { pub fn set_last_line_ending_recursive(&mut self) {
match self.data { match self.data {
BufferNodeData::Branch(_, ref mut right) => { BufferNodeData::Branch(_, ref mut right) => {
right.set_last_line_ending_recursive(f); right.set_last_line_ending_recursive();
}, },
BufferNodeData::Leaf(ref mut line) => { BufferNodeData::Leaf(ref mut line) => {
@ -761,7 +678,7 @@ impl BufferNode {
}, },
} }
self.update_stats(f); self.update_stats();
} }
@ -1015,18 +932,16 @@ impl<'a> Iterator for BufferNodeLineIter<'a> {
mod tests { mod tests {
use super::BufferNode; use super::BufferNode;
use super::super::line::LineEnding; use super::super::line::LineEnding;
use super::super::line_formatter::TestLineFormatter;
#[test] #[test]
fn merge_line_with_next_recursive_1() { fn merge_line_with_next_recursive_1() {
let f = TestLineFormatter::new(); let mut node = BufferNode::new();
let mut node = BufferNode::new(&f); node.insert_text("Hi\n there!", 0);
node.insert_text(&f, "Hi\n there!", 0);
assert!(node.grapheme_count == 10); assert!(node.grapheme_count == 10);
assert!(node.line_count == 2); assert!(node.line_count == 2);
node.merge_line_with_next_recursive(&f, 0, None); node.merge_line_with_next_recursive(0, None);
let mut iter = node.grapheme_iter(); let mut iter = node.grapheme_iter();
@ -1047,14 +962,13 @@ mod tests {
#[test] #[test]
fn merge_line_with_next_recursive_2() { fn merge_line_with_next_recursive_2() {
let f = TestLineFormatter::new(); let mut node = BufferNode::new();
let mut node = BufferNode::new(&f); node.insert_text("Hi\n there\n people \nof the\n world!", 0);
node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0);
assert!(node.grapheme_count == 33); assert!(node.grapheme_count == 33);
assert!(node.line_count == 5); assert!(node.line_count == 5);
node.merge_line_with_next_recursive(&f, 2, None); node.merge_line_with_next_recursive(2, None);
let mut iter = node.grapheme_iter(); let mut iter = node.grapheme_iter();
@ -1098,14 +1012,13 @@ mod tests {
#[test] #[test]
fn merge_line_with_next_recursive_3() { fn merge_line_with_next_recursive_3() {
let f = TestLineFormatter::new(); let mut node = BufferNode::new();
let mut node = BufferNode::new(&f); node.insert_text("Hi\n there\n people \nof the\n world!", 0);
node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0);
assert!(node.grapheme_count == 33); assert!(node.grapheme_count == 33);
assert!(node.line_count == 5); assert!(node.line_count == 5);
node.merge_line_with_next_recursive(&f, 0, None); node.merge_line_with_next_recursive(0, None);
let mut iter = node.grapheme_iter(); let mut iter = node.grapheme_iter();
@ -1149,14 +1062,13 @@ mod tests {
#[test] #[test]
fn pull_out_line_recursive_1() { fn pull_out_line_recursive_1() {
let f = TestLineFormatter::new(); let mut node = BufferNode::new();
let mut node = BufferNode::new(&f); node.insert_text("Hi\n there\n people \nof the\n world!", 0);
node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0);
assert!(node.grapheme_count == 33); assert!(node.grapheme_count == 33);
assert!(node.line_count == 5); assert!(node.line_count == 5);
let line = node.pull_out_line_recursive(&f, 0).unwrap(); let line = node.pull_out_line_recursive(0).unwrap();
assert!(line.as_str() == "Hi"); assert!(line.as_str() == "Hi");
assert!(line.ending == LineEnding::LF); assert!(line.ending == LineEnding::LF);
@ -1200,14 +1112,13 @@ mod tests {
#[test] #[test]
fn pull_out_line_recursive_2() { fn pull_out_line_recursive_2() {
let f = TestLineFormatter::new(); let mut node = BufferNode::new();
let mut node = BufferNode::new(&f); node.insert_text("Hi\n there\n people \nof the\n world!", 0);
node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0);
assert!(node.grapheme_count == 33); assert!(node.grapheme_count == 33);
assert!(node.line_count == 5); assert!(node.line_count == 5);
let line = node.pull_out_line_recursive(&f, 2).unwrap(); let line = node.pull_out_line_recursive(2).unwrap();
assert!(line.as_str() == " people "); assert!(line.as_str() == " people ");
assert!(line.ending == LineEnding::LF); assert!(line.ending == LineEnding::LF);
@ -1245,14 +1156,13 @@ mod tests {
#[test] #[test]
fn pull_out_line_recursive_3() { fn pull_out_line_recursive_3() {
let f = TestLineFormatter::new(); let mut node = BufferNode::new();
let mut node = BufferNode::new(&f); node.insert_text("Hi\n there\n people \nof the\n world!", 0);
node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0);
assert!(node.grapheme_count == 33); assert!(node.grapheme_count == 33);
assert!(node.line_count == 5); assert!(node.line_count == 5);
let line = node.pull_out_line_recursive(&f, 4).unwrap(); let line = node.pull_out_line_recursive(4).unwrap();
assert!(line.as_str() == " world!"); assert!(line.as_str() == " world!");
assert!(line.ending == LineEnding::None); assert!(line.ending == LineEnding::None);

View File

@ -5,7 +5,7 @@ use std::ops::{Index, IndexMut};
use std::cmp::Ordering; use std::cmp::Ordering;
use buffer::Buffer; use buffer::Buffer;
use buffer::line_formatter::LineFormatter; use super::formatter::LineFormatter;
/// A text cursor. Also represents selections when range.0 != range.1. /// A text cursor. Also represents selections when range.0 != range.1.
/// ///
@ -27,9 +27,10 @@ impl Cursor {
} }
} }
pub fn update_vis_start<T: LineFormatter>(&mut self, buf: &Buffer<T>) { pub fn update_vis_start<T: LineFormatter>(&mut self, buf: &Buffer, f: &T) {
let (_, h) = buf.index_to_v2d(self.range.0); // TODO
self.vis_start = h; //let (_, h) = buf.index_to_v2d(self.range.0);
//self.vis_start = h;
} }
} }

View File

@ -2,19 +2,21 @@
use buffer::Buffer; use buffer::Buffer;
use buffer::line::LineEnding; use buffer::line::LineEnding;
use buffer::line_formatter::LineFormatter; use self::formatter::LineFormatter;
use buffer::line_formatter::RoundingBehavior::*; use self::formatter::RoundingBehavior::*;
use std::path::Path; use std::path::Path;
use std::cmp::{min, max}; use std::cmp::{min, max};
use files::{save_buffer_to_file}; use files::{save_buffer_to_file};
use string_utils::grapheme_count; use string_utils::grapheme_count;
use self::cursor::CursorSet; use self::cursor::CursorSet;
pub mod formatter;
mod cursor; mod cursor;
pub struct Editor<T: LineFormatter> { pub struct Editor<T: LineFormatter> {
pub buffer: Buffer<T>, pub buffer: Buffer,
pub formatter: T,
pub file_path: Path, pub file_path: Path,
pub line_ending_type: LineEnding, pub line_ending_type: LineEnding,
pub soft_tabs: bool, pub soft_tabs: bool,
@ -34,7 +36,8 @@ impl<T: LineFormatter> Editor<T> {
/// Create a new blank editor /// Create a new blank editor
pub fn new(formatter: T) -> Editor<T> { pub fn new(formatter: T) -> Editor<T> {
Editor { Editor {
buffer: Buffer::new(formatter), buffer: Buffer::new(),
formatter: formatter,
file_path: Path::new(""), file_path: Path::new(""),
line_ending_type: LineEnding::LF, line_ending_type: LineEnding::LF,
soft_tabs: false, soft_tabs: false,
@ -47,8 +50,7 @@ impl<T: LineFormatter> Editor<T> {
} }
pub fn new_from_file(formatter: T, path: &Path) -> Editor<T> { pub fn new_from_file(formatter: T, path: &Path) -> Editor<T> {
//let buf = match load_file_to_buffer(path, formatter) { let buf = match Buffer::new_from_file(path) {
let buf = match Buffer::new_from_file(formatter, path) {
Ok(b) => {b}, Ok(b) => {b},
// TODO: handle un-openable file better // TODO: handle un-openable file better
_ => panic!("Could not open file!"), _ => panic!("Could not open file!"),
@ -56,6 +58,7 @@ impl<T: LineFormatter> Editor<T> {
let mut ed = Editor { let mut ed = Editor {
buffer: buf, buffer: buf,
formatter: formatter,
file_path: path.clone(), file_path: path.clone(),
line_ending_type: LineEnding::LF, line_ending_type: LineEnding::LF,
soft_tabs: false, soft_tabs: false,
@ -70,7 +73,7 @@ impl<T: LineFormatter> Editor<T> {
//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.formatter));
//ed.cursors.add_cursor(cur); //ed.cursors.add_cursor(cur);
ed.auto_detect_line_ending(); ed.auto_detect_line_ending();
@ -259,7 +262,7 @@ impl<T: LineFormatter> Editor<T> {
self.cursors.truncate(1); self.cursors.truncate(1);
self.cursors[0].range.0 = pos; self.cursors[0].range.0 = pos;
self.cursors[0].range.1 = pos; self.cursors[0].range.1 = pos;
self.cursors[0].update_vis_start(&(self.buffer)); self.cursors[0].update_vis_start(&(self.buffer), &(self.formatter));
self.move_view_to_cursor(); self.move_view_to_cursor();
@ -276,7 +279,7 @@ impl<T: LineFormatter> Editor<T> {
self.cursors.truncate(1); self.cursors.truncate(1);
self.cursors[0].range.0 = pos; self.cursors[0].range.0 = pos;
self.cursors[0].range.1 = pos; self.cursors[0].range.1 = pos;
self.cursors[0].update_vis_start(&(self.buffer)); self.cursors[0].update_vis_start(&(self.buffer), &(self.formatter));
self.move_view_to_cursor(); self.move_view_to_cursor();
@ -292,23 +295,25 @@ impl<T: LineFormatter> Editor<T> {
// TODO: handle multiple cursors properly. Should only move if // TODO: handle multiple cursors properly. Should only move if
// there are no cursors currently in view, and should jump to // there are no cursors currently in view, and should jump to
// the closest cursor. // the closest cursor.
let (v, h) = self.buffer.index_to_v2d(self.cursors[0].range.0);
// Horizontal // TODO: update to new formatting code
if h < self.view_pos.1 { //let (v, h) = self.buffer.index_to_v2d(self.cursors[0].range.0);
self.view_pos.1 = h; //
} //// Horizontal
else if h >= (self.view_pos.1 + self.view_dim.1) { //if h < self.view_pos.1 {
self.view_pos.1 = 1 + h - self.view_dim.1; // self.view_pos.1 = h;
} //}
//else if h >= (self.view_pos.1 + self.view_dim.1) {
// Vertical // self.view_pos.1 = 1 + h - self.view_dim.1;
if v < self.view_pos.0 { //}
self.view_pos.0 = v; //
} //// Vertical
else if v >= (self.view_pos.0 + self.view_dim.0) { //if v < self.view_pos.0 {
self.view_pos.0 = 1 + v - self.view_dim.0; // self.view_pos.0 = v;
} //}
//else if v >= (self.view_pos.0 + self.view_dim.0) {
// self.view_pos.0 = 1 + v - self.view_dim.0;
//}
} }
pub fn insert_text_at_cursor(&mut self, text: &str) { pub fn insert_text_at_cursor(&mut self, text: &str) {
@ -325,7 +330,7 @@ impl<T: LineFormatter> Editor<T> {
// Move cursor // Move cursor
c.range.0 += str_len + offset; c.range.0 += str_len + offset;
c.range.1 += str_len + offset; c.range.1 += str_len + offset;
c.update_vis_start(&(self.buffer)); c.update_vis_start(&(self.buffer), &(self.formatter));
// Update offset // Update offset
offset += str_len; offset += str_len;
@ -336,43 +341,45 @@ impl<T: LineFormatter> Editor<T> {
} }
pub fn insert_tab_at_cursor(&mut self) { pub fn insert_tab_at_cursor(&mut self) {
self.cursors.make_consistent(); // TODO: update to new formatting code
if self.soft_tabs { //self.cursors.make_consistent();
let mut offset = 0; //
//if self.soft_tabs {
for c in self.cursors.iter_mut() { // let mut offset = 0;
// Update cursor with offset //
c.range.0 += offset; // for c in self.cursors.iter_mut() {
c.range.1 += offset; // // Update cursor with offset
// c.range.0 += offset;
// Figure out how many spaces to insert // c.range.1 += offset;
let (_, vis_pos) = self.buffer.index_to_v2d(c.range.0); //
// TODO: handle tab settings // // Figure out how many spaces to insert
let next_tab_stop = ((vis_pos / self.soft_tab_width as usize) + 1) * self.soft_tab_width as usize; // let (_, vis_pos) = self.buffer.index_to_v2d(c.range.0);
let space_count = min(next_tab_stop - vis_pos, 8); // // TODO: handle tab settings
// let next_tab_stop = ((vis_pos / self.soft_tab_width as usize) + 1) * self.soft_tab_width as usize;
// let space_count = min(next_tab_stop - vis_pos, 8);
// Insert spaces //
let space_strs = ["", " ", " ", " ", " ", " ", " ", " ", " "]; //
self.buffer.insert_text(space_strs[space_count], c.range.0); // // Insert spaces
self.dirty = true; // let space_strs = ["", " ", " ", " ", " ", " ", " ", " ", " "];
// self.buffer.insert_text(space_strs[space_count], c.range.0);
// Move cursor // self.dirty = true;
c.range.0 += space_count; //
c.range.1 += space_count; // // Move cursor
c.update_vis_start(&(self.buffer)); // c.range.0 += space_count;
// c.range.1 += space_count;
// Update offset // c.update_vis_start(&(self.buffer), &(self.formatter));
offset += space_count; //
} // // Update offset
// offset += space_count;
// Adjust view // }
self.move_view_to_cursor(); //
} // // Adjust view
else { // self.move_view_to_cursor();
self.insert_text_at_cursor("\t"); //}
} //else {
// self.insert_text_at_cursor("\t");
//}
} }
pub fn backspace_at_cursor(&mut self) { pub fn backspace_at_cursor(&mut self) {
@ -409,7 +416,7 @@ impl<T: LineFormatter> Editor<T> {
// Move cursor // Move cursor
c.range.0 -= len; c.range.0 -= len;
c.range.1 -= len; c.range.1 -= len;
c.update_vis_start(&(self.buffer)); c.update_vis_start(&(self.buffer), &(self.formatter));
// Update offset // Update offset
offset += len; offset += len;
@ -444,7 +451,7 @@ impl<T: LineFormatter> Editor<T> {
self.dirty = true; self.dirty = true;
// Move cursor // Move cursor
c.update_vis_start(&(self.buffer)); c.update_vis_start(&(self.buffer), &(self.formatter));
// Update offset // Update offset
offset += len; offset += len;
@ -480,7 +487,7 @@ impl<T: LineFormatter> Editor<T> {
offset += len; offset += len;
} }
c.update_vis_start(&(self.buffer)); c.update_vis_start(&(self.buffer), &(self.formatter));
} }
self.cursors.make_consistent(); self.cursors.make_consistent();
@ -493,7 +500,7 @@ impl<T: LineFormatter> Editor<T> {
self.cursors = CursorSet::new(); self.cursors = CursorSet::new();
self.cursors[0].range = (0, 0); self.cursors[0].range = (0, 0);
self.cursors[0].update_vis_start(&(self.buffer)); self.cursors[0].update_vis_start(&(self.buffer), &(self.formatter));
// Adjust view // Adjust view
self.move_view_to_cursor(); self.move_view_to_cursor();
@ -504,7 +511,7 @@ impl<T: LineFormatter> Editor<T> {
self.cursors = CursorSet::new(); self.cursors = CursorSet::new();
self.cursors[0].range = (end, end); self.cursors[0].range = (end, end);
self.cursors[0].update_vis_start(&(self.buffer)); self.cursors[0].update_vis_start(&(self.buffer), &(self.formatter));
// Adjust view // Adjust view
self.move_view_to_cursor(); self.move_view_to_cursor();
@ -520,7 +527,7 @@ impl<T: LineFormatter> Editor<T> {
} }
c.range.1 = c.range.0; c.range.1 = c.range.0;
c.update_vis_start(&(self.buffer)); c.update_vis_start(&(self.buffer), &(self.formatter));
} }
// Adjust view // Adjust view
@ -536,7 +543,7 @@ impl<T: LineFormatter> Editor<T> {
} }
c.range.0 = c.range.1; c.range.0 = c.range.1;
c.update_vis_start(&(self.buffer)); c.update_vis_start(&(self.buffer), &(self.formatter));
} }
// Adjust view // Adjust view
@ -544,93 +551,103 @@ impl<T: LineFormatter> Editor<T> {
} }
pub fn cursor_up(&mut self, n: usize) { pub fn cursor_up(&mut self, n: usize) {
for c in self.cursors.iter_mut() { // TODO: update to new formatting code
let vmove = n * self.buffer.formatter.single_line_height();
let (v, _) = self.buffer.index_to_v2d(c.range.0);
if vmove <= v { //for c in self.cursors.iter_mut() {
c.range.0 = self.buffer.v2d_to_index((v - vmove, c.vis_start), (Floor, Floor)); // let vmove = n * self.buffer.formatter.single_line_height();
c.range.1 = c.range.0; // let (v, _) = self.buffer.index_to_v2d(c.range.0);
} //
else { // if vmove <= v {
c.range = (0, 0); // c.range.0 = self.buffer.v2d_to_index((v - vmove, c.vis_start), (Floor, Floor));
c.update_vis_start(&(self.buffer)); // c.range.1 = c.range.0;
} // }
} // else {
// c.range = (0, 0);
// Adjust view // c.update_vis_start(&(self.buffer), &(self.formatter));
self.move_view_to_cursor(); // }
//}
//
//// Adjust view
//self.move_view_to_cursor();
} }
pub fn cursor_down(&mut self, n: usize) { pub fn cursor_down(&mut self, n: usize) {
for c in self.cursors.iter_mut() { // TODO: update to new formatting code
let vmove = n * self.buffer.formatter.single_line_height();
let (v, _) = self.buffer.index_to_v2d(c.range.0);
let (h, _) = self.buffer.dimensions();
if vmove < (h - v) { //for c in self.cursors.iter_mut() {
c.range.0 = self.buffer.v2d_to_index((v + vmove, c.vis_start), (Floor, Floor)); // let vmove = n * self.buffer.formatter.single_line_height();
c.range.1 = c.range.0; // let (v, _) = self.buffer.index_to_v2d(c.range.0);
} // let (h, _) = self.buffer.dimensions();
else { //
let end = self.buffer.grapheme_count(); // if vmove < (h - v) {
c.range = (end, end); // c.range.0 = self.buffer.v2d_to_index((v + vmove, c.vis_start), (Floor, Floor));
c.update_vis_start(&(self.buffer)); // c.range.1 = c.range.0;
} // }
} // else {
// let end = self.buffer.grapheme_count();
// Adjust view // c.range = (end, end);
self.move_view_to_cursor(); // c.update_vis_start(&(self.buffer), &(self.formatter));
// }
//}
//
//// Adjust view
//self.move_view_to_cursor();
} }
pub fn page_up(&mut self) { pub fn page_up(&mut self) {
let move_amount = self.view_dim.0 - max((self.view_dim.0 / 8), self.buffer.formatter.single_line_height()); // TODO: update to new formatting code
if self.view_pos.0 > 0 { //let move_amount = self.view_dim.0 - max((self.view_dim.0 / 8), self.buffer.formatter.single_line_height());
if self.view_pos.0 >= move_amount { //
self.view_pos.0 -= move_amount; //if self.view_pos.0 > 0 {
} // if self.view_pos.0 >= move_amount {
else { // self.view_pos.0 -= move_amount;
self.view_pos.0 = 0; // }
} // else {
} // self.view_pos.0 = 0;
// }
self.cursor_up(move_amount); //}
//
// Adjust view //self.cursor_up(move_amount);
self.move_view_to_cursor(); //
//// Adjust view
//self.move_view_to_cursor();
} }
pub fn page_down(&mut self) { pub fn page_down(&mut self) {
let nlc = self.buffer.line_count() - 1; // TODO: update to new formatting code
let move_amount = self.view_dim.0 - max((self.view_dim.0 / 8), self.buffer.formatter.single_line_height());
if self.view_pos.0 < nlc { //let nlc = self.buffer.line_count() - 1;
let max_move = nlc - self.view_pos.0; //let move_amount = self.view_dim.0 - max((self.view_dim.0 / 8), self.buffer.formatter.single_line_height());
//
if max_move >= move_amount { //if self.view_pos.0 < nlc {
self.view_pos.0 += move_amount; // let max_move = nlc - self.view_pos.0;
} //
else { // if max_move >= move_amount {
self.view_pos.0 += max_move; // self.view_pos.0 += move_amount;
} // }
// else {
} // self.view_pos.0 += max_move;
// }
self.cursor_down(move_amount); //
//}
// Adjust view //
self.move_view_to_cursor(); //self.cursor_down(move_amount);
//
//// Adjust view
//self.move_view_to_cursor();
} }
pub fn jump_to_line(&mut self, n: usize) { pub fn jump_to_line(&mut self, n: usize) {
let pos = self.buffer.line_col_to_index((n, 0)); // TODO: update to new formatting code
let (v, _) = self.buffer.index_to_v2d(pos);
self.cursors.truncate(1);
self.cursors[0].range.0 = self.buffer.v2d_to_index((v, self.cursors[0].vis_start), (Floor, Floor));
self.cursors[0].range.1 = self.cursors[0].range.0;
// Adjust view //let pos = self.buffer.line_col_to_index((n, 0));
self.move_view_to_cursor(); //let (v, _) = self.buffer.index_to_v2d(pos);
//self.cursors.truncate(1);
//self.cursors[0].range.0 = self.buffer.v2d_to_index((v, self.cursors[0].vis_start), (Floor, Floor));
//self.cursors[0].range.1 = self.cursors[0].range.0;
//
//// Adjust view
//self.move_view_to_cursor();
} }
} }

View File

@ -3,10 +3,9 @@ use std::old_io::fs::File;
use std::path::Path; use std::path::Path;
use buffer::line::{line_ending_to_str}; use buffer::line::{line_ending_to_str};
use buffer::line_formatter::LineFormatter;
use buffer::Buffer as TextBuffer; use buffer::Buffer as TextBuffer;
pub fn save_buffer_to_file<T: LineFormatter>(tb: &TextBuffer<T>, path: &Path) -> IoResult<()> { pub fn save_buffer_to_file(tb: &TextBuffer, path: &Path) -> IoResult<()> {
// TODO: make save atomic // TODO: make save atomic
let mut iter = tb.line_iter(); let mut iter = tb.line_iter();
let mut f = BufferedWriter::new(try!(File::create(path))); let mut f = BufferedWriter::new(try!(File::create(path)));

View File

@ -2,7 +2,7 @@ use std::cmp::max;
use string_utils::{is_line_ending}; use string_utils::{is_line_ending};
use buffer::line::{Line, LineGraphemeIter}; use buffer::line::{Line, LineGraphemeIter};
use buffer::line_formatter::{LineFormatter, RoundingBehavior}; use editor::formatter::{LineFormatter, RoundingBehavior};
//=================================================================== //===================================================================
// LineFormatter implementation for terminals/consoles. // LineFormatter implementation for terminals/consoles.

View File

@ -3,11 +3,11 @@
use rustbox; use rustbox;
use rustbox::Color; use rustbox::Color;
use editor::Editor; use editor::Editor;
use editor::formatter::{LineFormatter, RoundingBehavior};
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 buffer::line::{line_ending_to_str, LineEnding}; use buffer::line::{line_ending_to_str, LineEnding};
use buffer::line_formatter::{LineFormatter, RoundingBehavior};
use self::formatter::ConsoleLineFormatter; use self::formatter::ConsoleLineFormatter;
pub mod formatter; pub mod formatter;
@ -84,8 +84,7 @@ impl TermUI {
let mut resize: Option<(usize, usize)> = None; let mut resize: Option<(usize, usize)> = None;
self.editor.update_dim(self.height-1, self.width); self.editor.update_dim(self.height-1, self.width);
self.editor.buffer.formatter.wrap_width = self.width as usize; self.editor.formatter.wrap_width = self.width as usize;
self.editor.buffer.reformat();
loop { loop {
// Draw the editor to screen // Draw the editor to screen
@ -197,8 +196,7 @@ impl TermUI {
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-1, self.width);
self.editor.buffer.formatter.wrap_width = self.width; self.editor.formatter.wrap_width = self.width;
self.editor.buffer.reformat();
println!("Resized window!"); println!("Resized window!");
} }
resize = None; resize = None;
@ -354,101 +352,103 @@ 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 // TODO: update to new formatting code
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 screen_line = c1.0 as isize + vis_starting_line as isize; //// Calculate all the starting info
let screen_col = c1.1 as isize; //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 line_iter = editor.buffer.line_iter_at_index(starting_line); //let mut grapheme_index = editor.buffer.line_col_to_index((starting_line, 0));
//let (vis_starting_line, _) = editor.buffer.index_to_v2d(grapheme_index);
for line in line_iter { //
let mut g_iter = editor.buffer.formatter.vis_grapheme_iter(line); //let mut screen_line = c1.0 as isize + vis_starting_line as isize;
//let screen_col = c1.1 as isize;
// Loop through the graphemes of the line and print them to //
// the screen. //let mut line_iter = editor.buffer.line_iter_at_index(starting_line);
for (g, (pos_y, pos_x), width) in g_iter { //
// Calculate the cell coordinates at which to draw the grapheme //for line in line_iter {
let px = pos_x as isize + screen_col - editor.view_pos.1 as isize; // let mut g_iter = editor.buffer.formatter.vis_grapheme_iter(line);
let py = pos_y as isize + screen_line - editor.view_pos.0 as isize; //
// // Loop through the graphemes of the line and print them to
// If we're off the bottom, we're done // // the screen.
if py > c2.0 as isize { // for (g, (pos_y, pos_x), width) in g_iter {
return; // // 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;
// 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) { // // If we're off the bottom, we're done
// Check if the character is within a cursor // if py > c2.0 as isize {
let mut at_cursor = false; // return;
for c in editor.cursors.iter() { // }
if grapheme_index >= c.range.0 && grapheme_index <= c.range.1 { //
at_cursor = true; // // 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;
// Actually print the character // for c in editor.cursors.iter() {
if is_line_ending(g) { // if grapheme_index >= c.range.0 && grapheme_index <= c.range.1 {
if at_cursor { // at_cursor = true;
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " "); // }
} // }
} //
else if g == "\t" { // // Actually print the character
for i in 0..width { // if is_line_ending(g) {
let tpx = px as usize + i; // if at_cursor {
if tpx <= c2.1 { // self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " ");
self.rb.print(tpx as usize, py as usize, rustbox::RB_NORMAL, Color::White, Color::Black, " "); // }
} // }
} // else if g == "\t" {
// for i in 0..width {
if at_cursor { // let tpx = px as usize + i;
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " "); // if tpx <= c2.1 {
} // self.rb.print(tpx as usize, py as usize, rustbox::RB_NORMAL, Color::White, Color::Black, " ");
} // }
else { // }
if at_cursor { //
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, g); // if at_cursor {
} // self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " ");
else { // }
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::White, Color::Black, g); // }
} // else {
} // if at_cursor {
} // self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, g);
// }
grapheme_index += 1; // else {
} // self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::White, Color::Black, g);
// }
let (dim_y, _) = editor.buffer.formatter.dimensions(line); // }
screen_line += dim_y as isize; // }
} //
// grapheme_index += 1;
// }
//
// If we get here, it means we reached the end of the text buffer // let (dim_y, _) = editor.buffer.formatter.dimensions(line);
// without going off the bottom of the screen. So draw the cursor // screen_line += dim_y as isize;
// at the end if needed. //}
//
// Check if the character is within a cursor //
let mut at_cursor = false; //
for c in editor.cursors.iter() { //// If we get here, it means we reached the end of the text buffer
if grapheme_index >= c.range.0 && grapheme_index <= c.range.1 { //// without going off the bottom of the screen. So draw the cursor
at_cursor = true; //// at the end if needed.
} //
} //// Check if the character is within a cursor
//let mut at_cursor = false;
if at_cursor { //for c in editor.cursors.iter() {
// Calculate the cell coordinates at which to draw the cursor // if grapheme_index >= c.range.0 && grapheme_index <= c.range.1 {
let (pos_y, pos_x) = editor.buffer.index_to_v2d(grapheme_index); // at_cursor = true;
let px = pos_x as isize + c1.1 as isize - editor.view_pos.1 as isize; // }
let py = pos_y as isize + c1.0 as isize - editor.view_pos.0 as isize; //}
//
if (px >= c1.1 as isize) && (py >= c1.0 as isize) && (px <= c2.1 as isize) && (py <= c2.0 as isize) { //if at_cursor {
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " "); // // Calculate the cell coordinates at which to draw the cursor
} // let (pos_y, pos_x) = editor.buffer.index_to_v2d(grapheme_index);
} // let px = pos_x as isize + c1.1 as isize - editor.view_pos.1 as isize;
// let py = pos_y as isize + c1.0 as isize - editor.view_pos.0 as isize;
//
// if (px >= c1.1 as isize) && (py >= c1.0 as isize) && (px <= c2.1 as isize) && (py <= c2.0 as isize) {
// self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " ");
// }
//}
} }