Basic line-ending detection when opening files.

Buffers now store what line-ending type they consider themselves to be,
and the ui uses that when adding new lines while editing.
This commit is contained in:
Nathan Vegdahl 2015-01-03 15:15:14 -08:00
parent f760d6078d
commit 0941339906
5 changed files with 85 additions and 73 deletions

View File

@ -171,7 +171,7 @@ impl Line {
if le_size == 0 && tl.text.len() >= 1 { if le_size == 0 && tl.text.len() >= 1 {
match unsafe{mem::transmute::<&[u8], &str>(tl.text.slice_from(text_size-1))} { match unsafe{mem::transmute::<&[u8], &str>(tl.text.slice_from(text_size-1))} {
// LF or CRLF // LF
"\u{000A}" => { "\u{000A}" => {
tl.ending = LineEnding::LF; tl.ending = LineEnding::LF;
le_size = 1; le_size = 1;

View File

@ -3,7 +3,7 @@
use std::mem; use std::mem;
use self::node::{BufferNode, BufferNodeGraphemeIter, BufferNodeLineIter}; use self::node::{BufferNode, BufferNodeGraphemeIter, BufferNodeLineIter};
use self::line::{Line}; use self::line::{Line, LineEnding};
use string_utils::{is_line_ending}; use string_utils::{is_line_ending};
pub mod line; pub mod line;
@ -16,25 +16,27 @@ mod node;
/// A text buffer /// A text buffer
pub struct Buffer { pub struct Buffer {
root: BufferNode, text: BufferNode,
pub line_ending_type: LineEnding,
} }
impl Buffer { impl Buffer {
pub fn new() -> Buffer { pub fn new() -> Buffer {
Buffer { Buffer {
root: BufferNode::new() text: BufferNode::new(),
line_ending_type: LineEnding::LF,
} }
} }
pub fn len(&self) -> uint { pub fn len(&self) -> uint {
self.root.grapheme_count self.text.grapheme_count
} }
pub fn line_count(&self) -> uint { pub fn line_count(&self) -> uint {
self.root.line_count self.text.line_count
} }
@ -43,7 +45,7 @@ impl Buffer {
panic!("Buffer::get_grapheme(): index past last grapheme."); panic!("Buffer::get_grapheme(): index past last grapheme.");
} }
else { else {
return self.root.get_grapheme_recursive(index); return self.text.get_grapheme_recursive(index);
} }
} }
@ -53,7 +55,7 @@ impl Buffer {
panic!("Buffer::get_grapheme_width(): index past last grapheme."); panic!("Buffer::get_grapheme_width(): index past last grapheme.");
} }
else { else {
return self.root.get_grapheme_width_recursive(index); return self.text.get_grapheme_width_recursive(index);
} }
} }
@ -66,7 +68,7 @@ impl Buffer {
// NOTE: this can be done non-recursively, which would be more // NOTE: this can be done non-recursively, which would be more
// efficient. However, it seems likely to require unsafe code // efficient. However, it seems likely to require unsafe code
// if done that way. // if done that way.
return self.root.get_line_recursive(index); return self.text.get_line_recursive(index);
} }
@ -74,7 +76,7 @@ impl Buffer {
/// doing any sanity checks. This is primarily for efficient /// doing any sanity checks. This is primarily for efficient
/// file loading. /// file loading.
pub fn append_line_unchecked(&mut self, line: Line) { pub fn append_line_unchecked(&mut self, line: Line) {
self.root.append_line_unchecked_recursive(line); self.text.append_line_unchecked_recursive(line);
} }
@ -93,20 +95,20 @@ impl Buffer {
panic!("Buffer::remove_lines(): attempt to remove lines past the last line of text."); panic!("Buffer::remove_lines(): attempt to remove lines past the last line of text.");
} }
// Complete removal of all lines // Complete removal of all lines
else if line_a == 0 && line_b == self.root.line_count { else if line_a == 0 && line_b == self.text.line_count {
let mut temp_node = BufferNode::new(); let mut temp_node = BufferNode::new();
mem::swap(&mut (self.root), &mut temp_node); mem::swap(&mut (self.text), &mut temp_node);
} }
// All other cases // All other cases
else { else {
self.root.remove_lines_recursive(line_a, line_b); self.text.remove_lines_recursive(line_a, line_b);
self.root.set_last_line_ending_recursive(); self.text.set_last_line_ending_recursive();
} }
} }
pub fn pos_2d_to_closest_1d(&self, pos: (uint, uint)) -> uint { pub fn pos_2d_to_closest_1d(&self, pos: (uint, uint)) -> uint {
return self.root.pos_2d_to_closest_1d_recursive(pos); return self.text.pos_2d_to_closest_1d_recursive(pos);
} }
@ -123,12 +125,12 @@ impl Buffer {
pub fn pos_1d_to_closest_2d(&self, pos: uint) -> (uint, uint) { pub fn pos_1d_to_closest_2d(&self, pos: uint) -> (uint, uint) {
return self.root.pos_1d_to_closest_2d_recursive(pos); return self.text.pos_1d_to_closest_2d_recursive(pos);
} }
pub fn pos_1d_to_closest_vis_2d(&self, pos: uint) -> (uint, uint) { pub fn pos_1d_to_closest_vis_2d(&self, pos: uint) -> (uint, uint) {
let (v, h) = self.root.pos_1d_to_closest_2d_recursive(pos); let (v, h) = self.text.pos_1d_to_closest_2d_recursive(pos);
let vis_h = self.get_line(v).grapheme_index_to_closest_vis_pos(h); let vis_h = self.get_line(v).grapheme_index_to_closest_vis_pos(h);
return (v, vis_h); return (v, vis_h);
} }
@ -136,7 +138,7 @@ impl Buffer {
/// Insert 'text' at grapheme position 'pos'. /// Insert 'text' at grapheme position 'pos'.
pub fn insert_text(&mut self, text: &str, pos: uint) { pub fn insert_text(&mut self, text: &str, pos: uint) {
self.root.insert_text(text, pos); self.text.insert_text(text, pos);
} }
@ -155,16 +157,16 @@ impl Buffer {
panic!("Buffer::remove_text(): attempt to remove text past the end of buffer."); panic!("Buffer::remove_text(): attempt to remove text past the end of buffer.");
} }
// Complete removal of all text // Complete removal of all text
else if pos_a == 0 && pos_b == self.root.grapheme_count { else if pos_a == 0 && pos_b == self.text.grapheme_count {
let mut temp_node = BufferNode::new(); let mut temp_node = BufferNode::new();
mem::swap(&mut (self.root), &mut temp_node); mem::swap(&mut (self.text), &mut temp_node);
} }
// All other cases // All other cases
else { else {
if self.root.remove_text_recursive(pos_a, pos_b, true) { if self.text.remove_text_recursive(pos_a, pos_b, true) {
panic!("Buffer::remove_text(): dangling left side remains. This should never happen!"); panic!("Buffer::remove_text(): dangling left side remains. This should never happen!");
} }
self.root.set_last_line_ending_recursive(); self.text.set_last_line_ending_recursive();
} }
} }
@ -172,7 +174,7 @@ impl Buffer {
/// Creates an iterator at the first character /// Creates an iterator at the first character
pub fn grapheme_iter<'a>(&'a self) -> BufferGraphemeIter<'a> { pub fn grapheme_iter<'a>(&'a self) -> BufferGraphemeIter<'a> {
BufferGraphemeIter { BufferGraphemeIter {
gi: self.root.grapheme_iter() gi: self.text.grapheme_iter()
} }
} }
@ -182,21 +184,21 @@ impl Buffer {
/// return None on next(). /// return None on next().
pub fn grapheme_iter_at_index<'a>(&'a self, index: uint) -> BufferGraphemeIter<'a> { pub fn grapheme_iter_at_index<'a>(&'a self, index: uint) -> BufferGraphemeIter<'a> {
BufferGraphemeIter { BufferGraphemeIter {
gi: self.root.grapheme_iter_at_index(index) gi: self.text.grapheme_iter_at_index(index)
} }
} }
pub fn line_iter<'a>(&'a self) -> BufferLineIter<'a> { pub fn line_iter<'a>(&'a self) -> BufferLineIter<'a> {
BufferLineIter { BufferLineIter {
li: self.root.line_iter() li: self.text.line_iter()
} }
} }
pub fn line_iter_at_index<'a>(&'a self, index: uint) -> BufferLineIter<'a> { pub fn line_iter_at_index<'a>(&'a self, index: uint) -> BufferLineIter<'a> {
BufferLineIter { BufferLineIter {
li: self.root.line_iter_at_index(index) li: self.text.line_iter_at_index(index)
} }
} }
@ -286,7 +288,7 @@ fn insert_text() {
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 9); assert!(buf.len() == 9);
assert!(buf.root.line_count == 1); assert!(buf.text.line_count == 1);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
assert!(Some("l") == iter.next()); assert!(Some("l") == iter.next());
@ -309,7 +311,7 @@ fn insert_text_with_newlines() {
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 11); assert!(buf.len() == 11);
assert!(buf.root.line_count == 3); assert!(buf.text.line_count == 3);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
assert!(Some("l") == iter.next()); assert!(Some("l") == iter.next());
@ -335,7 +337,7 @@ fn insert_text_in_non_empty_buffer_1() {
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 17); assert!(buf.len() == 17);
assert!(buf.root.line_count == 3); assert!(buf.text.line_count == 3);
assert!(Some("A") == iter.next()); assert!(Some("A") == iter.next());
assert!(Some("g") == iter.next()); assert!(Some("g") == iter.next());
assert!(Some("a") == iter.next()); assert!(Some("a") == iter.next());
@ -367,7 +369,7 @@ fn insert_text_in_non_empty_buffer_2() {
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 17); assert!(buf.len() == 17);
assert!(buf.root.line_count == 3); assert!(buf.text.line_count == 3);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
assert!(Some("l") == iter.next()); assert!(Some("l") == iter.next());
@ -399,7 +401,7 @@ fn insert_text_in_non_empty_buffer_3() {
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 16); assert!(buf.len() == 16);
assert!(buf.root.line_count == 3); assert!(buf.text.line_count == 3);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
assert!(Some("l") == iter.next()); assert!(Some("l") == iter.next());
@ -430,7 +432,7 @@ fn insert_text_in_non_empty_buffer_4() {
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 16); assert!(buf.len() == 16);
assert!(buf.root.line_count == 3); assert!(buf.text.line_count == 3);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
assert!(Some("l") == iter.next()); assert!(Some("l") == iter.next());
@ -461,7 +463,7 @@ fn insert_text_in_non_empty_buffer_5() {
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 16); assert!(buf.len() == 16);
assert!(buf.root.line_count == 3); assert!(buf.text.line_count == 3);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
assert!(Some("a") == iter.next()); assert!(Some("a") == iter.next());
@ -493,7 +495,7 @@ fn insert_text_in_non_empty_buffer_6() {
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 16); assert!(buf.len() == 16);
assert!(buf.root.line_count == 3); assert!(buf.text.line_count == 3);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
assert!(Some("l") == iter.next()); assert!(Some("l") == iter.next());
@ -525,7 +527,7 @@ fn insert_text_in_non_empty_buffer_7() {
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 20); assert!(buf.len() == 20);
assert!(buf.root.line_count == 7); assert!(buf.text.line_count == 7);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
assert!(Some("\n") == iter.next()); assert!(Some("\n") == iter.next());
@ -557,14 +559,14 @@ fn remove_text_1() {
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.len() == 29); assert!(buf.len() == 29);
assert!(buf.root.line_count == 6); assert!(buf.text.line_count == 6);
buf.remove_text(0, 3); buf.remove_text(0, 3);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 26); assert!(buf.len() == 26);
assert!(buf.root.line_count == 5); assert!(buf.text.line_count == 5);
assert!(Some("t") == iter.next()); assert!(Some("t") == iter.next());
assert!(Some("h") == iter.next()); assert!(Some("h") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
@ -601,14 +603,14 @@ fn remove_text_2() {
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.len() == 29); assert!(buf.len() == 29);
assert!(buf.root.line_count == 6); assert!(buf.text.line_count == 6);
buf.remove_text(0, 12); buf.remove_text(0, 12);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 17); assert!(buf.len() == 17);
assert!(buf.root.line_count == 4); assert!(buf.text.line_count == 4);
assert!(Some("p") == iter.next()); assert!(Some("p") == iter.next());
assert!(Some("l") == iter.next()); assert!(Some("l") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
@ -636,14 +638,14 @@ fn remove_text_3() {
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.len() == 29); assert!(buf.len() == 29);
assert!(buf.root.line_count == 6); assert!(buf.text.line_count == 6);
buf.remove_text(5, 17); buf.remove_text(5, 17);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 17); assert!(buf.len() == 17);
assert!(buf.root.line_count == 4); assert!(buf.text.line_count == 4);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("i") == iter.next()); assert!(Some("i") == iter.next());
assert!(Some("\n") == iter.next()); assert!(Some("\n") == iter.next());
@ -671,14 +673,14 @@ fn remove_text_4() {
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.len() == 29); assert!(buf.len() == 29);
assert!(buf.root.line_count == 6); assert!(buf.text.line_count == 6);
buf.remove_text(23, 29); buf.remove_text(23, 29);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 23); assert!(buf.len() == 23);
assert!(buf.root.line_count == 6); assert!(buf.text.line_count == 6);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("i") == iter.next()); assert!(Some("i") == iter.next());
assert!(Some("\n") == iter.next()); assert!(Some("\n") == iter.next());
@ -712,14 +714,14 @@ fn remove_text_5() {
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.len() == 29); assert!(buf.len() == 29);
assert!(buf.root.line_count == 6); assert!(buf.text.line_count == 6);
buf.remove_text(17, 29); buf.remove_text(17, 29);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 17); assert!(buf.len() == 17);
assert!(buf.root.line_count == 4); assert!(buf.text.line_count == 4);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("i") == iter.next()); assert!(Some("i") == iter.next());
assert!(Some("\n") == iter.next()); assert!(Some("\n") == iter.next());
@ -747,14 +749,14 @@ fn remove_text_6() {
buf.insert_text("Hello\nworld!", 0); buf.insert_text("Hello\nworld!", 0);
assert!(buf.len() == 12); assert!(buf.len() == 12);
assert!(buf.root.line_count == 2); assert!(buf.text.line_count == 2);
buf.remove_text(3, 12); buf.remove_text(3, 12);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 3); assert!(buf.len() == 3);
assert!(buf.root.line_count == 1); assert!(buf.text.line_count == 1);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
assert!(Some("l") == iter.next()); assert!(Some("l") == iter.next());
@ -768,14 +770,14 @@ fn remove_text_7() {
buf.insert_text("Hi\nthere\nworld!", 0); buf.insert_text("Hi\nthere\nworld!", 0);
assert!(buf.len() == 15); assert!(buf.len() == 15);
assert!(buf.root.line_count == 3); assert!(buf.text.line_count == 3);
buf.remove_text(5, 15); buf.remove_text(5, 15);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 5); assert!(buf.len() == 5);
assert!(buf.root.line_count == 2); assert!(buf.text.line_count == 2);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("i") == iter.next()); assert!(Some("i") == iter.next());
assert!(Some("\n") == iter.next()); assert!(Some("\n") == iter.next());
@ -791,14 +793,14 @@ fn remove_text_8() {
buf.insert_text("Hello\nworld!", 0); buf.insert_text("Hello\nworld!", 0);
assert!(buf.len() == 12); assert!(buf.len() == 12);
assert!(buf.root.line_count == 2); assert!(buf.text.line_count == 2);
buf.remove_text(3, 11); buf.remove_text(3, 11);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 4); assert!(buf.len() == 4);
assert!(buf.root.line_count == 1); assert!(buf.text.line_count == 1);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
assert!(Some("l") == iter.next()); assert!(Some("l") == iter.next());
@ -813,14 +815,14 @@ fn remove_text_9() {
buf.insert_text("Hello\nworld!", 0); buf.insert_text("Hello\nworld!", 0);
assert!(buf.len() == 12); assert!(buf.len() == 12);
assert!(buf.root.line_count == 2); assert!(buf.text.line_count == 2);
buf.remove_text(8, 12); buf.remove_text(8, 12);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 8); assert!(buf.len() == 8);
assert!(buf.root.line_count == 2); assert!(buf.text.line_count == 2);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("e") == iter.next()); assert!(Some("e") == iter.next());
assert!(Some("l") == iter.next()); assert!(Some("l") == iter.next());
@ -839,14 +841,14 @@ fn remove_text_10() {
buf.insert_text("12\n34\n56\n78", 0); buf.insert_text("12\n34\n56\n78", 0);
assert!(buf.len() == 11); assert!(buf.len() == 11);
assert!(buf.root.line_count == 4); assert!(buf.text.line_count == 4);
buf.remove_text(4, 11); buf.remove_text(4, 11);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 4); assert!(buf.len() == 4);
assert!(buf.root.line_count == 2); assert!(buf.text.line_count == 2);
assert!(Some("1") == iter.next()); assert!(Some("1") == iter.next());
assert!(Some("2") == iter.next()); assert!(Some("2") == iter.next());
assert!(Some("\n") == iter.next()); assert!(Some("\n") == iter.next());
@ -861,14 +863,14 @@ fn remove_text_11() {
buf.insert_text("1234567890", 0); buf.insert_text("1234567890", 0);
assert!(buf.len() == 10); assert!(buf.len() == 10);
assert!(buf.root.line_count == 1); assert!(buf.text.line_count == 1);
buf.remove_text(9, 10); buf.remove_text(9, 10);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 9); assert!(buf.len() == 9);
assert!(buf.root.line_count == 1); assert!(buf.text.line_count == 1);
assert!(Some("1") == iter.next()); assert!(Some("1") == iter.next());
assert!(Some("2") == iter.next()); assert!(Some("2") == iter.next());
assert!(Some("3") == iter.next()); assert!(Some("3") == iter.next());
@ -888,14 +890,14 @@ fn remove_lines_1() {
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.len() == 29); assert!(buf.len() == 29);
assert!(buf.root.line_count == 6); assert!(buf.text.line_count == 6);
buf.remove_lines(0, 3); buf.remove_lines(0, 3);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 13); assert!(buf.len() == 13);
assert!(buf.root.line_count == 3); assert!(buf.text.line_count == 3);
assert!(Some("o") == iter.next()); assert!(Some("o") == iter.next());
assert!(Some("f") == iter.next()); assert!(Some("f") == iter.next());
assert!(Some("\n") == iter.next()); assert!(Some("\n") == iter.next());
@ -919,14 +921,14 @@ fn remove_lines_2() {
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.len() == 29); assert!(buf.len() == 29);
assert!(buf.root.line_count == 6); assert!(buf.text.line_count == 6);
buf.remove_lines(1, 4); buf.remove_lines(1, 4);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 13); assert!(buf.len() == 13);
assert!(buf.root.line_count == 3); assert!(buf.text.line_count == 3);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("i") == iter.next()); assert!(Some("i") == iter.next());
assert!(Some("\n") == iter.next()); assert!(Some("\n") == iter.next());
@ -950,14 +952,14 @@ fn remove_lines_3() {
buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0);
assert!(buf.len() == 29); assert!(buf.len() == 29);
assert!(buf.root.line_count == 6); assert!(buf.text.line_count == 6);
buf.remove_lines(3, 6); buf.remove_lines(3, 6);
let mut iter = buf.grapheme_iter(); let mut iter = buf.grapheme_iter();
assert!(buf.len() == 15); assert!(buf.len() == 15);
assert!(buf.root.line_count == 3); assert!(buf.text.line_count == 3);
assert!(Some("H") == iter.next()); assert!(Some("H") == iter.next());
assert!(Some("i") == iter.next()); assert!(Some("i") == iter.next());
assert!(Some("\n") == iter.next()); assert!(Some("\n") == iter.next());

