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:
parent
e29777e33c
commit
8319033ae5
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -92,6 +87,7 @@ impl<T: LineFormatter> Buffer<T> {
|
|||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
//------------------------------------------------------------------------
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
// TODO: update to new formatting code
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
// TODO: update to new formatting code
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
// TODO: update to new formatting code
|
||||
|
||||
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, " ");
|
||||
}
|
||||
}
|
||||
//// 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, " ");
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user