From 6a43727240c02b97f3935085c053f78068efa250 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Tue, 16 Mar 2021 12:18:37 -0400 Subject: [PATCH] Highlight primary keywords --- src/document.rs | 18 ++++----- src/filetype.rs | 95 +++++++++++++++++++++++++++++++++++++++++---- src/highlighting.rs | 8 +++- src/row.rs | 77 +++++++++++++++++++++++++++++++++--- 4 files changed, 174 insertions(+), 24 deletions(-) diff --git a/src/document.rs b/src/document.rs index 7ba9cb7..a597cd3 100644 --- a/src/document.rs +++ b/src/document.rs @@ -22,7 +22,7 @@ impl Document { for value in contents.lines() { let mut row = Row::from(value); - row.highlight(file_type.highlighting_options(), None); + row.highlight(&file_type.highlighting_options(), None); rows.push(row); } @@ -66,13 +66,13 @@ impl Document { if at.y == self.rows.len() { let mut row = Row::default(); row.insert(0, c); - row.highlight(self.file_type.highlighting_options(), None); + row.highlight(&self.file_type.highlighting_options(), None); self.rows.push(row); } else { #[allow(clippy::indexing_slicing)] let row = &mut self.rows[at.y]; row.insert(at.x, c); - row.highlight(self.file_type.highlighting_options(), None); + row.highlight(&self.file_type.highlighting_options(), None); } } @@ -90,11 +90,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(self.file_type.highlighting_options(), None); + row.highlight(&self.file_type.highlighting_options(), None); } else { let row = &mut self.rows[at.y]; row.delete(at.x); - row.highlight(self.file_type.highlighting_options(), None); + row.highlight(&self.file_type.highlighting_options(), None); } } @@ -106,7 +106,7 @@ impl Document { for row in &mut self.rows { file.write_all(row.as_bytes())?; file.write_all(b"\n")?; - row.highlight(self.file_type.highlighting_options(), None) + row.highlight(&self.file_type.highlighting_options(), None) } // File has been cleaned! (Saved) @@ -118,7 +118,7 @@ impl Document { pub fn highlight(&mut self, word: Option<&str>) { for row in &mut self.rows { - row.highlight(self.file_type.highlighting_options(), word); + row.highlight(&self.file_type.highlighting_options(), word); } } @@ -175,8 +175,8 @@ impl Document { let current_row = &mut self.rows[at.y]; let mut new_row = current_row.split(at.x); - current_row.highlight(self.file_type.highlighting_options(), None); - new_row.highlight(self.file_type.highlighting_options(), None); + current_row.highlight(&self.file_type.highlighting_options(), None); + new_row.highlight(&self.file_type.highlighting_options(), None); #[allow(clippy::integer_arithmetic)] self.rows.insert(at.y + 1, new_row); diff --git a/src/filetype.rs b/src/filetype.rs index fb9ce0e..127577d 100644 --- a/src/filetype.rs +++ b/src/filetype.rs @@ -3,12 +3,14 @@ pub struct FileType { hl_opts: HighlightingOptions, } -#[derive(Default, Copy, Clone)] +#[derive(Default)] pub struct HighlightingOptions { numbers: bool, strings: bool, characters: bool, comments: bool, + primary_keywords: Vec, + secondary_keywords: Vec, } impl Default for FileType { @@ -25,8 +27,8 @@ impl FileType { self.name.clone() } - pub fn highlighting_options(&self) -> HighlightingOptions { - self.hl_opts + pub fn highlighting_options(&self) -> &HighlightingOptions { + &self.hl_opts } pub fn from(file_name: &str) -> Self { @@ -38,6 +40,77 @@ impl FileType { strings: true, characters: true, comments: true, + primary_keywords: vec![ + "as".to_string(), + "break".to_string(), + "const".to_string(), + "continue".to_string(), + "crate".to_string(), + "else".to_string(), + "enum".to_string(), + "extern".to_string(), + "false".to_string(), + "fn".to_string(), + "For".to_string(), + "if".to_string(), + "impl".to_string(), + "in".to_string(), + "let".to_string(), + "loop".to_string(), + "match".to_string(), + "mod".to_string(), + "move".to_string(), + "mut".to_string(), + "pub".to_string(), + "ref".to_string(), + "return".to_string(), + "self".to_string(), + "Self".to_string(), + "static".to_string(), + "struct".to_string(), + "super".to_string(), + "trait".to_string(), + "true".to_string(), + "type".to_string(), + "unsafe".to_string(), + "use".to_string(), + "where".to_string(), + "while".to_string(), + "dyn".to_string(), + "abstract".to_string(), + "become".to_string(), + "box".to_string(), + "do".to_string(), + "final".to_string(), + "macro".to_string(), + "overrid".to_string(), + "priv".to_string(), + "typeof".to_string(), + "unsized".to_string(), + "virtual".to_string(), + "yield".to_string(), + "async".to_string(), + "await".to_string(), + "try".to_string(), + ], + secondary_keywords: vec![ + "bool".to_string(), + "char".to_string(), + "i8".to_string(), + "i16".to_string(), + "i32".to_string(), + "i64".to_string(), + "i128".to_string(), + "isize".to_string(), + "u8".to_string(), + "u16".to_string(), + "u32".to_string(), + "u64".to_string(), + "u128".to_string(), + "usize".to_string(), + "f32".to_string(), + "f64".to_string(), + ], }, }; } @@ -47,19 +120,27 @@ impl FileType { } impl HighlightingOptions { - pub fn numbers(self) -> bool { + pub fn numbers(&self) -> bool { self.numbers } - pub fn strings(self) -> bool { + pub fn strings(&self) -> bool { self.strings } - pub fn characters(self) -> bool { + pub fn characters(&self) -> bool { self.characters } - pub fn comments(self) -> bool { + pub fn comments(&self) -> bool { self.comments } + + pub fn primary_keywords(&self) -> &Vec { + &self.primary_keywords + } + + pub fn secondary_keywords(&self) -> &Vec { + &self.secondary_keywords + } } diff --git a/src/highlighting.rs b/src/highlighting.rs index 2d2921d..323ccfc 100644 --- a/src/highlighting.rs +++ b/src/highlighting.rs @@ -1,6 +1,6 @@ use termion::color; -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] pub enum Type { None, Number, @@ -8,16 +8,20 @@ pub enum Type { String, Character, Comment, + PrimaryKeywords, + SecondaryKeywords, } impl Type { - pub fn to_color(&self) -> impl color::Color { + pub fn to_color(self) -> impl color::Color { match self { Type::Number => color::Rgb(220, 163, 163), Type::Match => color::Rgb(38, 139, 210), Type::String => color::Rgb(211, 54, 130), Type::Character => color::Rgb(108, 113, 196), Type::Comment => color::Rgb(133, 153, 0), + Type::PrimaryKeywords => color::Rgb(181, 137, 0), + Type::SecondaryKeywords => color::Rgb(42, 161, 152), _ => color::Rgb(255, 255, 255), } } diff --git a/src/row.rs b/src/row.rs index 78fd646..d6afc08 100644 --- a/src/row.rs +++ b/src/row.rs @@ -213,10 +213,70 @@ impl Row { } } + fn highlight_str( + &mut self, + index: &mut usize, + substring: &str, + chars: &[char], + hl_type: highlighting::Type, + ) -> bool { + if substring.is_empty() { + return false; + } + + for (substring_index, c) in substring.chars().enumerate() { + if let Some(next_char) = chars.get(index.saturating_add(substring_index)) { + if *next_char != c { + return false; + } + } else { + return false; + } + } + + for _ in 0..substring.len() { + self.highlighting.push(hl_type); + *index += 1; + } + + true + } + + fn highlight_primary_keywords( + &mut self, + index: &mut usize, + opts: &HighlightingOptions, + chars: &[char], + ) -> bool { + if *index > 0 { + #[allow(clippy::indexing_slicing, clippy::integer_arithmetic)] + let prev_char = chars[*index - 1]; + if !is_separator(prev_char) { + return false; + } + } + + for word in opts.primary_keywords() { + if *index < chars.len().saturating_sub(word.len()) { + #[allow(clippy::indexing_slicing, clippy::integer_arithmetic)] + let next_char = chars[*index + word.len()]; + if !is_separator(next_char) { + continue; + } + } + + if self.highlight_str(index, word, chars, highlighting::Type::PrimaryKeywords) { + return true; + } + } + + false + } + fn highlight_char( &mut self, index: &mut usize, - opts: HighlightingOptions, + opts: &HighlightingOptions, c: char, chars: &[char], ) -> bool { @@ -247,7 +307,7 @@ impl Row { fn highlight_comment( &mut self, index: &mut usize, - opts: HighlightingOptions, + opts: &HighlightingOptions, c: char, chars: &[char], ) -> bool { @@ -270,7 +330,7 @@ impl Row { fn highlight_string( &mut self, index: &mut usize, - opts: HighlightingOptions, + opts: &HighlightingOptions, c: char, chars: &[char], ) -> bool { @@ -299,7 +359,7 @@ impl Row { fn highlight_number( &mut self, index: &mut usize, - opts: HighlightingOptions, + opts: &HighlightingOptions, c: char, chars: &[char], ) -> bool { @@ -307,7 +367,7 @@ impl Row { if *index > 0 { #[allow(clippy::indexing_slicing, clippy::integer_arithmetic)] let prev_char = chars[*index - 1]; - if !prev_char.is_ascii_punctuation() && !prev_char.is_ascii_whitespace() { + if !is_separator(prev_char) { return false; } } @@ -330,7 +390,7 @@ impl Row { false } - pub fn highlight(&mut self, opts: HighlightingOptions, word: Option<&str>) { + pub fn highlight(&mut self, opts: &HighlightingOptions, word: Option<&str>) { self.highlighting = Vec::new(); let chars: Vec = self.string.chars().collect(); let mut index = 0; @@ -338,6 +398,7 @@ impl Row { while let Some(c) = chars.get(index) { if self.highlight_char(&mut index, opts, *c, &chars) || self.highlight_comment(&mut index, opts, *c, &chars) + || self.highlight_primary_keywords(&mut index, &opts, &chars) || self.highlight_string(&mut index, opts, *c, &chars) || self.highlight_number(&mut index, opts, *c, &chars) { @@ -351,3 +412,7 @@ impl Row { self.highlight_match(word); } } + +fn is_separator(c: char) -> bool { + c.is_ascii_punctuation() || c.is_ascii_whitespace() +} \ No newline at end of file