diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 31000a2..cf7f9a1 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -11,12 +11,16 @@ env: jobs: build: - runs-on: ubuntu-latest - steps: - uses: actions/checkout@v3 - name: Build run: cargo build --verbose - name: Run tests run: cargo test --verbose + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: rustfmt + run: rustfmt --check src/**/*.rs diff --git a/src/buffer/cursor.rs b/src/buffer/cursor.rs index 4ef6f74..47859a1 100644 --- a/src/buffer/cursor.rs +++ b/src/buffer/cursor.rs @@ -1,8 +1,8 @@ //! Bounds-checked buffer cursor type. +use crate::buffer::{GapBuffer, Position}; +use std::cell::RefCell; use std::ops::{Deref, DerefMut}; use std::rc::Rc; -use std::cell::RefCell; -use crate::buffer::{Position, GapBuffer}; use unicode_segmentation::UnicodeSegmentation; /// Read-only wrapper for a `Position`, to allow field level access to a @@ -32,10 +32,10 @@ impl DerefMut for Cursor { impl Cursor { /// Initializes a cursor bound to the specified gap buffer, at the specified position. pub fn new(data: Rc>, position: Position) -> Cursor { - Cursor{ + Cursor { data, position, - sticky_offset: position.offset + sticky_offset: position.offset, } } @@ -70,7 +70,7 @@ impl Cursor { // to maintain it when moving across lines. self.sticky_offset = position.offset; - return true + return true; } false } @@ -79,10 +79,15 @@ impl Cursor { /// the data and the cursor will not be updated if it is out-of-bounds. pub fn move_up(&mut self) { // Don't bother if we are already at the top. - if self.line == 0 { return; } + if self.line == 0 { + return; + } - let target_line = self.line-1; - let new_position = Position{ line: target_line, offset: self.sticky_offset }; + let target_line = self.line - 1; + let new_position = Position { + line: target_line, + offset: self.sticky_offset, + }; // Try moving to the same offset on the line above, falling back to its EOL. if !self.move_to(new_position) { @@ -92,7 +97,10 @@ impl Cursor { target_offset = line.graphemes(true).count(); } } - self.move_to(Position{ line: target_line, offset: target_offset }); + self.move_to(Position { + line: target_line, + offset: target_offset, + }); // Moving the position successfully updates the sticky offset, but we // haven't actually moved to where we really wanted to go (offset-wise). @@ -104,8 +112,11 @@ impl Cursor { /// Increments the cursor line. The location is bounds-checked against /// the data and the cursor will not be updated if it is out-of-bounds. pub fn move_down(&mut self) { - let target_line = self.line+1; - let new_position = Position{ line: target_line, offset: self.sticky_offset }; + let target_line = self.line + 1; + let new_position = Position { + line: target_line, + offset: self.sticky_offset, + }; // Try moving to the same offset on the line below, falling back to its EOL. if !self.move_to(new_position) { @@ -115,7 +126,10 @@ impl Cursor { target_offset = line.graphemes(true).count(); } } - self.move_to(Position{ line: target_line, offset: target_offset }); + self.move_to(Position { + line: target_line, + offset: target_offset, + }); // Moving the position successfully updates the sticky offset, but we // haven't actually moved to where we really wanted to go (offset-wise). @@ -128,22 +142,33 @@ impl Cursor { /// the data and the cursor will not be updated if it is out-of-bounds. pub fn move_left(&mut self) { // Don't bother if we are already at the left edge. - if self.offset == 0 { return; } + if self.offset == 0 { + return; + } - let new_position = Position{ line: self.line, offset: self.offset-1 }; + let new_position = Position { + line: self.line, + offset: self.offset - 1, + }; self.move_to(new_position); } /// Increments the cursor offset. The location is bounds-checked against /// the data and the cursor will not be updated if it is out-of-bounds. pub fn move_right(&mut self) { - let new_position = Position{ line: self.line, offset: self.offset+1 }; + let new_position = Position { + line: self.line, + offset: self.offset + 1, + }; self.move_to(new_position); } /// Sets the cursor offset to 0: the start of the current line. pub fn move_to_start_of_line(&mut self) { - let new_position = Position{ line: self.line, offset: 0 }; + let new_position = Position { + line: self.line, + offset: 0, + }; self.move_to(new_position); } @@ -152,7 +177,10 @@ impl Cursor { let data = self.data.borrow().to_string(); let current_line = data.lines().nth(self.line); if let Some(line) = current_line { - let new_position = Position{ line: self.line, offset: line.graphemes(true).count() }; + let new_position = Position { + line: self.line, + offset: line.graphemes(true).count(), + }; self.move_to(new_position); } } @@ -171,14 +199,19 @@ impl Cursor { } } - let target_position = - if length < self.sticky_offset { - // Current offset is beyond the last line's length; move to the end of it. - Position{ line, offset: length } - } else { - // Current offset is available on the last line; go there. - Position{ line, offset: self.sticky_offset } - }; + let target_position = if length < self.sticky_offset { + // Current offset is beyond the last line's length; move to the end of it. + Position { + line, + offset: length, + } + } else { + // Current offset is available on the last line; go there. + Position { + line, + offset: self.sticky_offset, + } + }; self.move_to(target_position); } @@ -194,14 +227,19 @@ impl Cursor { .map(|line| line.graphemes(true).count()) .unwrap_or(0); - let target_position = - if length < self.sticky_offset { - // Current offset is beyond the first line's length; move to the end of it. - Position{ line: 0, offset: length } - } else { - // Current offset is available on the first line; go there. - Position{ line: 0, offset: self.sticky_offset } - }; + let target_position = if length < self.sticky_offset { + // Current offset is beyond the first line's length; move to the end of it. + Position { + line: 0, + offset: length, + } + } else { + // Current offset is available on the first line; go there. + Position { + line: 0, + offset: self.sticky_offset, + } + }; self.move_to(target_position); } } @@ -209,13 +247,21 @@ impl Cursor { #[cfg(test)] mod tests { use crate::buffer::{Cursor, GapBuffer, Position}; - use std::rc::Rc; use std::cell::RefCell; + use std::rc::Rc; #[test] fn move_up_goes_to_eol_if_offset_would_be_out_of_range() { - let buffer = Rc::new(RefCell::new(GapBuffer::new("This is a test.\nAnother line that is longer.".to_string()))); - let mut cursor = Cursor::new(buffer, Position{ line: 1, offset: 20 }); + let buffer = Rc::new(RefCell::new(GapBuffer::new( + "This is a test.\nAnother line that is longer.".to_string(), + ))); + let mut cursor = Cursor::new( + buffer, + Position { + line: 1, + offset: 20, + }, + ); cursor.move_up(); assert_eq!(cursor.line, 0); assert_eq!(cursor.offset, 15); @@ -223,8 +269,16 @@ mod tests { #[test] fn move_down_goes_to_eol_if_offset_would_be_out_of_range() { - let buffer = Rc::new(RefCell::new(GapBuffer::new("Another line that is longer.\nThis is a test.".to_string()))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 20 }); + let buffer = Rc::new(RefCell::new(GapBuffer::new( + "Another line that is longer.\nThis is a test.".to_string(), + ))); + let mut cursor = Cursor::new( + buffer, + Position { + line: 0, + offset: 20, + }, + ); cursor.move_down(); assert_eq!(cursor.line, 1); assert_eq!(cursor.offset, 15); @@ -233,9 +287,15 @@ mod tests { #[test] fn move_up_counts_graphemes_as_a_single_offset() { let buffer = Rc::new(RefCell::new(GapBuffer::new( - "First नी\nSecond line".to_string() + "First नी\nSecond line".to_string(), ))); - let mut cursor = Cursor::new(buffer, Position{ line: 1, offset: 11 }); + let mut cursor = Cursor::new( + buffer, + Position { + line: 1, + offset: 11, + }, + ); cursor.move_up(); assert_eq!(cursor.line, 0); assert_eq!(cursor.offset, 7); @@ -244,9 +304,15 @@ mod tests { #[test] fn move_down_counts_graphemes_as_a_single_offset() { let buffer = Rc::new(RefCell::new(GapBuffer::new( - "First line\nSecond नी".to_string() + "First line\nSecond नी".to_string(), ))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 10 }); + let mut cursor = Cursor::new( + buffer, + Position { + line: 0, + offset: 10, + }, + ); cursor.move_down(); assert_eq!(cursor.line, 1); assert_eq!(cursor.offset, 8); @@ -255,9 +321,15 @@ mod tests { #[test] fn move_up_persists_offset_across_shorter_lines() { let buffer = Rc::new(RefCell::new(GapBuffer::new( - "First line that is longer.\nThis is a test.\nAnother line that is longer.".to_string() + "First line that is longer.\nThis is a test.\nAnother line that is longer.".to_string(), ))); - let mut cursor = Cursor::new(buffer, Position{ line: 2, offset: 20 }); + let mut cursor = Cursor::new( + buffer, + Position { + line: 2, + offset: 20, + }, + ); cursor.move_up(); cursor.move_up(); assert_eq!(cursor.line, 0); @@ -267,9 +339,15 @@ mod tests { #[test] fn move_down_persists_offset_across_shorter_lines() { let buffer = Rc::new(RefCell::new(GapBuffer::new( - "First line that is longer.\nThis is a test.\nAnother line that is longer.".to_string() + "First line that is longer.\nThis is a test.\nAnother line that is longer.".to_string(), ))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 20 }); + let mut cursor = Cursor::new( + buffer, + Position { + line: 0, + offset: 20, + }, + ); cursor.move_down(); cursor.move_down(); assert_eq!(cursor.line, 2); @@ -279,10 +357,16 @@ mod tests { #[test] fn move_to_sets_persisted_offset() { let buffer = Rc::new(RefCell::new(GapBuffer::new( - "First line that is longer.\nThis is a test.\nAnother line that is longer.".to_string() + "First line that is longer.\nThis is a test.\nAnother line that is longer.".to_string(), ))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 20 }); - cursor.move_to(Position{ line: 1, offset: 5 }); + let mut cursor = Cursor::new( + buffer, + Position { + line: 0, + offset: 20, + }, + ); + cursor.move_to(Position { line: 1, offset: 5 }); cursor.move_down(); assert_eq!(cursor.line, 2); assert_eq!(cursor.offset, 5); @@ -290,8 +374,10 @@ mod tests { #[test] fn move_to_start_of_line_sets_offset_to_zero() { - let buffer = Rc::new(RefCell::new(GapBuffer::new("This is a test.\nAnother line.".to_string()))); - let mut cursor = Cursor::new(buffer, Position{ line: 1, offset: 5 }); + let buffer = Rc::new(RefCell::new(GapBuffer::new( + "This is a test.\nAnother line.".to_string(), + ))); + let mut cursor = Cursor::new(buffer, Position { line: 1, offset: 5 }); cursor.move_to_start_of_line(); assert_eq!(cursor.line, 1); assert_eq!(cursor.offset, 0); @@ -299,10 +385,8 @@ mod tests { #[test] fn move_to_end_of_line_counts_graphemes_as_a_single_offset() { - let buffer = Rc::new(RefCell::new(GapBuffer::new( - "First नी".to_string() - ))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 0 }); + let buffer = Rc::new(RefCell::new(GapBuffer::new("First नी".to_string()))); + let mut cursor = Cursor::new(buffer, Position { line: 0, offset: 0 }); cursor.move_to_end_of_line(); assert_eq!(cursor.line, 0); assert_eq!(cursor.offset, 7); @@ -310,8 +394,10 @@ mod tests { #[test] fn move_to_end_of_line_sets_offset_the_line_length() { - let buffer = Rc::new(RefCell::new(GapBuffer::new("This is a test.\nAnother line.".to_string()))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 5 }); + let buffer = Rc::new(RefCell::new(GapBuffer::new( + "This is a test.\nAnother line.".to_string(), + ))); + let mut cursor = Cursor::new(buffer, Position { line: 0, offset: 5 }); cursor.move_to_end_of_line(); assert_eq!(cursor.line, 0); assert_eq!(cursor.offset, 15); @@ -320,7 +406,7 @@ mod tests { #[test] fn move_up_does_nothing_if_at_the_start_of_line() { let buffer = Rc::new(RefCell::new(GapBuffer::new("This is a test.".to_string()))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 0 }); + let mut cursor = Cursor::new(buffer, Position { line: 0, offset: 0 }); cursor.move_up(); assert_eq!(cursor.line, 0); assert_eq!(cursor.offset, 0); @@ -329,7 +415,7 @@ mod tests { #[test] fn move_left_does_nothing_if_at_the_start_of_line() { let buffer = Rc::new(RefCell::new(GapBuffer::new("This is a test.".to_string()))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 0 }); + let mut cursor = Cursor::new(buffer, Position { line: 0, offset: 0 }); cursor.move_left(); assert_eq!(cursor.line, 0); assert_eq!(cursor.offset, 0); @@ -338,9 +424,15 @@ mod tests { #[test] fn move_to_last_line_counts_graphemes_as_a_single_offset() { let buffer = Rc::new(RefCell::new(GapBuffer::new( - "First line\nLast नी".to_string() + "First line\nLast नी".to_string(), ))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 10 }); + let mut cursor = Cursor::new( + buffer, + Position { + line: 0, + offset: 10, + }, + ); cursor.move_to_last_line(); assert_eq!(cursor.line, 1); assert_eq!(cursor.offset, 6); @@ -348,8 +440,10 @@ mod tests { #[test] fn move_to_last_line_moves_to_same_offset_on_last_line() { - let buffer = Rc::new(RefCell::new(GapBuffer::new("first\nsecond\nlast".to_string()))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 2 }); + let buffer = Rc::new(RefCell::new(GapBuffer::new( + "first\nsecond\nlast".to_string(), + ))); + let mut cursor = Cursor::new(buffer, Position { line: 0, offset: 2 }); cursor.move_to_last_line(); assert_eq!(cursor.line, 2); assert_eq!(cursor.offset, 2); @@ -357,8 +451,10 @@ mod tests { #[test] fn move_to_last_line_moves_to_end_of_last_line_if_offset_would_be_out_of_range() { - let buffer = Rc::new(RefCell::new(GapBuffer::new("first\nsecond\nlast".to_string()))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 5 }); + let buffer = Rc::new(RefCell::new(GapBuffer::new( + "first\nsecond\nlast".to_string(), + ))); + let mut cursor = Cursor::new(buffer, Position { line: 0, offset: 5 }); cursor.move_to_last_line(); assert_eq!(cursor.line, 2); assert_eq!(cursor.offset, 4); @@ -366,8 +462,10 @@ mod tests { #[test] fn move_to_last_line_moves_last_line_when_it_is_a_trailing_newline() { - let buffer = Rc::new(RefCell::new(GapBuffer::new("first\nsecond\nlast\n".to_string()))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 2 }); + let buffer = Rc::new(RefCell::new(GapBuffer::new( + "first\nsecond\nlast\n".to_string(), + ))); + let mut cursor = Cursor::new(buffer, Position { line: 0, offset: 2 }); cursor.move_to_last_line(); assert_eq!(cursor.line, 3); assert_eq!(cursor.offset, 0); @@ -376,9 +474,9 @@ mod tests { #[test] fn move_to_first_line_counts_graphemes_as_a_single_offset() { let buffer = Rc::new(RefCell::new(GapBuffer::new( - "First नी\nLast line".to_string() + "First नी\nLast line".to_string(), ))); - let mut cursor = Cursor::new(buffer, Position{ line: 0, offset: 9 }); + let mut cursor = Cursor::new(buffer, Position { line: 0, offset: 9 }); cursor.move_to_first_line(); assert_eq!(cursor.line, 0); assert_eq!(cursor.offset, 7); @@ -386,8 +484,10 @@ mod tests { #[test] fn move_to_first_line_moves_to_same_offset_on_first_line() { - let buffer = Rc::new(RefCell::new(GapBuffer::new("first\nsecond\nlast".to_string()))); - let mut cursor = Cursor::new(buffer, Position{ line: 1, offset: 2 }); + let buffer = Rc::new(RefCell::new(GapBuffer::new( + "first\nsecond\nlast".to_string(), + ))); + let mut cursor = Cursor::new(buffer, Position { line: 1, offset: 2 }); cursor.move_to_first_line(); assert_eq!(cursor.line, 0); assert_eq!(cursor.offset, 2); @@ -395,8 +495,10 @@ mod tests { #[test] fn move_to_first_line_moves_to_end_of_first_line_if_offset_would_be_out_of_range() { - let buffer = Rc::new(RefCell::new(GapBuffer::new("first\nsecond\nlast".to_string()))); - let mut cursor = Cursor::new(buffer, Position{ line: 1, offset: 6 }); + let buffer = Rc::new(RefCell::new(GapBuffer::new( + "first\nsecond\nlast".to_string(), + ))); + let mut cursor = Cursor::new(buffer, Position { line: 1, offset: 6 }); cursor.move_to_first_line(); assert_eq!(cursor.line, 0); assert_eq!(cursor.offset, 5); diff --git a/src/buffer/distance.rs b/src/buffer/distance.rs index ae40f8d..bf20d9a 100644 --- a/src/buffer/distance.rs +++ b/src/buffer/distance.rs @@ -23,9 +23,9 @@ impl Distance { /// }); /// ``` pub fn of_str(from: &str) -> Distance { - Distance{ + Distance { lines: from.chars().filter(|&c| c == '\n').count(), - offset: from.split('\n').last().map(|l| l.len()).unwrap_or(0) + offset: from.split('\n').last().map(|l| l.len()).unwrap_or(0), } } } @@ -36,17 +36,23 @@ mod tests { #[test] fn of_str_works_with_a_single_line_of_data() { - assert_eq!(Distance::of_str("line"), Distance{ - lines: 0, - offset: 4 - }); + assert_eq!( + Distance::of_str("line"), + Distance { + lines: 0, + offset: 4 + } + ); } #[test] fn of_str_works_with_a_trailing_newline() { - assert_eq!(Distance::of_str("trailing newline\n"), Distance{ - lines: 1, - offset: 0 - }); + assert_eq!( + Distance::of_str("trailing newline\n"), + Distance { + lines: 1, + offset: 0 + } + ); } } diff --git a/src/buffer/gap_buffer.rs b/src/buffer/gap_buffer.rs index 537210f..51885c5 100644 --- a/src/buffer/gap_buffer.rs +++ b/src/buffer/gap_buffer.rs @@ -35,7 +35,11 @@ impl GapBuffer { bytes.set_len(capacity); } - GapBuffer{ data: bytes, gap_start, gap_length } + GapBuffer { + data: bytes, + gap_start, + gap_length, + } } /// Inserts the specified data into the buffer at the specified position. @@ -112,7 +116,7 @@ impl GapBuffer { // The gap is in the middle of the range being requested. // Stitch the surrounding halves together to exclude it. let first_half = &self.data[start_offset..self.gap_start]; - let second_half = &self.data[self.gap_start+self.gap_length..end_offset]; + let second_half = &self.data[self.gap_start + self.gap_length..end_offset]; // Allocate a string for the first half. let mut data = String::from_utf8_lossy(first_half).into_owned(); @@ -156,18 +160,21 @@ impl GapBuffer { Some(offset) => { // Widen the gap to cover the deleted contents. self.gap_length = offset - self.gap_start; - }, + } None => { // The end of the range doesn't exist; check // if it's on the last line in the file. - let start_of_next_line = Position{ line: range.end().line + 1, offset: 0 }; + let start_of_next_line = Position { + line: range.end().line + 1, + offset: 0, + }; match self.find_offset(&start_of_next_line) { Some(offset) => { // There are other lines below this range. // Just remove up until the end of the line. self.gap_length = offset - self.gap_start; - }, + } None => { // We're on the last line, just get rid of the rest // by extending the gap right to the end of the buffer. @@ -210,21 +217,21 @@ impl GapBuffer { // Advance the line and offset characters. if grapheme == "\n" { - line+=1; + line += 1; line_offset = 0; } else { - line_offset+=1; + line_offset += 1; } } // We didn't find the position *within* the first half, but it could // be right after it, which means it's right at the start of the gap. if line == position.line && line_offset == position.offset { - return Some(self.gap_start+self.gap_length); + return Some(self.gap_start + self.gap_length); } // We haven't reached the position yet, so we'll move on to the other half. - let second_half = String::from_utf8_lossy(&self.data[self.gap_start+self.gap_length..]); + let second_half = String::from_utf8_lossy(&self.data[self.gap_start + self.gap_length..]); for (offset, grapheme) in (*second_half).grapheme_indices(true) { // Check to see if we've found the position yet. if line == position.line && line_offset == position.offset { @@ -233,10 +240,10 @@ impl GapBuffer { // Advance the line and offset characters. if grapheme == "\n" { - line+=1; + line += 1; line_offset = 0; } else { - line_offset+=1; + line_offset += 1; } } @@ -265,18 +272,18 @@ impl GapBuffer { } self.gap_start = offset; - }, + } Ordering::Greater => { // Shift the gap to the right one byte at a time. for index in self.gap_start + self.gap_length..offset { - self.data[index-self.gap_length] = self.data[index]; + self.data[index - self.gap_length] = self.data[index]; self.data[index] = 0; } // Because the offset was after the gap, its value included the // gap length. We must remove it to determine the starting point. self.gap_start = offset - self.gap_length; - }, + } Ordering::Equal => (), // already at requested offset; NOP } } @@ -284,8 +291,8 @@ impl GapBuffer { fn write_to_gap(&mut self, data: &str) { for byte in data.bytes() { self.data[self.gap_start] = byte; - self.gap_start+=1; - self.gap_length-=1; + self.gap_start += 1; + self.gap_length -= 1; } } } @@ -293,7 +300,7 @@ impl GapBuffer { impl fmt::Display for GapBuffer { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let first_half = String::from_utf8_lossy(&self.data[..self.gap_start]); - let second_half = String::from_utf8_lossy(&self.data[self.gap_start+self.gap_length..]); + let second_half = String::from_utf8_lossy(&self.data[self.gap_start + self.gap_length..]); write!(f, "{}{}", first_half, second_half) } @@ -340,7 +347,13 @@ mod tests { #[test] fn inserting_at_the_end_works() { let mut gb = GapBuffer::new("This is a test.".to_string()); - gb.insert(" Seriously.", &Position { line: 0, offset: 15 }); + gb.insert( + " Seriously.", + &Position { + line: 0, + offset: 15, + }, + ); assert_eq!(gb.to_string(), "This is a test. Seriously."); } @@ -348,29 +361,41 @@ mod tests { fn inserting_in_different_spots_twice_works() { let mut gb = GapBuffer::new("This is a test.".to_string()); gb.insert("Hi. ", &Position { line: 0, offset: 0 }); - gb.insert(" Thank you.", &Position { line: 0, offset: 19 }); + gb.insert( + " Thank you.", + &Position { + line: 0, + offset: 19, + }, + ); assert_eq!(gb.to_string(), "Hi. This is a test. Thank you."); } #[test] fn inserting_at_an_invalid_position_does_nothing() { let mut gb = GapBuffer::new("This is a test.".to_string()); - gb.insert(" Seriously.", &Position { line: 0, offset: 35 }); + gb.insert( + " Seriously.", + &Position { + line: 0, + offset: 35, + }, + ); assert_eq!(gb.to_string(), "This is a test."); } #[test] fn inserting_after_a_grapheme_cluster_works() { let mut gb = GapBuffer::new("scribe नी".to_string()); - gb.insert(" library", &Position{ line : 0, offset: 8 }); + gb.insert(" library", &Position { line: 0, offset: 8 }); assert_eq!(gb.to_string(), "scribe नी library"); } #[test] fn deleting_works() { let mut gb = GapBuffer::new("This is a test.\nSee what happens.".to_string()); - let start = Position{ line: 0, offset: 8 }; - let end = Position{ line: 1, offset: 4 }; + let start = Position { line: 0, offset: 8 }; + let end = Position { line: 1, offset: 4 }; gb.delete(&Range::new(start, end)); assert_eq!(gb.to_string(), "This is what happens."); } @@ -378,9 +403,9 @@ mod tests { #[test] fn inserting_then_deleting_at_the_start_works() { let mut gb = GapBuffer::new(String::new()); - gb.insert("This is a test.", &Position{ line: 0, offset: 0}); - let start = Position{ line: 0, offset: 0 }; - let end = Position{ line: 0, offset: 1 }; + gb.insert("This is a test.", &Position { line: 0, offset: 0 }); + let start = Position { line: 0, offset: 0 }; + let end = Position { line: 0, offset: 1 }; gb.delete(&Range::new(start, end)); assert_eq!(gb.to_string(), "his is a test."); } @@ -388,14 +413,17 @@ mod tests { #[test] fn deleting_immediately_after_the_end_of_the_gap_widens_the_gap() { let mut gb = GapBuffer::new("This is a test.".to_string()); - let mut start = Position{ line: 0, offset: 8 }; - let mut end = Position{ line: 0, offset: 9 }; + let mut start = Position { line: 0, offset: 8 }; + let mut end = Position { line: 0, offset: 9 }; gb.delete(&Range::new(start, end)); assert_eq!(gb.to_string(), "This is test."); assert_eq!(gb.gap_length, 1); - start = Position{ line: 0, offset: 9 }; - end = Position{ line: 0, offset: 10 }; + start = Position { line: 0, offset: 9 }; + end = Position { + line: 0, + offset: 10, + }; gb.delete(&Range::new(start, end)); assert_eq!(gb.to_string(), "This is est."); assert_eq!(gb.gap_length, 2); @@ -404,8 +432,11 @@ mod tests { #[test] fn deleting_to_an_out_of_range_line_deletes_to_the_end_of_the_buffer() { let mut gb = GapBuffer::new("scribe\nlibrary".to_string()); - let start = Position{ line: 0, offset: 6 }; - let end = Position{ line: 2, offset: 10 }; + let start = Position { line: 0, offset: 6 }; + let end = Position { + line: 2, + offset: 10, + }; gb.delete(&Range::new(start, end)); assert_eq!(gb.to_string(), "scribe"); } @@ -413,8 +444,11 @@ mod tests { #[test] fn deleting_to_an_out_of_range_column_deletes_to_the_end_of_the_buffer() { let mut gb = GapBuffer::new("scribe\nlibrary".to_string()); - let start = Position{ line: 0, offset: 0 }; - let end = Position{ line: 0, offset: 100 }; + let start = Position { line: 0, offset: 0 }; + let end = Position { + line: 0, + offset: 100, + }; gb.delete(&Range::new(start, end)); assert_eq!(gb.to_string(), "library"); } @@ -422,8 +456,11 @@ mod tests { #[test] fn deleting_after_a_grapheme_cluster_works() { let mut gb = GapBuffer::new("scribe नी library".to_string()); - let start = Position{ line: 0, offset: 8 }; - let end = Position{ line: 0, offset: 16 }; + let start = Position { line: 0, offset: 8 }; + let end = Position { + line: 0, + offset: 16, + }; gb.delete(&Range::new(start, end)); assert_eq!(gb.to_string(), "scribe नी"); } @@ -433,8 +470,8 @@ mod tests { // Create a buffer and a range that captures the first character. let mut gb = GapBuffer::new("scribe".to_string()); let range = Range::new( - Position{ line: 0, offset: 0 }, - Position{ line: 0, offset: 1 } + Position { line: 0, offset: 0 }, + Position { line: 0, offset: 1 }, ); // Delete the first character, which will move the gap buffer to the start. @@ -452,15 +489,15 @@ mod tests { // Delete data from the middle of the buffer, which will move the gap there. gb.delete(&Range::new( - Position{ line: 0, offset: 2 }, - Position{ line: 0, offset: 4 } + Position { line: 0, offset: 2 }, + Position { line: 0, offset: 4 }, )); assert_eq!(gb.to_string(), "scbe"); // Request a range that extends from the start to the finish. let range = Range::new( - Position{ line: 0, offset: 0 }, - Position{ line: 0, offset: 4 } + Position { line: 0, offset: 0 }, + Position { line: 0, offset: 4 }, ); assert_eq!(gb.read(&range).unwrap(), "scbe"); } @@ -469,8 +506,11 @@ mod tests { fn reading_after_a_grapheme_cluster_works() { let gb = GapBuffer::new("scribe नी library".to_string()); let range = Range::new( - Position{ line: 0, offset: 8 }, - Position{ line: 0, offset: 16 } + Position { line: 0, offset: 8 }, + Position { + line: 0, + offset: 16, + }, ); assert_eq!(gb.read(&range).unwrap(), " library"); } @@ -478,8 +518,14 @@ mod tests { #[test] fn in_bounds_considers_grapheme_clusters() { let gb = GapBuffer::new("scribe नी library".to_string()); - let in_bounds = Position{ line: 0, offset: 16 }; - let out_of_bounds = Position{ line: 0, offset: 17 }; + let in_bounds = Position { + line: 0, + offset: 16, + }; + let out_of_bounds = Position { + line: 0, + offset: 17, + }; assert!(gb.in_bounds(&in_bounds)); assert!(!gb.in_bounds(&out_of_bounds)); } diff --git a/src/buffer/line_range.rs b/src/buffer/line_range.rs index 1944425..3031a46 100644 --- a/src/buffer/line_range.rs +++ b/src/buffer/line_range.rs @@ -4,7 +4,7 @@ use crate::buffer::{Position, Range}; #[derive(PartialEq, Debug)] pub struct LineRange { start: usize, - end: usize, + end: usize, } impl LineRange { @@ -12,9 +12,12 @@ impl LineRange { /// arguments in the event that the end precedes the start. pub fn new(start: usize, end: usize) -> LineRange { if start < end { - LineRange{ start, end } + LineRange { start, end } } else { - LineRange{ start: end, end: start } + LineRange { + start: end, + end: start, + } } } @@ -44,8 +47,14 @@ impl LineRange { /// ``` pub fn to_range(&self) -> Range { Range::new( - Position{ line: self.start, offset: 0 }, - Position{ line: self.end, offset:0 } + Position { + line: self.start, + offset: 0, + }, + Position { + line: self.end, + offset: 0, + }, ) } @@ -68,8 +77,14 @@ impl LineRange { /// ``` pub fn to_inclusive_range(&self) -> Range { Range::new( - Position{ line: self.start, offset: 0 }, - Position{ line: self.end+1, offset:0 } + Position { + line: self.start, + offset: 0, + }, + Position { + line: self.end + 1, + offset: 0, + }, ) } diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 3bd4799..8bac585 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -1,28 +1,29 @@ //! Types related to in-memory buffers. // Published API -pub use self::gap_buffer::GapBuffer; pub use self::distance::Distance; +pub use self::gap_buffer::GapBuffer; +pub use self::cursor::Cursor; +pub use self::line_range::LineRange; pub use self::position::Position; pub use self::range::Range; -pub use self::line_range::LineRange; -pub use self::cursor::Cursor; pub use self::token::{Lexeme, Token, TokenSet}; pub use syntect::parsing::{Scope, ScopeStack}; // Child modules -mod gap_buffer; +mod cursor; mod distance; -mod position; -mod range; +mod gap_buffer; mod line_range; -mod cursor; mod operation; +mod position; +mod range; mod token; // Buffer type implementation -use std::rc::Rc; +use self::operation::history::History; +use self::operation::{Operation, OperationGroup}; use std::cell::RefCell; use std::default::Default; use std::fs::File; @@ -31,8 +32,7 @@ use std::io::{Read, Write}; use std::mem; use std::ops::Fn; use std::path::{Path, PathBuf}; -use self::operation::{Operation, OperationGroup}; -use self::operation::history::History; +use std::rc::Rc; use syntect::parsing::SyntaxReference; /// A feature-rich wrapper around an underlying gap buffer. @@ -60,11 +60,11 @@ pub struct Buffer { impl Default for Buffer { fn default() -> Self { let data = Rc::new(RefCell::new(GapBuffer::new(String::new()))); - let cursor = Cursor::new(data.clone(), Position{ line: 0, offset: 0 }); + let cursor = Cursor::new(data.clone(), Position { line: 0, offset: 0 }); let mut history = History::new(); history.mark(); - Buffer{ + Buffer { id: None, data: data.clone(), path: None, @@ -119,10 +119,10 @@ impl Buffer { file.read_to_string(&mut data)?; let data = Rc::new(RefCell::new(GapBuffer::new(data))); - let cursor = Cursor::new(data.clone(), Position{ line: 0, offset: 0 }); + let cursor = Cursor::new(data.clone(), Position { line: 0, offset: 0 }); // Create a new buffer using the loaded data, path, and other defaults. - let mut buffer = Buffer{ + let mut buffer = Buffer { id: None, data: data.clone(), path: Some(path.canonicalize()?), @@ -183,12 +183,11 @@ impl Buffer { /// ``` pub fn save(&mut self) -> io::Result<()> { // Try to open and write to the file, returning any errors encountered. - let mut file = - if let Some(ref path) = self.path { - File::create(path)? - } else { - File::create(PathBuf::new())? - }; + let mut file = if let Some(ref path) = self.path { + File::create(path)? + } else { + File::create(PathBuf::new())? + }; // We use to_string here because we don't want to write the gap contents. file.write_all(self.data().to_string().as_bytes())?; @@ -215,13 +214,11 @@ impl Buffer { /// ``` pub fn file_name(&self) -> Option { self.path.as_ref().and_then(|p| { - p.file_name().and_then(|f| { - f.to_str().map(|s| s.to_string()) - }) + p.file_name() + .and_then(|f| f.to_str().map(|s| s.to_string())) }) } - /// Reverses the last modification to the buffer. /// /// # Examples @@ -339,13 +336,10 @@ impl Buffer { let haystack = &data[offset..]; // Check haystack length before slicing it and comparing bytes with needle. - if haystack.len() >= needle.len() && needle.as_bytes() == &haystack.as_bytes()[..needle.len()] { - results.push( - Position{ - line, - offset - } - ); + if haystack.len() >= needle.len() + && needle.as_bytes() == &haystack.as_bytes()[..needle.len()] + { + results.push(Position { line, offset }); } } } @@ -433,9 +427,12 @@ impl Buffer { // Try to retain cursor position or line. if !self.cursor.move_to(*buf.cursor) { - self.cursor.move_to(Position{ line: buf.cursor.line, offset: 0 }); + self.cursor.move_to(Position { + line: buf.cursor.line, + offset: 0, + }); } - }, + } Err(e) => return Err(e), } } @@ -470,7 +467,9 @@ impl Buffer { pub fn file_extension(&self) -> Option { self.path.as_ref().and_then(|p| { p.extension().and_then(|e| { - if !e.is_empty() { return Some(e.to_string_lossy().into_owned()) } + if !e.is_empty() { + return Some(e.to_string_lossy().into_owned()); + } None }) @@ -481,11 +480,11 @@ impl Buffer { #[cfg(test)] mod tests { extern crate syntect; - use syntect::parsing::SyntaxSet; + use crate::buffer::{Buffer, Position}; use std::cell::RefCell; use std::path::Path; use std::rc::Rc; - use crate::buffer::{Buffer, Position}; + use syntect::parsing::SyntaxSet; #[test] fn reload_persists_id_and_syntax_definition() { @@ -565,7 +564,7 @@ mod tests { buffer.insert("amp\neditor"); // Create a non-zero position that we'll share with the callback. - let tracked_position = Rc::new(RefCell::new(Position{ line: 1, offset: 1 })); + let tracked_position = Rc::new(RefCell::new(Position { line: 1, offset: 1 })); let callback_position = tracked_position.clone(); // Set up the callback so that it updates the shared position. @@ -614,7 +613,7 @@ mod tests { buffer.insert("scribe"); assert_eq!("scribe", buffer.data()); - buffer.cursor.move_to(Position{ line: 0, offset: 0 }); + buffer.cursor.move_to(Position { line: 0, offset: 0 }); buffer.delete(); assert_eq!("cribe", buffer.data()); @@ -629,12 +628,15 @@ mod tests { // Run some operations in a group. buffer.start_operation_group(); buffer.insert("scribe"); - buffer.cursor.move_to(Position{ line: 0, offset: 6}); + buffer.cursor.move_to(Position { line: 0, offset: 6 }); buffer.insert(" library"); buffer.end_operation_group(); // Run an operation outside of the group. - buffer.cursor.move_to(Position{ line: 0, offset: 14}); + buffer.cursor.move_to(Position { + line: 0, + offset: 14, + }); buffer.insert(" test"); // Make sure the buffer looks okay. @@ -658,9 +660,12 @@ mod tests { // Run some operations in a group, without closing it. buffer.start_operation_group(); - buffer.cursor.move_to(Position{ line: 0, offset: 6}); + buffer.cursor.move_to(Position { line: 0, offset: 6 }); buffer.insert(" library"); - buffer.cursor.move_to(Position{ line: 0, offset: 14}); + buffer.cursor.move_to(Position { + line: 0, + offset: 14, + }); buffer.insert(" test"); // Make sure the buffer looks okay. diff --git a/src/buffer/operation/delete.rs b/src/buffer/operation/delete.rs index 083de29..4b5fec3 100644 --- a/src/buffer/operation/delete.rs +++ b/src/buffer/operation/delete.rs @@ -32,7 +32,10 @@ impl Operation for Delete { fn reverse(&mut self, buffer: &mut Buffer) { if let Some(ref content) = self.content { - buffer.data.borrow_mut().insert(content, &self.range.start()); + buffer + .data + .borrow_mut() + .insert(content, &self.range.start()); // Run the change callback, if present. if let Some(ref callback) = buffer.change_callback { @@ -49,7 +52,10 @@ impl Operation for Delete { impl Delete { /// Creates a new empty delete operation. pub fn new(range: Range) -> Delete { - Delete{ content: None, range } + Delete { + content: None, + range, + } } } @@ -71,7 +77,10 @@ impl Buffer { pub fn delete(&mut self) { // We need to specify a range to delete, so start at // the current offset and delete the character to the right. - let mut end = Position{ line: self.cursor.line, offset: self.cursor.offset + 1 }; + let mut end = Position { + line: self.cursor.line, + offset: self.cursor.offset + 1, + }; // If there isn't a character to the right, // delete the newline by jumping to the start @@ -127,11 +136,11 @@ impl Buffer { #[cfg(test)] mod tests { - use std::cell::RefCell; - use std::rc::Rc; use super::Delete; - use crate::buffer::{Buffer, Position, Range}; use crate::buffer::operation::Operation; + use crate::buffer::{Buffer, Position, Range}; + use std::cell::RefCell; + use std::rc::Rc; #[test] fn run_and_reverse_remove_and_add_content_without_newlines_at_cursor_position() { @@ -140,8 +149,11 @@ mod tests { buffer.insert("something else"); // Set up a range that covers everything after the first word. - let start = Position{ line: 0, offset: 9 }; - let end = Position{ line: 0, offset: 14 }; + let start = Position { line: 0, offset: 9 }; + let end = Position { + line: 0, + offset: 14, + }; let delete_range = Range::new(start, end); // Create the delete operation and run it. @@ -162,8 +174,11 @@ mod tests { buffer.insert("\n something\n else\n entirely"); // Set up a range that covers everything after the first word. - let start = Position{ line: 1, offset: 10 }; - let end = Position{ line: 3, offset: 9 }; + let start = Position { + line: 1, + offset: 10, + }; + let end = Position { line: 3, offset: 9 }; let delete_range = Range::new(start, end); // Create the delete operation and run it. @@ -187,8 +202,11 @@ mod tests { buffer.insert("something else"); // Set up a range that covers everything after the first word. - let start = Position{ line: 0, offset: 9 }; - let end = Position{ line: 0, offset: 14 }; + let start = Position { line: 0, offset: 9 }; + let end = Position { + line: 0, + offset: 14, + }; let delete_range = Range::new(start, end); // Create a position that we'll share with the callback. @@ -205,7 +223,7 @@ mod tests { delete_operation.run(&mut buffer); // Verify that the callback received the correct position. - assert_eq!(*tracked_position.borrow(), Position{ line: 0, offset: 9}); + assert_eq!(*tracked_position.borrow(), Position { line: 0, offset: 9 }); } #[test] @@ -215,8 +233,11 @@ mod tests { buffer.insert("something else"); // Set up a range that covers everything after the first word. - let start = Position{ line: 0, offset: 9 }; - let end = Position{ line: 0, offset: 14 }; + let start = Position { line: 0, offset: 9 }; + let end = Position { + line: 0, + offset: 14, + }; let delete_range = Range::new(start, end); // Create the delete operation and run it. @@ -236,6 +257,6 @@ mod tests { delete_operation.reverse(&mut buffer); // Verify that the callback received the correct position. - assert_eq!(*tracked_position.borrow(), Position{ line: 0, offset: 9}); + assert_eq!(*tracked_position.borrow(), Position { line: 0, offset: 9 }); } } diff --git a/src/buffer/operation/group.rs b/src/buffer/operation/group.rs index 3185084..c3e7e27 100644 --- a/src/buffer/operation/group.rs +++ b/src/buffer/operation/group.rs @@ -33,8 +33,12 @@ impl Operation for OperationGroup { /// Build a new operation group by manually cloning all of the groups individual operations. /// We can't derive this because operations are unsized and need some hand holding. fn clone_operation(&self) -> Box { - Box::new(OperationGroup{ - operations: self.operations.iter().map(|o| (*o).clone_operation()).collect() + Box::new(OperationGroup { + operations: self + .operations + .iter() + .map(|o| (*o).clone_operation()) + .collect(), }) } } @@ -42,7 +46,9 @@ impl Operation for OperationGroup { impl OperationGroup { /// Creates a new empty operation group. pub fn new() -> OperationGroup { - OperationGroup{ operations: Vec::new() } + OperationGroup { + operations: Vec::new(), + } } /// Adds an operation to the group. @@ -86,9 +92,9 @@ impl Buffer { #[cfg(test)] mod tests { use super::OperationGroup; - use crate::buffer::{Buffer, Position}; - use crate::buffer::operation::Operation; use crate::buffer::operation::insert::Insert; + use crate::buffer::operation::Operation; + use crate::buffer::{Buffer, Position}; #[test] fn run_and_reverse_call_themselves_on_all_operations() { @@ -96,8 +102,14 @@ mod tests { let mut buffer = Buffer::new(); // Push two insert operations into the group. - let first = Box::new(Insert::new("something".to_string(), Position{ line: 0, offset: 0 })); - let second = Box::new(Insert::new(" else".to_string(), Position{ line: 0, offset: 9 })); + let first = Box::new(Insert::new( + "something".to_string(), + Position { line: 0, offset: 0 }, + )); + let second = Box::new(Insert::new( + " else".to_string(), + Position { line: 0, offset: 9 }, + )); group.add(first); group.add(second); diff --git a/src/buffer/operation/history.rs b/src/buffer/operation/history.rs index 6843bce..288199b 100644 --- a/src/buffer/operation/history.rs +++ b/src/buffer/operation/history.rs @@ -8,16 +8,16 @@ use crate::buffer::operation::Operation; pub struct History { previous: Vec>, next: Vec>, - marked_position: Option + marked_position: Option, } impl History { /// Creates a new empty operation history. pub fn new() -> History { - History{ + History { previous: Vec::new(), next: Vec::new(), - marked_position: None + marked_position: None, } } @@ -42,8 +42,8 @@ impl History { // clone of it so that it can be re-applied as a redo operation. self.next.push(operation.clone_operation()); Some(operation) - }, - None => None + } + None => None, } } @@ -55,8 +55,8 @@ impl History { // clone of it so that it can be re-applied as an undo operation, again. self.previous.push(operation.clone_operation()); Some(operation) - }, - None => None + } + None => None, } } @@ -76,9 +76,9 @@ impl History { #[cfg(test)] mod tests { use super::History; - use crate::buffer::{Buffer, Position}; - use crate::buffer::operation::Operation; use crate::buffer::operation::insert::Insert; + use crate::buffer::operation::Operation; + use crate::buffer::{Buffer, Position}; #[test] fn previous_and_next_return_the_correct_operations() { @@ -88,7 +88,7 @@ mod tests { let mut buffer = Buffer::new(); // Run an insert operation and add it to the history. - let insert_position = Position{ line: 0, offset: 0 }; + let insert_position = Position { line: 0, offset: 0 }; let mut insert_operation = Insert::new("scribe".to_string(), insert_position); insert_operation.run(&mut buffer); history.add(Box::new(insert_operation)); @@ -130,7 +130,7 @@ mod tests { let mut history = History::new(); // Add an insert operation to the history. - let insert_position = Position{ line: 0, offset: 0 }; + let insert_position = Position { line: 0, offset: 0 }; let insert_operation = Insert::new("scribe".to_string(), insert_position); history.add(Box::new(insert_operation)); @@ -160,7 +160,7 @@ mod tests { history.mark(); // Add an insert operation to the history. - let insert_position = Position{ line: 0, offset: 0 }; + let insert_position = Position { line: 0, offset: 0 }; let insert_operation = Insert::new("scribe".to_string(), insert_position); history.add(Box::new(insert_operation)); @@ -173,7 +173,7 @@ mod tests { history.mark(); // Add an insert operation to the history. - let insert_position = Position{ line: 0, offset: 0 }; + let insert_position = Position { line: 0, offset: 0 }; let insert_operation = Insert::new("scribe".to_string(), insert_position); history.add(Box::new(insert_operation)); @@ -188,7 +188,7 @@ mod tests { let mut history = History::new(); // Add an insert operation to the history. - let insert_position = Position{ line: 0, offset: 0 }; + let insert_position = Position { line: 0, offset: 0 }; let insert_operation = Insert::new("scribe".to_string(), insert_position); history.add(Box::new(insert_operation)); @@ -209,7 +209,7 @@ mod tests { let mut history = History::new(); // Add an insert operation to the history. - let mut insert_position = Position{ line: 0, offset: 0 }; + let mut insert_position = Position { line: 0, offset: 0 }; let mut insert_operation = Insert::new("scribe".to_string(), insert_position); history.add(Box::new(insert_operation)); @@ -220,7 +220,7 @@ mod tests { history.previous(); // Add a replacement operation. - insert_position = Position{ line: 0, offset: 0 }; + insert_position = Position { line: 0, offset: 0 }; insert_operation = Insert::new("scribe".to_string(), insert_position); history.add(Box::new(insert_operation)); diff --git a/src/buffer/operation/insert.rs b/src/buffer/operation/insert.rs index a9d206d..17d707b 100644 --- a/src/buffer/operation/insert.rs +++ b/src/buffer/operation/insert.rs @@ -20,7 +20,10 @@ pub struct Insert { impl Operation for Insert { fn run(&mut self, buffer: &mut Buffer) { - buffer.data.borrow_mut().insert(&self.content, &self.position); + buffer + .data + .borrow_mut() + .insert(&self.content, &self.position); // Run the change callback, if present. if let Some(ref callback) = buffer.change_callback { @@ -52,14 +55,11 @@ impl Operation for Insert { // Now that we have the required info, // build the end position and total range. - let end_position = Position{ + let end_position = Position { line: end_line, offset: end_offset, }; - let range = Range::new( - self.position, - end_position - ); + let range = Range::new(self.position, end_position); // Remove the content we'd previously inserted. buffer.data.borrow_mut().delete(&range); @@ -78,7 +78,7 @@ impl Operation for Insert { impl Insert { /// Creates a new empty insert operation. pub fn new(content: String, position: Position) -> Insert { - Insert{ content, position } + Insert { content, position } } } @@ -110,12 +110,12 @@ impl Buffer { #[cfg(test)] mod tests { - use std::cell::RefCell; - use std::rc::Rc; use super::Insert; - use crate::buffer::Buffer; - use crate::buffer::position::Position; use crate::buffer::operation::Operation; + use crate::buffer::position::Position; + use crate::buffer::Buffer; + use std::cell::RefCell; + use std::rc::Rc; #[test] fn run_and_reverse_add_and_remove_content_without_newlines_at_cursor_position() { @@ -124,7 +124,7 @@ mod tests { buffer.insert("something"); // Set up a position pointing to the end of the buffer's contents. - let insert_position = Position{ line: 0, offset: 9 }; + let insert_position = Position { line: 0, offset: 9 }; // Create the insert operation and run it. let mut insert_operation = Insert::new(" else".to_string(), insert_position); @@ -144,7 +144,10 @@ mod tests { buffer.insert("\n something"); // Set up a position pointing to the end of the buffer's contents. - let insert_position = Position{ line: 1, offset: 10 }; + let insert_position = Position { + line: 1, + offset: 10, + }; // Create the insert operation and run it. // @@ -164,7 +167,7 @@ mod tests { fn reverse_removes_a_newline() { // Set up a buffer with some data. let mut buffer = Buffer::new(); - let mut insert_operation = Insert::new("\n".to_string(), Position{ line: 0, offset: 0 }); + let mut insert_operation = Insert::new("\n".to_string(), Position { line: 0, offset: 0 }); insert_operation.run(&mut buffer); assert_eq!(buffer.data(), "\n"); @@ -178,7 +181,8 @@ mod tests { let mut buffer = Buffer::new(); buffer.insert("scribe\nlibrary\n"); - let mut insert_operation = Insert::new("editor\n".to_string(), Position{ line: 1, offset: 0 }); + let mut insert_operation = + Insert::new("editor\n".to_string(), Position { line: 1, offset: 0 }); insert_operation.run(&mut buffer); assert_eq!(buffer.data(), "scribe\neditor\nlibrary\n"); @@ -192,7 +196,8 @@ mod tests { let mut buffer = Buffer::new(); buffer.insert("scribe\nlibrary"); - let mut insert_operation = Insert::new("नी editor ".to_string(), Position{ line: 1, offset: 0 }); + let mut insert_operation = + Insert::new("नी editor ".to_string(), Position { line: 1, offset: 0 }); insert_operation.run(&mut buffer); assert_eq!(buffer.data(), "scribe\nनी editor library"); @@ -206,7 +211,8 @@ mod tests { let mut buffer = Buffer::new(); buffer.insert("scribe\nlibrary"); - let mut insert_operation = Insert::new("\nनी editor".to_string(), Position{ line: 0, offset: 6 }); + let mut insert_operation = + Insert::new("\nनी editor".to_string(), Position { line: 0, offset: 6 }); insert_operation.run(&mut buffer); assert_eq!(buffer.data(), "scribe\nनी editor\nlibrary"); @@ -221,7 +227,7 @@ mod tests { buffer.insert("something"); // Set up a position pointing to the end of the buffer's contents. - let insert_position = Position{ line: 0, offset: 9 }; + let insert_position = Position { line: 0, offset: 9 }; // Create a position that we'll share with the callback. let tracked_position = Rc::new(RefCell::new(Position::new())); @@ -237,7 +243,7 @@ mod tests { insert_operation.run(&mut buffer); // Verify that the callback received the correct position. - assert_eq!(*tracked_position.borrow(), Position{ line: 0, offset: 9}); + assert_eq!(*tracked_position.borrow(), Position { line: 0, offset: 9 }); } #[test] @@ -247,7 +253,7 @@ mod tests { buffer.insert("something"); // Set up a position pointing to the end of the buffer's contents. - let insert_position = Position{ line: 0, offset: 9 }; + let insert_position = Position { line: 0, offset: 9 }; // Create the insert operation and run it. let mut insert_operation = Insert::new(" else".to_string(), insert_position); @@ -266,6 +272,6 @@ mod tests { insert_operation.reverse(&mut buffer); // Verify that the callback received the correct position. - assert_eq!(*tracked_position.borrow(), Position{ line: 0, offset: 9}); + assert_eq!(*tracked_position.borrow(), Position { line: 0, offset: 9 }); } } diff --git a/src/buffer/operation/mod.rs b/src/buffer/operation/mod.rs index 7abad60..86d9180 100644 --- a/src/buffer/operation/mod.rs +++ b/src/buffer/operation/mod.rs @@ -1,10 +1,10 @@ -use crate::buffer::Buffer; pub use self::group::OperationGroup; +use crate::buffer::Buffer; +mod delete; pub mod group; pub mod history; mod insert; -mod delete; /// A reversible buffer operation. /// diff --git a/src/buffer/position.rs b/src/buffer/position.rs index 6f08f4d..f0f804e 100644 --- a/src/buffer/position.rs +++ b/src/buffer/position.rs @@ -1,5 +1,5 @@ use crate::buffer::Distance; -use std::cmp::{PartialOrd, Ordering}; +use std::cmp::{Ordering, PartialOrd}; use std::default::Default; use std::ops::{Add, AddAssign}; @@ -9,25 +9,23 @@ use std::ops::{Add, AddAssign}; /// to avoid fencepost errors. #[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct Position { - pub line: usize, + pub line: usize, pub offset: usize, } impl PartialOrd for Position { fn partial_cmp(&self, other: &Position) -> Option { - Some( - if self.line < other.line { - Ordering::Less - } else if self.line > other.line { - Ordering::Greater - } else if self.offset < other.offset { - Ordering::Less - } else if self.offset > other.offset { - Ordering::Greater - } else { - Ordering::Equal - } - ) + Some(if self.line < other.line { + Ordering::Less + } else if self.line > other.line { + Ordering::Greater + } else if self.offset < other.offset { + Ordering::Less + } else if self.offset > other.offset { + Ordering::Greater + } else { + Ordering::Equal + }) } } @@ -35,16 +33,15 @@ impl Add for Position { type Output = Position; fn add(self, distance: Distance) -> Self::Output { - let offset = - if distance.lines > 0 { - distance.offset - } else { - self.offset + distance.offset - }; + let offset = if distance.lines > 0 { + distance.offset + } else { + self.offset + distance.offset + }; Position { line: self.line + distance.lines, - offset + offset, } } } @@ -52,12 +49,11 @@ impl Add for Position { impl AddAssign for Position { fn add_assign(&mut self, distance: Distance) { self.line += distance.lines; - self.offset = - if distance.lines > 0 { - distance.offset - } else { - self.offset + distance.offset - }; + self.offset = if distance.lines > 0 { + distance.offset + } else { + self.offset + distance.offset + }; } } @@ -87,24 +83,42 @@ mod tests { fn compare_works_when_lines_differ() { // Important to make the earlier position have a greater // offset, since that's an easy mistake to make. - let earlier_position = Position{ line: 2, offset: 20 }; - let later_position = Position{ line: 3, offset: 10}; + let earlier_position = Position { + line: 2, + offset: 20, + }; + let later_position = Position { + line: 3, + offset: 10, + }; assert!(earlier_position < later_position); } #[test] fn compare_works_when_lines_are_equal() { - let earlier_position = Position{ line: 3, offset: 10 }; - let later_position = Position{ line: 3, offset: 20}; + let earlier_position = Position { + line: 3, + offset: 10, + }; + let later_position = Position { + line: 3, + offset: 20, + }; assert!(earlier_position < later_position); } #[test] fn compare_works_when_lines_and_offsets_are_equal() { - let earlier_position = Position{ line: 3, offset: 10 }; - let later_position = Position{ line: 3, offset: 10}; + let earlier_position = Position { + line: 3, + offset: 10, + }; + let later_position = Position { + line: 3, + offset: 10, + }; assert!(earlier_position <= later_position); assert!(earlier_position >= later_position); @@ -117,13 +131,13 @@ mod tests { #[test] fn add_assign_works_with_zero_line_distance() { - let mut position = Position{ line: 1, offset: 3 }; - let distance = Distance{ lines: 0, offset: 4 }; + let mut position = Position { line: 1, offset: 3 }; + let distance = Distance { + lines: 0, + offset: 4, + }; position += distance; - assert_eq!(position, Position{ - line: 1, - offset: 7 - }); + assert_eq!(position, Position { line: 1, offset: 7 }); } } diff --git a/src/buffer/range.rs b/src/buffer/range.rs index 4963e5b..5774d99 100644 --- a/src/buffer/range.rs +++ b/src/buffer/range.rs @@ -4,7 +4,7 @@ use crate::buffer::Position; #[derive(Clone, Debug, PartialEq)] pub struct Range { start: Position, - end: Position, + end: Position, } impl Range { @@ -13,9 +13,12 @@ impl Range { pub fn new(start: Position, end: Position) -> Range { // Ensure that the end does not precede the start. if start > end { - Range{ start: end, end: start } + Range { + start: end, + end: start, + } } else { - Range{ start, end } + Range { start, end } } } @@ -60,8 +63,8 @@ impl Range { #[cfg(test)] mod tests { - use crate::buffer::Position; use super::Range; + use crate::buffer::Position; #[test] fn new_does_not_swap_values_if_end_does_not_precede_start() { diff --git a/src/buffer/token/mod.rs b/src/buffer/token/mod.rs index a6982a9..27af13c 100644 --- a/src/buffer/token/mod.rs +++ b/src/buffer/token/mod.rs @@ -10,7 +10,7 @@ use syntect::parsing::ScopeStack; #[derive(Debug, PartialEq)] pub enum Token<'a> { Newline, - Lexeme(Lexeme<'a>) + Lexeme(Lexeme<'a>), } #[derive(Debug, PartialEq)] diff --git a/src/buffer/token/token_iterator.rs b/src/buffer/token/token_iterator.rs index 8e62161..ad84584 100644 --- a/src/buffer/token/token_iterator.rs +++ b/src/buffer/token/token_iterator.rs @@ -14,21 +14,25 @@ pub struct TokenIterator<'a> { current_position: Position, line_events: Vec<(usize, ScopeStackOp)>, syntaxes: &'a SyntaxSet, - pub error: Option + pub error: Option, } impl<'a> TokenIterator<'a> { - pub fn new(data: &'a str, def: &'a SyntaxReference, syntaxes: &'a SyntaxSet) -> Result> { - let mut token_iterator = TokenIterator{ + pub fn new( + data: &'a str, + def: &'a SyntaxReference, + syntaxes: &'a SyntaxSet, + ) -> Result> { + let mut token_iterator = TokenIterator { scopes: ScopeStack::new(), parser: ParseState::new(def), lines: LineIterator::new(data), current_line: None, current_byte_offset: 0, - current_position: Position{ line: 0, offset: 0 }, + current_position: Position { line: 0, offset: 0 }, line_events: Vec::new(), syntaxes, - error: None + error: None, }; // Preload the first line @@ -88,18 +92,15 @@ impl<'a> TokenIterator<'a> { // Don't include trailing newlines in lexemes. let end_of_token = cmp::min(event_offset, end_of_line); - lexeme = Some( - Token::Lexeme(Lexeme{ - value: &line[self.current_byte_offset..end_of_token], - scope: self.scopes.clone(), - position: self.current_position, - }) - ); + lexeme = Some(Token::Lexeme(Lexeme { + value: &line[self.current_byte_offset..end_of_token], + scope: self.scopes.clone(), + position: self.current_position, + })); // The event/current offsets are byte-based, but // position offsets should be grapheme cluster-based. - self.current_position.offset += - line[self.current_byte_offset..end_of_token] + self.current_position.offset += line[self.current_byte_offset..end_of_token] .graphemes(true) .count(); @@ -110,18 +111,18 @@ impl<'a> TokenIterator<'a> { // that we can pair it with a token later on. self.scopes.apply(&scope_change)?; - if lexeme.is_some() { return Ok(lexeme) } + if lexeme.is_some() { + return Ok(lexeme); + } } // Categorize the rest of the line with the last known scope. if self.current_byte_offset < end_of_line { - lexeme = Some( - Token::Lexeme(Lexeme{ - value: &line[self.current_byte_offset..end_of_line], - scope: self.scopes.clone(), - position: self.current_position, - }) - ); + lexeme = Some(Token::Lexeme(Lexeme { + value: &line[self.current_byte_offset..end_of_line], + scope: self.scopes.clone(), + position: self.current_position, + })); } } @@ -143,7 +144,10 @@ impl<'a> TokenIterator<'a> { self.current_line = Some(line); // Track our position, which we'll pass to generated tokens. - self.current_position = Position{ line: line_number, offset: 0 }; + self.current_position = Position { + line: line_number, + offset: 0, + }; // Reset byte-based line offset. self.current_byte_offset = 0; @@ -173,97 +177,108 @@ mod tests { fn token_iterator_returns_correct_tokens() { let syntax_set = SyntaxSet::load_defaults_newlines(); let def = syntax_set.find_syntax_by_extension("rs"); - let iterator = TokenIterator::new("struct Buffer {\n// comment\n data: String\n}garbage\n\n", def.unwrap(), &syntax_set).unwrap(); + let iterator = TokenIterator::new( + "struct Buffer {\n// comment\n data: String\n}garbage\n\n", + def.unwrap(), + &syntax_set, + ) + .unwrap(); let mut scope_stack = ScopeStack::new(); let mut expected_tokens = Vec::new(); scope_stack.push(Scope::new("source.rust").unwrap()); scope_stack.push(Scope::new("meta.struct.rust").unwrap()); scope_stack.push(Scope::new("storage.type.struct.rust").unwrap()); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: "struct", scope: scope_stack.clone(), - position: Position{ line: 0, offset: 0 } + position: Position { line: 0, offset: 0 }, })); scope_stack.pop(); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: " ", scope: scope_stack.clone(), - position: Position{ line: 0, offset: 6 } + position: Position { line: 0, offset: 6 }, })); scope_stack.push(Scope::new("entity.name.struct.rust").unwrap()); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: "Buffer", scope: scope_stack.clone(), - position: Position{ line: 0, offset: 7 } + position: Position { line: 0, offset: 7 }, })); scope_stack.pop(); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: " ", scope: scope_stack.clone(), - position: Position{ line: 0, offset: 13 } + position: Position { + line: 0, + offset: 13, + }, })); scope_stack.push(Scope::new("meta.block.rust").unwrap()); scope_stack.push(Scope::new("punctuation.section.block.begin.rust").unwrap()); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: "{", scope: scope_stack.clone(), - position: Position{ line: 0, offset: 14 } + position: Position { + line: 0, + offset: 14, + }, })); expected_tokens.push(Token::Newline); scope_stack.pop(); scope_stack.push(Scope::new("comment.line.double-slash.rust").unwrap()); scope_stack.push(Scope::new("punctuation.definition.comment.rust").unwrap()); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: "//", scope: scope_stack.clone(), - position: Position{ line: 1, offset: 0 } + position: Position { line: 1, offset: 0 }, })); scope_stack.pop(); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: " comment", scope: scope_stack.clone(), - position: Position{ line: 1, offset: 2 } + position: Position { line: 1, offset: 2 }, })); expected_tokens.push(Token::Newline); scope_stack.pop(); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: " ", scope: scope_stack.clone(), - position: Position{ line: 2, offset: 0 } + position: Position { line: 2, offset: 0 }, })); scope_stack.push(Scope::new("variable.other.member.rust").unwrap()); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: "data", scope: scope_stack.clone(), - position: Position{ line: 2, offset: 2 } + position: Position { line: 2, offset: 2 }, })); scope_stack.pop(); scope_stack.push(Scope::new("punctuation.separator.rust").unwrap()); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: ":", scope: scope_stack.clone(), - position: Position{ line: 2, offset: 6 } + position: Position { line: 2, offset: 6 }, })); scope_stack.pop(); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: " String", scope: scope_stack.clone(), - position: Position{ line: 2, offset: 7 } + position: Position { line: 2, offset: 7 }, })); expected_tokens.push(Token::Newline); scope_stack.push(Scope::new("punctuation.section.block.end.rust").unwrap()); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: "}", scope: scope_stack.clone(), - position: Position{ line: 3, offset: 0 } + position: Position { line: 3, offset: 0 }, })); scope_stack.pop(); scope_stack.pop(); scope_stack.pop(); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: "garbage", scope: scope_stack.clone(), - position: Position{ line: 3, offset: 1 } + position: Position { line: 3, offset: 1 }, })); expected_tokens.push(Token::Newline); expected_tokens.push(Token::Newline); @@ -284,15 +299,11 @@ mod tests { let def = syntax_set.find_syntax_plain_text(); let iterator = TokenIterator::new("struct", def, &syntax_set).unwrap(); let mut expected_tokens = Vec::new(); - expected_tokens.push( - Token::Lexeme(Lexeme{ - value: "struct", - scope: ScopeStack::from_vec(vec![ - Scope::new("text.plain").unwrap(), - ]), - position: Position{ line: 0, offset: 0 } - }) - ); + expected_tokens.push(Token::Lexeme(Lexeme { + value: "struct", + scope: ScopeStack::from_vec(vec![Scope::new("text.plain").unwrap()]), + position: Position { line: 0, offset: 0 }, + })); let actual_tokens: Vec = iterator.collect(); for (index, token) in expected_tokens.into_iter().enumerate() { assert_eq!(token, actual_tokens[index]); @@ -309,16 +320,16 @@ mod tests { let mut scope_stack = ScopeStack::new(); let mut expected_tokens = Vec::new(); scope_stack.push(Scope::new("source.rust").unwrap()); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: "€", scope: scope_stack.clone(), - position: Position{ line: 0, offset: 0 } + position: Position { line: 0, offset: 0 }, })); scope_stack.push(Scope::new("constant.numeric.integer.decimal.rust").unwrap()); - expected_tokens.push(Token::Lexeme(Lexeme{ + expected_tokens.push(Token::Lexeme(Lexeme { value: "16", scope: scope_stack.clone(), - position: Position{ line: 0, offset: 1 } + position: Position { line: 0, offset: 1 }, })); let actual_tokens: Vec = iterator.collect(); diff --git a/src/buffer/token/token_set.rs b/src/buffer/token/token_set.rs index dab5a1b..23e2eae 100644 --- a/src/buffer/token/token_set.rs +++ b/src/buffer/token/token_set.rs @@ -5,15 +5,15 @@ use syntect::parsing::{SyntaxReference, SyntaxSet}; pub struct TokenSet<'a> { data: String, syntax_definition: &'a SyntaxReference, - syntaxes: &'a SyntaxSet + syntaxes: &'a SyntaxSet, } impl<'a> TokenSet<'a> { pub fn new(data: String, def: &'a SyntaxReference, syntaxes: &'a SyntaxSet) -> TokenSet<'a> { - TokenSet{ + TokenSet { data, syntax_definition: def, - syntaxes + syntaxes, } } diff --git a/src/errors.rs b/src/errors.rs index 4fa2ba4..b05a175 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,5 +1,3 @@ - - error_chain! { errors { EmptyWorkspace { diff --git a/src/lib.rs b/src/lib.rs index 1f13147..a236bed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,10 +9,10 @@ extern crate unicode_segmentation; extern crate error_chain; pub mod buffer; -pub mod util; mod errors; +pub mod util; mod workspace; -pub use crate::errors::*; pub use crate::buffer::Buffer; +pub use crate::errors::*; pub use crate::workspace::Workspace; diff --git a/src/util/line_iterator.rs b/src/util/line_iterator.rs index 22c7dbf..0659178 100644 --- a/src/util/line_iterator.rs +++ b/src/util/line_iterator.rs @@ -3,17 +3,17 @@ pub struct LineIterator<'a> { line_number: usize, line_start: usize, line_end: usize, - done: bool + done: bool, } impl<'a> LineIterator<'a> { pub fn new(data: &str) -> LineIterator { - LineIterator{ + LineIterator { data, line_number: 0, line_start: 0, line_end: 0, - done: false + done: false, } } @@ -27,7 +27,7 @@ impl<'a> Iterator for LineIterator<'a> { fn next(&mut self) -> Option { if self.done { - return None + return None; } // Move the range beyond its previous position. @@ -48,12 +48,7 @@ impl<'a> Iterator for LineIterator<'a> { } } - let line = Some(( - self.line_number, - &self.data[ - self.line_start..self.line_end - ] - )); + let line = Some((self.line_number, &self.data[self.line_start..self.line_end])); // Flag the iterator as done as soon as we've exhausted its data, // and have given one last line for data with a trailing newline. diff --git a/src/workspace.rs b/src/workspace.rs index ab7d7b3..5532fa8 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -31,13 +31,13 @@ impl Workspace { syntax_set = builder.build(); } - Ok(Workspace{ + Ok(Workspace { path: path.canonicalize()?, buffers: Vec::new(), next_buffer_id: 0, current_buffer: None, current_buffer_index: None, - syntax_set + syntax_set, }) } @@ -71,7 +71,7 @@ impl Workspace { self.next_buffer_id += 1; // The target index is directly after the current buffer's index. - let target_index = self.current_buffer_index.map(|i| i + 1 ).unwrap_or(0); + let target_index = self.current_buffer_index.map(|i| i + 1).unwrap_or(0); // Insert the buffer and select it. self.buffers.insert(target_index, buf); @@ -146,12 +146,11 @@ impl Workspace { /// assert_eq!(workspace.current_buffer_path(), Some(Path::new("file"))); /// ``` pub fn current_buffer_path(&self) -> Option<&Path> { - self.current_buffer.as_ref() - .and_then(|buf| buf.path.as_ref() - .and_then(|path| path.strip_prefix(&self.path).ok() - .or_else(|| Some(path)) - ) - ) + self.current_buffer.as_ref().and_then(|buf| { + buf.path + .as_ref() + .and_then(|path| path.strip_prefix(&self.path).ok().or_else(|| Some(path))) + }) } /// Removes the currently selected buffer from the collection. @@ -220,9 +219,9 @@ impl Workspace { pub fn previous_buffer(&mut self) { if let Some(index) = self.current_buffer_index { if index > 0 { - self.select_buffer(index-1); + self.select_buffer(index - 1); } else { - self.select_buffer(self.buffers.len()-1); + self.select_buffer(self.buffers.len() - 1); } } } @@ -254,10 +253,10 @@ impl Workspace { /// ``` pub fn next_buffer(&mut self) { if let Some(index) = self.current_buffer_index { - if index == self.buffers.len()-1 { + if index == self.buffers.len() - 1 { self.select_buffer(0); } else { - self.select_buffer(index+1); + self.select_buffer(index + 1); } } } @@ -295,11 +294,15 @@ impl Workspace { /// ); /// ``` pub fn current_buffer_tokens(&self) -> Result> { - let buf = self.current_buffer.as_ref().ok_or(ErrorKind::EmptyWorkspace)?; + let buf = self + .current_buffer + .as_ref() + .ok_or(ErrorKind::EmptyWorkspace)?; let data = buf.data(); - let syntax_definition = buf.syntax_definition.as_ref().ok_or( - ErrorKind::MissingSyntax - )?; + let syntax_definition = buf + .syntax_definition + .as_ref() + .ok_or(ErrorKind::MissingSyntax)?; Ok(TokenSet::new(data, syntax_definition, &self.syntax_set)) } @@ -347,12 +350,15 @@ impl Workspace { /// /// ``` pub fn update_current_syntax(&mut self) -> Result<()> { - let buffer = self.current_buffer.as_mut().ok_or(ErrorKind::EmptyWorkspace)?; - let definition = buffer.file_extension().and_then(|ex| { - self.syntax_set.find_syntax_by_extension(&ex) - }).or_else(|| { - Some(self.syntax_set.find_syntax_plain_text()) - }).cloned(); + let buffer = self + .current_buffer + .as_mut() + .ok_or(ErrorKind::EmptyWorkspace)?; + let definition = buffer + .file_extension() + .and_then(|ex| self.syntax_set.find_syntax_by_extension(&ex)) + .or_else(|| Some(self.syntax_set.find_syntax_plain_text())) + .cloned(); buffer.syntax_definition = definition; Ok(()) @@ -361,7 +367,10 @@ impl Workspace { fn select_buffer(&mut self, index: usize) -> bool { // Check-in current buffer, if it exists. if let Some(current_buffer) = self.current_buffer.as_mut() { - mem::swap(current_buffer, &mut self.buffers[self.current_buffer_index.unwrap()]); + mem::swap( + current_buffer, + &mut self.buffers[self.current_buffer_index.unwrap()], + ); } // Check-out buffer at provided index. @@ -384,13 +393,16 @@ impl Workspace { } // Look at other open buffers to see if one matches. - let index = self.buffers.iter().position(|buffer| { - buffer.path.as_ref() == Some(canonical_path) - }); + let index = self + .buffers + .iter() + .position(|buffer| buffer.path.as_ref() == Some(canonical_path)); // If we found a matching buffer, select it and propagate the // result of that operation. Otherwise, return false. - index.map(|index| self.select_buffer(index)).unwrap_or(false) + index + .map(|index| self.select_buffer(index)) + .unwrap_or(false) } else { false } @@ -401,8 +413,8 @@ impl Workspace { mod tests { use super::Workspace; use crate::buffer::Buffer; - use std::path::Path; use std::env; + use std::path::Path; #[test] fn add_buffer_adds_and_selects_the_passed_buffer() { @@ -461,11 +473,15 @@ mod tests { workspace.add_buffer(buf); let name = workspace - .current_buffer - .as_ref() - .and_then(|ref b| b.syntax_definition.as_ref().map(|sd| sd.name.clone())); - - assert!(workspace.current_buffer.unwrap().syntax_definition.is_some()); + .current_buffer + .as_ref() + .and_then(|ref b| b.syntax_definition.as_ref().map(|sd| sd.name.clone())); + + assert!(workspace + .current_buffer + .unwrap() + .syntax_definition + .is_some()); assert_eq!(name, Some("Plain Text".to_string())); } @@ -476,18 +492,24 @@ mod tests { workspace.add_buffer(buf.unwrap()); let name = workspace - .current_buffer - .as_ref() - .and_then(|ref b| b.syntax_definition.as_ref().map(|sd| sd.name.clone())); - - assert!(workspace.current_buffer.unwrap().syntax_definition.is_some()); + .current_buffer + .as_ref() + .and_then(|ref b| b.syntax_definition.as_ref().map(|sd| sd.name.clone())); + + assert!(workspace + .current_buffer + .unwrap() + .syntax_definition + .is_some()); assert_eq!(name, Some("Plain Text".to_string())); } #[test] fn open_buffer_adds_and_selects_the_buffer_at_the_specified_path() { let mut workspace = Workspace::new(Path::new("tests/sample"), None).unwrap(); - workspace.open_buffer(Path::new("tests/sample/file")).unwrap(); + workspace + .open_buffer(Path::new("tests/sample/file")) + .unwrap(); assert_eq!(workspace.buffers.len(), 1); assert_eq!(workspace.current_buffer.unwrap().data(), "it works!\n"); @@ -496,8 +518,12 @@ mod tests { #[test] fn open_buffer_does_not_open_a_buffer_already_in_the_workspace() { let mut workspace = Workspace::new(Path::new("tests/sample"), None).unwrap(); - workspace.open_buffer(Path::new("tests/sample/file")).unwrap(); - workspace.open_buffer(Path::new("tests/sample/file")).unwrap(); + workspace + .open_buffer(Path::new("tests/sample/file")) + .unwrap(); + workspace + .open_buffer(Path::new("tests/sample/file")) + .unwrap(); assert_eq!(workspace.buffers.len(), 1); } @@ -505,7 +531,9 @@ mod tests { #[test] fn open_buffer_selects_buffer_if_it_already_exists_in_workspace() { let mut workspace = Workspace::new(Path::new("tests/sample"), None).unwrap(); - workspace.open_buffer(Path::new("tests/sample/file")).unwrap(); + workspace + .open_buffer(Path::new("tests/sample/file")) + .unwrap(); // Add and select another buffer. let mut buf = Buffer::new(); @@ -514,12 +542,17 @@ mod tests { assert_eq!(workspace.current_buffer.as_ref().unwrap().data(), "scribe"); // Try to add the first buffer again. - workspace.open_buffer(Path::new("tests/sample/file")).unwrap(); + workspace + .open_buffer(Path::new("tests/sample/file")) + .unwrap(); // Ensure there are only two buffers, and that the // one requested via open_buffer is now selected. assert_eq!(workspace.buffers.len(), 2); - assert_eq!(workspace.current_buffer.as_ref().unwrap().data(), "it works!\n"); + assert_eq!( + workspace.current_buffer.as_ref().unwrap().data(), + "it works!\n" + ); } #[test] @@ -543,7 +576,10 @@ mod tests { let absolute_path = env::current_dir().unwrap(); buf.path = Some(absolute_path.clone()); workspace.add_buffer(buf); - assert_eq!(workspace.current_buffer_path(), Some(absolute_path.as_path())); + assert_eq!( + workspace.current_buffer_path(), + Some(absolute_path.as_path()) + ); } #[test] @@ -631,19 +667,31 @@ mod tests { workspace.add_buffer(third_buffer); // Ensure that the third buffer is currently selected. - assert_eq!(workspace.current_buffer.as_ref().unwrap().data(), "third buffer"); + assert_eq!( + workspace.current_buffer.as_ref().unwrap().data(), + "third buffer" + ); // Ensure that the second buffer is returned. workspace.previous_buffer(); - assert_eq!(workspace.current_buffer.as_ref().unwrap().data(), "second buffer"); + assert_eq!( + workspace.current_buffer.as_ref().unwrap().data(), + "second buffer" + ); // Ensure that the first buffer is returned. workspace.previous_buffer(); - assert_eq!(workspace.current_buffer.as_ref().unwrap().data(), "first buffer"); + assert_eq!( + workspace.current_buffer.as_ref().unwrap().data(), + "first buffer" + ); // Ensure that it wraps back to the third buffer. workspace.previous_buffer(); - assert_eq!(workspace.current_buffer.as_ref().unwrap().data(), "third buffer"); + assert_eq!( + workspace.current_buffer.as_ref().unwrap().data(), + "third buffer" + ); } #[test] @@ -669,18 +717,30 @@ mod tests { workspace.add_buffer(third_buffer); // Ensure that the third buffer is currently selected. - assert_eq!(workspace.current_buffer.as_ref().unwrap().data(), "third buffer"); + assert_eq!( + workspace.current_buffer.as_ref().unwrap().data(), + "third buffer" + ); // Ensure that it wraps back to the first buffer. workspace.next_buffer(); - assert_eq!(workspace.current_buffer.as_ref().unwrap().data(), "first buffer"); + assert_eq!( + workspace.current_buffer.as_ref().unwrap().data(), + "first buffer" + ); // Ensure that the second buffer is returned. workspace.next_buffer(); - assert_eq!(workspace.current_buffer.as_ref().unwrap().data(), "second buffer"); + assert_eq!( + workspace.current_buffer.as_ref().unwrap().data(), + "second buffer" + ); // Ensure that the third buffer is returned. workspace.next_buffer(); - assert_eq!(workspace.current_buffer.as_ref().unwrap().data(), "third buffer"); + assert_eq!( + workspace.current_buffer.as_ref().unwrap().data(), + "third buffer" + ); } }