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::undo_stack::{UndoStack};
use self::undo_stack::Operation::*;
use self::line_formatter::{LineFormatter, RoundingBehavior};
use string_utils::{is_line_ending, grapheme_count};
pub mod line;
pub mod line_formatter;
mod node;
mod undo_stack;
@ -23,33 +21,30 @@ mod undo_stack;
//=============================================================
/// A text buffer
pub struct Buffer<T: LineFormatter> {
pub struct Buffer {
text: BufferNode,
file_path: Option<Path>,
undo_stack: UndoStack,
pub formatter: T,
}
impl<T: LineFormatter> Buffer<T> {
pub fn new(formatter: T) -> Buffer<T> {
impl Buffer {
pub fn new() -> Buffer {
Buffer {
text: BufferNode::new(&formatter),
text: BufferNode::new(),
file_path: None,
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 buf = Buffer {
text: BufferNode::new(&formatter),
text: BufferNode::new(),
file_path: Some(path.clone()),
undo_stack: UndoStack::new(),
formatter: formatter,
};
let string = f.read_to_string().unwrap();
@ -77,7 +72,7 @@ impl<T: LineFormatter> Buffer<T> {
if a != b {
let substr = &string[a..b];
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);
}
@ -90,6 +85,7 @@ impl<T: LineFormatter> Buffer<T> {
return Ok(buf);
}
//------------------------------------------------------------------------
@ -104,11 +100,7 @@ impl<T: LineFormatter> Buffer<T> {
pub fn line_count(&self) -> usize {
self.text.line_count
}
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) {
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
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);
}
// All other cases
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!");
}
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
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);
}
// All other cases
else {
self.text.remove_lines_recursive(&self.formatter, line_a, line_b);
self.text.set_last_line_ending_recursive(&self.formatter);
self.text.remove_lines_recursive(line_a, line_b);
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
/// file loading.
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) {
self.text.append_leaf_node_unchecked_recursive(&self.formatter, 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);
self.text.append_leaf_node_unchecked_recursive(node);
}
@ -374,31 +359,6 @@ impl<T: LineFormatter> Buffer<T> {
pub fn line_col_to_index(&self, pos: (usize, usize)) -> usize {
return self.text.line_col_to_index_recursive(pos);
}
/// 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);
}
//------------------------------------------------------------------------
@ -575,12 +535,11 @@ impl<'a> Iterator for BufferLineIter<'a> {
#[cfg(test)]
mod tests {
use super::line_formatter::TestLineFormatter;
use super::{Buffer, BufferGraphemeIter, BufferLineIter};
#[test]
fn insert_text() {
let mut buf = Buffer::new(TestLineFormatter::new());
let mut buf = Buffer::new();
buf.insert_text("Hello 世界!", 0);
@ -603,7 +562,7 @@ mod tests {
#[test]
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);
@ -628,7 +587,7 @@ mod tests {
#[test]
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("Again ", 0);
@ -660,7 +619,7 @@ mod tests {
#[test]
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(" again", 5);
@ -692,7 +651,7 @@ mod tests {
#[test]
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("again", 6);
@ -723,7 +682,7 @@ mod tests {
#[test]
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("again", 11);
@ -754,7 +713,7 @@ mod tests {
#[test]
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("again", 2);
@ -786,7 +745,7 @@ mod tests {
#[test]
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("again", 8);
@ -818,7 +777,7 @@ mod tests {
#[test]
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("\nag\n\nain\n", 2);
@ -854,7 +813,7 @@ mod tests {
#[test]
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);
assert!(buf.grapheme_count() == 29);
@ -898,7 +857,7 @@ mod tests {
#[test]
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);
assert!(buf.grapheme_count() == 29);
@ -933,7 +892,7 @@ mod tests {
#[test]
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);
assert!(buf.grapheme_count() == 29);
@ -968,7 +927,7 @@ mod tests {
#[test]
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);
assert!(buf.grapheme_count() == 29);
@ -1009,7 +968,7 @@ mod tests {
#[test]
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);
assert!(buf.grapheme_count() == 29);
@ -1044,7 +1003,7 @@ mod tests {
#[test]
fn remove_text_6() {
let mut buf = Buffer::new(TestLineFormatter::new());
let mut buf = Buffer::new();
buf.insert_text("Hello\nworld!", 0);
assert!(buf.grapheme_count() == 12);
@ -1065,7 +1024,7 @@ mod tests {
#[test]
fn remove_text_7() {
let mut buf = Buffer::new(TestLineFormatter::new());
let mut buf = Buffer::new();
buf.insert_text("Hi\nthere\nworld!", 0);
assert!(buf.grapheme_count() == 15);
@ -1088,7 +1047,7 @@ mod tests {
#[test]
fn remove_text_8() {
let mut buf = Buffer::new(TestLineFormatter::new());
let mut buf = Buffer::new();
buf.insert_text("Hello\nworld!", 0);
assert!(buf.grapheme_count() == 12);
@ -1110,7 +1069,7 @@ mod tests {
#[test]
fn remove_text_9() {
let mut buf = Buffer::new(TestLineFormatter::new());
let mut buf = Buffer::new();
buf.insert_text("Hello\nworld!", 0);
assert!(buf.grapheme_count() == 12);
@ -1136,7 +1095,7 @@ mod tests {
#[test]
fn remove_text_10() {
let mut buf = Buffer::new(TestLineFormatter::new());
let mut buf = Buffer::new();
buf.insert_text("12\n34\n56\n78", 0);
assert!(buf.grapheme_count() == 11);
@ -1158,7 +1117,7 @@ mod tests {
#[test]
fn remove_text_11() {
let mut buf = Buffer::new(TestLineFormatter::new());
let mut buf = Buffer::new();
buf.insert_text("1234567890", 0);
assert!(buf.grapheme_count() == 10);
@ -1185,7 +1144,7 @@ mod tests {
#[test]
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);
@ -1230,7 +1189,7 @@ mod tests {
#[test]
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);
@ -1275,7 +1234,7 @@ mod tests {
#[test]
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);
@ -1320,7 +1279,7 @@ mod tests {
#[test]
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);
@ -1365,7 +1324,7 @@ mod tests {
#[test]
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);
@ -1410,7 +1369,7 @@ mod tests {
#[test]
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);
assert!(buf.grapheme_count() == 29);
@ -1441,7 +1400,7 @@ mod tests {
#[test]
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);
assert!(buf.grapheme_count() == 29);
@ -1472,7 +1431,7 @@ mod tests {
#[test]
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);
assert!(buf.grapheme_count() == 29);
@ -1505,7 +1464,7 @@ mod tests {
#[test]
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);
let pos = buf.line_col_to_index((2, 3));
@ -1516,7 +1475,7 @@ mod tests {
#[test]
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);
let pos = buf.line_col_to_index((2, 10));
@ -1526,7 +1485,7 @@ mod tests {
#[test]
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);
let pos = buf.line_col_to_index((10, 2));
@ -1537,7 +1496,7 @@ mod tests {
#[test]
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);
let pos = buf.index_to_line_col(5);
@ -1548,7 +1507,7 @@ mod tests {
#[test]
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);
let pos = buf.index_to_line_col(50);
@ -1559,7 +1518,7 @@ mod tests {
#[test]
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);
let s = buf.string_from_range(1, 12);
@ -1570,7 +1529,7 @@ mod tests {
#[test]
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);
let s = buf.string_from_range(0, 29);
@ -1581,7 +1540,7 @@ mod tests {
#[test]
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);
let mut iter = buf.grapheme_iter_at_index(16);
@ -1605,7 +1564,7 @@ mod tests {
#[test]
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);
let mut iter = buf.grapheme_iter_at_index(29);

View File

@ -1,7 +1,6 @@
use std::mem;
use std::cmp::{min, max};
use super::line_formatter::{LineFormatter, RoundingBehavior};
use string_utils::is_line_ending;
use super::line::{Line, LineEnding, LineGraphemeIter, str_to_line_ending};
@ -16,46 +15,39 @@ pub struct BufferNode {
pub grapheme_count: usize,
pub line_count: usize,
pub vis_dim: (usize, usize), // Height, width
}
impl BufferNode {
pub fn new<T: LineFormatter>(f: &T) -> BufferNode {
pub fn new() -> BufferNode {
let line = Line::new();
let dim = f.dimensions(&line);
BufferNode {
data: BufferNodeData::Leaf(line),
tree_height: 1,
grapheme_count: 0,
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 dim = f.dimensions(&line);
BufferNode {
data: BufferNodeData::Leaf(line),
tree_height: 1,
grapheme_count: gc,
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 {
data: BufferNodeData::Leaf(line),
tree_height: 1,
grapheme_count: grapheme_count,
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();
match self.data {
BufferNodeData::Leaf(ref line) => {
self.grapheme_count = line.grapheme_count();
self.line_count = 1;
self.vis_dim = f.dimensions(line);
},
BufferNodeData::Branch(ref left, ref right) => {
self.grapheme_count = left.grapheme_count + right.grapheme_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
fn rotate_left<T: LineFormatter>(&mut self, f: &T) {
let mut temp = BufferNode::new(f);
fn rotate_left(&mut self) {
let mut temp = BufferNode::new();
if let BufferNodeData::Branch(_, ref mut right) = self.data {
mem::swap(&mut temp, &mut (**right));
@ -112,17 +102,17 @@ impl BufferNode {
if let BufferNodeData::Branch(ref mut left, _) = temp.data {
mem::swap(&mut (**left), self);
left.update_stats(f);
left.update_stats();
}
mem::swap(&mut temp, self);
self.update_stats(f);
self.update_stats();
}
/// Rotates the tree under the node right
fn rotate_right<T: LineFormatter>(&mut self, f: &T) {
let mut temp = BufferNode::new(f);
fn rotate_right(&mut self) {
let mut temp = BufferNode::new();
if let BufferNodeData::Branch(ref mut left, _) = self.data {
mem::swap(&mut temp, &mut (**left));
@ -140,16 +130,16 @@ impl BufferNode {
if let BufferNodeData::Branch(_, ref mut right) = temp.data {
mem::swap(&mut (**right), self);
right.update_stats(f);
right.update_stats();
}
mem::swap(&mut temp, self);
self.update_stats(f);
self.update_stats();
}
/// Rebalances the tree under the node
fn rebalance<T: LineFormatter>(&mut self, f: &T) {
fn rebalance(&mut self) {
loop {
let mut rot: isize;
@ -166,7 +156,7 @@ impl BufferNode {
}
if child_rot {
left.rotate_left(f);
left.rotate_left();
}
rot = 1;
@ -181,7 +171,7 @@ impl BufferNode {
}
if child_rot {
right.rotate_right(f);
right.rotate_right();
}
rot = -1;
@ -197,25 +187,10 @@ impl BufferNode {
}
if rot == 1 {
self.rotate_right(f);
self.rotate_right();
}
else if rot == -1 {
self.rotate_left(f);
}
}
}
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);
self.rotate_left();
}
}
}
@ -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'.
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
let mut b1: usize = 0;
let mut b2: usize = 0;
@ -383,14 +300,14 @@ impl BufferNode {
for grapheme in text.grapheme_indices(true) {
if is_line_ending(grapheme.1) {
if g1 < g2 {
self.insert_text_recursive(f, &text[b1..b2], pos + g1);
self.insert_text_recursive(&text[b1..b2], pos + g1);
}
g1 = g2;
b2 += grapheme.1.len();
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;
g1 = g2;
@ -402,22 +319,22 @@ impl BufferNode {
}
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.
/// 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 {
// Find node for text to be inserted into
BufferNodeData::Branch(ref mut left, ref mut right) => {
if pos < left.grapheme_count {
left.insert_text_recursive(f, text, pos);
left.insert_text_recursive(text, pos);
}
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
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 {
return;
}
@ -445,10 +362,10 @@ impl BufferNode {
// Find node for the line break to be inserted into
BufferNodeData::Branch(ref mut left, ref mut right) => {
if pos < left.grapheme_count {
left.insert_line_break_recursive(f, ending, pos);
left.insert_line_break_recursive(ending, pos);
}
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;
},
@ -464,16 +381,16 @@ impl BufferNode {
if do_split {
// Insert line break
let new_line = old_line.split(ending, pos);
let new_node_a = Box::new(BufferNode::new_from_line(f, old_line));
let new_node_b = Box::new(BufferNode::new_from_line(f, new_line));
let new_node_a = Box::new(BufferNode::new_from_line(old_line));
let new_node_b = Box::new(BufferNode::new_from_line(new_line));
self.data = BufferNodeData::Branch(new_node_a, new_node_b);
self.update_stats(f);
self.update_stats();
}
else {
self.update_stats(f);
self.rebalance(f);
self.update_stats();
self.rebalance();
}
}
@ -481,8 +398,8 @@ impl BufferNode {
/// Removes text between grapheme positions pos_a and pos_b.
/// Returns true if a dangling left side remains from the removal.
/// Returns false otherwise.
pub fn remove_text_recursive<T: LineFormatter>(&mut self, f: &T, pos_a: usize, pos_b: usize, is_last: bool) -> bool {
let mut temp_node = BufferNode::new(f);
pub fn remove_text_recursive(&mut self, pos_a: usize, pos_b: usize, is_last: bool) -> bool {
let mut temp_node = BufferNode::new();
let mut total_side_removal = false;
let mut dangling_line = false;
let mut do_merge_fix = false;
@ -500,7 +417,7 @@ impl BufferNode {
if pos_b > left.grapheme_count {
let a = 0;
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;
@ -511,7 +428,7 @@ impl BufferNode {
if pos_a < left.grapheme_count {
let a = pos_a;
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 {
@ -532,14 +449,14 @@ impl BufferNode {
if pos_b > left.grapheme_count {
let a = if pos_a > left.grapheme_count {pos_a - left.grapheme_count} else {0};
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
if pos_a < left.grapheme_count {
let a = pos_a;
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;
}
}
@ -560,7 +477,7 @@ impl BufferNode {
// Do the merge fix if necessary
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
// remaining side.
@ -568,54 +485,54 @@ impl BufferNode {
mem::swap(&mut temp_node, self);
}
self.update_stats(f);
self.rebalance(f);
self.update_stats();
self.rebalance();
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();
if let BufferNodeData::Branch(_, ref mut right) = self.data {
right.append_line_unchecked_recursive(f, line);
right.append_line_unchecked_recursive(line);
}
else {
if let BufferNodeData::Leaf(ref mut this_line) = self.data {
mem::swap(this_line, &mut other_line);
}
let new_node_a = Box::new(BufferNode::new_from_line(f, other_line));
let new_node_b = Box::new(BufferNode::new_from_line(f, line));
let new_node_a = Box::new(BufferNode::new_from_line(other_line));
let new_node_b = Box::new(BufferNode::new_from_line(line));
self.data = BufferNodeData::Branch(new_node_a, new_node_b);
}
self.update_stats(f);
self.rebalance(f);
self.update_stats();
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 {
right.append_leaf_node_unchecked_recursive(f, node);
right.append_leaf_node_unchecked_recursive(node);
}
else {
let mut new_left_node = BufferNode::new(f);
let mut new_left_node = BufferNode::new();
mem::swap(self, &mut new_left_node);
self.data = BufferNodeData::Branch(Box::new(new_left_node), Box::new(node));
}
self.update_stats(f);
self.rebalance(f);
self.update_stats();
self.rebalance();
}
/// 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_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 {
// Right node completely removed
@ -626,7 +543,7 @@ impl BufferNode {
else if line_b > left.line_count {
let a = if line_a > left.line_count {line_a - left.line_count} else {0};
let b = line_b - left.line_count;
right.remove_lines_recursive(f, a, b);
right.remove_lines_recursive(a, b);
}
// Left node completely removed
@ -637,7 +554,7 @@ impl BufferNode {
else if line_a < left.line_count {
let a = line_a;
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
@ -660,17 +577,17 @@ impl BufferNode {
mem::swap(&mut temp_node, self);
}
self.update_stats(f);
self.rebalance(f);
self.update_stats();
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 {
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 {
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 {
BufferNodeData::Branch(ref mut left, ref mut right) => {
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 {
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.rebalance(f);
self.update_stats();
self.rebalance();
}
/// 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 temp_node = BufferNode::new(f);
let mut temp_node = BufferNode::new();
let mut side_removal = false;
match self.data {
@ -713,7 +630,7 @@ impl BufferNode {
side_removal = true;
}
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 {
@ -723,7 +640,7 @@ impl BufferNode {
side_removal = true;
}
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 {
@ -741,8 +658,8 @@ impl BufferNode {
mem::swap(&mut temp_node, self);
}
self.update_stats(f);
self.rebalance(f);
self.update_stats();
self.rebalance();
return Some(pulled_line);
}
@ -750,10 +667,10 @@ impl BufferNode {
/// Ensures that the last line in the node tree has no
/// 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 {
BufferNodeData::Branch(_, ref mut right) => {
right.set_last_line_ending_recursive(f);
right.set_last_line_ending_recursive();
},
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 {
use super::BufferNode;
use super::super::line::LineEnding;
use super::super::line_formatter::TestLineFormatter;
#[test]
fn merge_line_with_next_recursive_1() {
let f = TestLineFormatter::new();
let mut node = BufferNode::new(&f);
node.insert_text(&f, "Hi\n there!", 0);
let mut node = BufferNode::new();
node.insert_text("Hi\n there!", 0);
assert!(node.grapheme_count == 10);
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();
@ -1047,14 +962,13 @@ mod tests {
#[test]
fn merge_line_with_next_recursive_2() {
let f = TestLineFormatter::new();
let mut node = BufferNode::new(&f);
node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0);
let mut node = BufferNode::new();
node.insert_text("Hi\n there\n people \nof the\n world!", 0);
assert!(node.grapheme_count == 33);
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();
@ -1098,14 +1012,13 @@ mod tests {
#[test]
fn merge_line_with_next_recursive_3() {
let f = TestLineFormatter::new();
let mut node = BufferNode::new(&f);
node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0);
let mut node = BufferNode::new();
node.insert_text("Hi\n there\n people \nof the\n world!", 0);
assert!(node.grapheme_count == 33);
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();
@ -1149,14 +1062,13 @@ mod tests {
#[test]
fn pull_out_line_recursive_1() {
let f = TestLineFormatter::new();
let mut node = BufferNode::new(&f);
node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0);
let mut node = BufferNode::new();
node.insert_text("Hi\n there\n people \nof the\n world!", 0);
assert!(node.grapheme_count == 33);
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.ending == LineEnding::LF);
@ -1200,14 +1112,13 @@ mod tests {
#[test]
fn pull_out_line_recursive_2() {
let f = TestLineFormatter::new();
let mut node = BufferNode::new(&f);
node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0);
let mut node = BufferNode::new();
node.insert_text("Hi\n there\n people \nof the\n world!", 0);
assert!(node.grapheme_count == 33);
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.ending == LineEnding::LF);
@ -1245,14 +1156,13 @@ mod tests {
#[test]
fn pull_out_line_recursive_3() {
let f = TestLineFormatter::new();
let mut node = BufferNode::new(&f);
node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0);
let mut node = BufferNode::new();
node.insert_text("Hi\n there\n people \nof the\n world!", 0);
assert!(node.grapheme_count == 33);
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.ending == LineEnding::None);

View File

@ -5,7 +5,7 @@ use std::ops::{Index, IndexMut};
use std::cmp::Ordering;
use buffer::Buffer;
use buffer::line_formatter::LineFormatter;
use super::formatter::LineFormatter;
/// 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>) {
let (_, h) = buf.index_to_v2d(self.range.0);
self.vis_start = h;
pub fn update_vis_start<T: LineFormatter>(&mut self, buf: &Buffer, f: &T) {
// TODO
//let (_, h) = buf.index_to_v2d(self.range.0);
//self.vis_start = h;
}
}

View File

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

View File

@ -3,11 +3,11 @@
use rustbox;
use rustbox::Color;
use editor::Editor;
use editor::formatter::{LineFormatter, RoundingBehavior};
use std::char;
use std::time::duration::Duration;
use string_utils::{is_line_ending};
use buffer::line::{line_ending_to_str, LineEnding};
use buffer::line_formatter::{LineFormatter, RoundingBehavior};
use self::formatter::ConsoleLineFormatter;
pub mod formatter;
@ -84,8 +84,7 @@ impl TermUI {
let mut resize: Option<(usize, usize)> = None;
self.editor.update_dim(self.height-1, self.width);
self.editor.buffer.formatter.wrap_width = self.width as usize;
self.editor.buffer.reformat();
self.editor.formatter.wrap_width = self.width as usize;
loop {
// Draw the editor to screen
@ -197,8 +196,7 @@ impl TermUI {
self.width = w as usize;
self.height = h as usize;
self.editor.update_dim(self.height-1, self.width);
self.editor.buffer.formatter.wrap_width = self.width;
self.editor.buffer.reformat();
self.editor.formatter.wrap_width = self.width;
println!("Resized window!");
}
resize = None;
@ -354,101 +352,103 @@ impl TermUI {
fn draw_editor_text(&self, editor: &Editor<ConsoleLineFormatter>, c1: (usize, usize), c2: (usize, usize)) {
// 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 screen_line = c1.0 as isize + vis_starting_line as isize;
let screen_col = c1.1 as isize;
// TODO: update to new formatting code
let mut line_iter = editor.buffer.line_iter_at_index(starting_line);
for line in line_iter {
let mut g_iter = editor.buffer.formatter.vis_grapheme_iter(line);
// Loop through the graphemes of the line and print them to
// the screen.
for (g, (pos_y, pos_x), width) in g_iter {
// 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) {
if at_cursor {
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " ");
}
}
else if g == "\t" {
for i in 0..width {
let tpx = px as usize + i;
if tpx <= c2.1 {
self.rb.print(tpx as usize, py as usize, rustbox::RB_NORMAL, Color::White, Color::Black, " ");
}
}
if at_cursor {
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " ");
}
}
else {
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;
}
let (dim_y, _) = editor.buffer.formatter.dimensions(line);
screen_line += dim_y as isize;
}
// If we get here, it means we reached the end of the text buffer
// without going off the bottom of the screen. So draw the cursor
// 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 grapheme_index >= c.range.0 && grapheme_index <= c.range.1 {
at_cursor = true;
}
}
if at_cursor {
// 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, " ");
}
}
//// 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 screen_line = c1.0 as isize + vis_starting_line as isize;
//let screen_col = c1.1 as isize;
//
//let mut line_iter = editor.buffer.line_iter_at_index(starting_line);
//
//for line in line_iter {
// let mut g_iter = editor.buffer.formatter.vis_grapheme_iter(line);
//
// // Loop through the graphemes of the line and print them to
// // the screen.
// for (g, (pos_y, pos_x), width) in g_iter {
// // 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) {
// if at_cursor {
// self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " ");
// }
// }
// else if g == "\t" {
// for i in 0..width {
// let tpx = px as usize + i;
// if tpx <= c2.1 {
// self.rb.print(tpx as usize, py as usize, rustbox::RB_NORMAL, Color::White, Color::Black, " ");
// }
// }
//
// if at_cursor {
// self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " ");
// }
// }
// else {
// 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;
// }
//
// let (dim_y, _) = editor.buffer.formatter.dimensions(line);
// screen_line += dim_y as isize;
//}
//
//
//
//// If we get here, it means we reached the end of the text buffer
//// without going off the bottom of the screen. So draw the cursor
//// 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 grapheme_index >= c.range.0 && grapheme_index <= c.range.1 {
// at_cursor = true;
// }
//}
//
//if at_cursor {
// // 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, " ");
// }
//}
}