View File

@ -8,20 +8,15 @@ use buffer::Buffer as TextBuffer;
pub fn load_file_to_buffer(path: &Path) -> IoResult<TextBuffer> { pub fn load_file_to_buffer(path: &Path) -> IoResult<TextBuffer> {
let mut tb = TextBuffer::new(); let mut tb = TextBuffer::new();
let mut f = BufferedReader::new(try!(File::open(path))); let mut f = BufferedReader::new(try!(File::open(path)));
let mut last_line_breaks = true;
for line in f.lines() { for line in f.lines() {
let l = Line::new_from_string_unchecked(line.unwrap()); let l = Line::new_from_string_unchecked(line.unwrap());
last_line_breaks = l.ending != LineEnding::None; if l.ending != LineEnding::None {
tb.line_ending_type = l.ending;
}
tb.append_line_unchecked(l); tb.append_line_unchecked(l);
} }
// If the last line had a line break, we need to add a final
// blank line.
if last_line_breaks {
tb.append_line_unchecked(Line::new());
}
// Remove initial blank line // Remove initial blank line
tb.remove_lines(0, 1); tb.remove_lines(0, 1);

View File

@ -6,6 +6,7 @@ use editor::Editor;
use std::char; use std::char;
use std::time::duration::Duration; use std::time::duration::Duration;
use string_utils::{is_line_ending}; use string_utils::{is_line_ending};
use buffer::line::{line_ending_to_str, LineEnding};
// Key codes // Key codes
const K_ENTER: u16 = 13; const K_ENTER: u16 = 13;
@ -126,7 +127,8 @@ impl TermUI {
}, },
K_ENTER => { K_ENTER => {
self.editor.insert_text_at_cursor("\n"); let nl = line_ending_to_str(self.editor.buffer.line_ending_type);
self.editor.insert_text_at_cursor(nl);
}, },
K_SPACE => { K_SPACE => {
@ -299,7 +301,18 @@ impl TermUI {
self.rb.print(c2.1 - pstring.len(), c1.0, rustbox::RB_NORMAL, foreground, background, pstring.as_slice()); self.rb.print(c2.1 - pstring.len(), c1.0, rustbox::RB_NORMAL, foreground, background, pstring.as_slice());
// Text encoding info and tab style // Text encoding info and tab style
let info_line = format!("UTF8:LF tabs:4"); let nl = match editor.buffer.line_ending_type {
LineEnding::None => "None",
LineEnding::CRLF => "CRLF",
LineEnding::LF => "LF",
LineEnding::VT => "VT",
LineEnding::FF => "FF",
LineEnding::CR => "CR",
LineEnding::NEL => "NEL",
LineEnding::LS => "LS",
LineEnding::PS => "PS",
};
let info_line = format!("UTF8:{} tabs:4", nl);
self.rb.print(c2.1 - 30, c1.0, rustbox::RB_NORMAL, foreground, background, info_line.as_slice()); self.rb.print(c2.1 - 30, c1.0, rustbox::RB_NORMAL, foreground, background, info_line.as_slice());
// Draw main text editing area // Draw main text editing area

View File

@ -1,3 +1,5 @@
- Custom line iterator code for file loading, because rust's built-in one
only recognizes LF and CRLF.
- Line number display - Line number display
- File opening by entering path - File opening by entering path
- UI that wraps editors, for split view. - UI that wraps editors, for split view.