diff --git a/src/document.rs b/src/document.rs index 5a04c44..949f643 100644 --- a/src/document.rs +++ b/src/document.rs @@ -17,7 +17,7 @@ impl Document { let mut rows = Vec::new(); for value in contents.lines() { let mut row = Row::from(value); - row.highlight(); + row.highlight(None); rows.push(row); } Ok(Self { @@ -47,13 +47,13 @@ impl Document { if at.y == self.rows.len() { let mut row = Row::default(); row.insert(0, c); - row.highlight(); + row.highlight(None); self.rows.push(row); } else { #[allow(clippy::indexing_slicing)] let row = &mut self.rows[at.y]; row.insert(at.x, c); - row.highlight(); + row.highlight(None); } } #[allow(clippy::indexing_slicing)] @@ -68,11 +68,11 @@ impl Document { let next_row = self.rows.remove(at.y + 1); let row = &mut self.rows[at.y]; row.append(&next_row); - row.highlight(); + row.highlight(None); } else { let row = &mut self.rows[at.y]; row.delete(at.x); - row.highlight(); + row.highlight(None); } } fn insert_newline(&mut self, at: &Position) { @@ -86,8 +86,8 @@ impl Document { #[allow(clippy::indexing_slicing)] let current_row = &mut self.rows[at.y]; let mut new_row = current_row.split(at.x); - current_row.highlight(); - new_row.highlight(); + current_row.highlight(None); + new_row.highlight(None); self.rows.insert(at.y + 1, new_row); } pub fn save(&mut self) -> Result<(), Error> { @@ -142,4 +142,9 @@ impl Document { } None } + pub fn highlight(&mut self, word: Option<&str>) { + for row in &mut self.rows { + row.highlight(word); + } + } } diff --git a/src/editor.rs b/src/editor.rs index 8deb47a..975eedb 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -387,6 +387,7 @@ impl Editor { } else if moved { editor.move_cursor(Key::Left); } + editor.document.highlight(Some(query)); } ).unwrap_or(None); @@ -394,6 +395,7 @@ impl Editor { self.cursor_position = old_position; self.scroll(); } + self.document.highlight(None); } } diff --git a/src/highlighting.rs b/src/highlighting.rs index c56fdcc..f236374 100644 --- a/src/highlighting.rs +++ b/src/highlighting.rs @@ -3,13 +3,15 @@ use termion::color; #[derive(PartialEq)] pub enum Type { None, - Number + Number, + Match } impl Type { pub fn to_color(&self) -> impl color::Color { match self { Type::Number => color::Rgb(220, 163, 163), + Type::Match => color::Rgb(38, 139, 210), _ => color::Rgb(255, 255, 255) } } diff --git a/src/row.rs b/src/row.rs index d15b540..8c4e68b 100644 --- a/src/row.rs +++ b/src/row.rs @@ -119,7 +119,7 @@ impl Row { self.string.as_bytes() } pub fn find(&self, query: &str, at: usize, direction: SearchDirection) -> Option { - if at > self.len { + if at > self.len || query.is_empty() { return None; } let start = if direction == SearchDirection::Forward { @@ -151,14 +151,41 @@ impl Row { } None } - pub fn highlight(&mut self) { + pub fn highlight(&mut self, word: Option<&str>) { let mut highlighting = Vec::new(); - for c in self.string.chars() { + let chars: Vec = self.string.chars().collect(); + let mut matches = Vec::new(); + let mut search_index = 0; + + if let Some(word) = word { + while let Some(search_match) = self.find(word, search_index, SearchDirection::Forward) { + matches.push(search_match); + if let Some(next_index) = search_match.checked_add(word[..].graphemes(true).count()) { + search_index = next_index; + } else { + break; + } + } + } + + let mut index = 0; + while let Some(c) = chars.get(index) { + if let Some(word) = word { + if matches.contains(&index) { + for _ in word[..].graphemes(true) { + index += 1; + highlighting.push(highlighting::Type::Match); + } + continue; + } + } + if c.is_ascii_digit() { highlighting.push(highlighting::Type::Number); } else { highlighting.push(highlighting::Type::None); } + index += 1; } self.highlighting = highlighting; }