From cd7ff3b6e564bb97f09cf056a2fafec34a8a702d Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Tue, 16 Mar 2021 14:29:04 -0400 Subject: [PATCH] Final performance improvements, finish tutorial --- src/document.rs | 36 ++++++++++++++++++++++-------------- src/editor.rs | 14 +++++++++++--- src/row.rs | 23 ++++++++++++++++++++--- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/src/document.rs b/src/document.rs index 169ddc4..008c3b8 100644 --- a/src/document.rs +++ b/src/document.rs @@ -17,14 +17,11 @@ impl Document { pub fn open(filename: &str) -> Result { let contents = fs::read_to_string(filename)?; let file_type = FileType::from(filename); - let mut start_with_comment = false; let mut rows = Vec::new(); for value in contents.lines() { - let mut row = Row::from(value); - start_with_comment = row.highlight(&file_type.highlighting_options(), None, start_with_comment); - rows.push(row); + rows.push(Row::from(value)); } Ok(Self { @@ -71,7 +68,7 @@ impl Document { row.insert(at.x, c); } - self.highlight(None); + self.unhighlight_rows(at.y); } #[allow(clippy::integer_arithmetic, clippy::indexing_slicing)] @@ -93,23 +90,17 @@ impl Document { row.delete(at.x); } - self.highlight(None); + self.unhighlight_rows(at.y); } pub fn save(&mut self) -> Result<(), Error> { if let Some(file_name) = &self.file_name { let mut file = fs::File::create(file_name)?; self.file_type = FileType::from(file_name); - let mut start_with_comment = false; for row in &mut self.rows { file.write_all(row.as_bytes())?; file.write_all(b"\n")?; - start_with_comment = row.highlight( - &self.file_type.highlighting_options(), - None, - start_with_comment, - ); } // File has been cleaned! (Saved) @@ -119,10 +110,20 @@ impl Document { Ok(()) } - pub fn highlight(&mut self, word: Option<&str>) { + pub fn highlight(&mut self, word: &Option, until: Option) { let mut start_with_comment = false; + let until = if let Some(until) = until { + if until.saturating_add(1) < self.rows.len() { + until.saturating_add(1) + } else { + self.rows.len() + } + } else { + self.rows.len() + }; - for row in &mut self.rows { + #[allow(clippy::indexing_slicing)] + for row in &mut self.rows[..until] { start_with_comment = row.highlight( &self.file_type.highlighting_options(), word, @@ -187,4 +188,11 @@ impl Document { #[allow(clippy::integer_arithmetic)] self.rows.insert(at.y + 1, new_row); } + + fn unhighlight_rows(&mut self, start: usize) { + let start = start.saturating_sub(1); + for row in self.rows.iter_mut().skip(start) { + row.is_highlighted = false; + } + } } diff --git a/src/editor.rs b/src/editor.rs index 471dc8a..bcb0641 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -55,6 +55,7 @@ pub struct Editor { document: Document, status_message: StatusMessage, quit_times: u8, + highlighted_word: Option, } impl Editor { @@ -96,16 +97,23 @@ impl Editor { offset: Position::default(), status_message: StatusMessage::from(initial_status), quit_times: QUIT_TIMES, + highlighted_word: None, } } - fn refresh_screen(&self) -> Result<(), std::io::Error> { + fn refresh_screen(&mut self) -> Result<(), std::io::Error> { Terminal::cursor_hide(); Terminal::cursor_position(&Position::default()); if self.should_quit { Terminal::clear_screen(); println!("Goodbye.\r"); } else { + self.document.highlight( + &self.highlighted_word, + Some( + self.offset.y.saturating_add(self.terminal.size().height as usize), + ) + ); self.draw_rows(); self.draw_status_bar(); self.draw_message_bar(); @@ -222,7 +230,7 @@ impl Editor { editor.move_cursor(Key::Left); } - editor.document.highlight(Some(query)); + editor.highlighted_word = Some(query.to_string()); }, ) .unwrap_or(None); @@ -232,7 +240,7 @@ impl Editor { self.scroll(); } - self.document.highlight(None); + self.highlighted_word = None; } fn process_keypress(&mut self) -> Result<(), std::io::Error> { diff --git a/src/row.rs b/src/row.rs index 08e0c3b..0bafd66 100644 --- a/src/row.rs +++ b/src/row.rs @@ -9,6 +9,7 @@ use unicode_segmentation::UnicodeSegmentation; pub struct Row { string: String, highlighting: Vec, + pub is_highlighted: bool, len: usize, } @@ -17,6 +18,7 @@ impl From<&str> for Row { Self { string: String::from(slice), highlighting: Vec::new(), + is_highlighted: false, len: slice.graphemes(true).count(), } } @@ -143,10 +145,12 @@ impl Row { self.string = row; self.len = length; + self.is_highlighted = false; Self { string: splitted_row, len: splittend_length, + is_highlighted: false, highlighting: Vec::new(), } } @@ -190,7 +194,7 @@ impl Row { None } - fn highlight_match(&mut self, word: Option<&str>) { + fn highlight_match(&mut self, word: &Option) { if let Some(word) = word { if word.is_empty() { return; @@ -454,11 +458,22 @@ impl Row { pub fn highlight( &mut self, opts: &HighlightingOptions, - word: Option<&str>, + word: &Option, start_with_comment: bool, ) -> bool { - self.highlighting = Vec::new(); let chars: Vec = self.string.chars().collect(); + + if self.is_highlighted && word.is_none() { + if let Some(hl_type) = self.highlighting.last() { + if *hl_type == highlighting::Type::MultilineComment && self.string.len() > 1 && self.string[self.string.len() - 2..] == *"*/" { + return true; + } + } + + return false; + } + + self.highlighting = Vec::new(); let mut index = 0; let mut in_ml_comment = start_with_comment; @@ -507,6 +522,8 @@ impl Row { return true; } + self.is_highlighted = true; + false } }