Massive refactor of highlighting logic
This commit is contained in:
parent
aa849373ad
commit
d5b880dd9e
238
src/row.rs
238
src/row.rs
@ -190,134 +190,164 @@ impl Row {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn highlight(&mut self, opts: HighlightingOptions, word: Option<&str>) {
|
fn highlight_match(&mut self, word: Option<&str>) {
|
||||||
let mut highlighting = Vec::new();
|
|
||||||
let chars: Vec<char> = self.string.chars().collect();
|
|
||||||
let mut matches = Vec::new();
|
|
||||||
let mut search_index = 0;
|
|
||||||
|
|
||||||
if let Some(word) = word {
|
if let Some(word) = word {
|
||||||
while let Some(search_match) = self.find(word, search_index, SearchDirection::Forward) {
|
if word.is_empty() {
|
||||||
matches.push(search_match);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut index = 0;
|
||||||
|
while let Some(search_match) = self.find(word, index, SearchDirection::Forward) {
|
||||||
if let Some(next_index) = search_match.checked_add(word[..].graphemes(true).count())
|
if let Some(next_index) = search_match.checked_add(word[..].graphemes(true).count())
|
||||||
{
|
{
|
||||||
search_index = next_index
|
#[allow(clippy::indexing_slicing)]
|
||||||
|
for i in index.saturating_add(search_match)..next_index {
|
||||||
|
self.highlighting[i] = highlighting::Type::Match;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = next_index;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut prev_is_separator = true;
|
fn highlight_char(
|
||||||
let mut in_string = false;
|
&mut self,
|
||||||
let mut index = 0;
|
index: &mut usize,
|
||||||
while let Some(c) = chars.get(index) {
|
opts: HighlightingOptions,
|
||||||
if let Some(word) = word {
|
c: char,
|
||||||
if matches.contains(&index) {
|
chars: &[char],
|
||||||
for _ in word[..].graphemes(true) {
|
) -> bool {
|
||||||
index += 1;
|
if opts.characters() && c == '\'' {
|
||||||
highlighting.push(highlighting::Type::Match);
|
if let Some(next_char) = chars.get(index.saturating_add(1)) {
|
||||||
|
let closing_index = if *next_char == '\\' {
|
||||||
|
index.saturating_add(3)
|
||||||
|
} else {
|
||||||
|
index.saturating_add(2)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(closing_char) = chars.get(closing_index) {
|
||||||
|
if *closing_char == '\'' {
|
||||||
|
for _ in 0..=closing_index.saturating_sub(*index) {
|
||||||
|
self.highlighting.push(highlighting::Type::Character);
|
||||||
|
*index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn highlight_comment(
|
||||||
|
&mut self,
|
||||||
|
index: &mut usize,
|
||||||
|
opts: HighlightingOptions,
|
||||||
|
c: char,
|
||||||
|
chars: &[char],
|
||||||
|
) -> bool {
|
||||||
|
if opts.comments() && c == '/' && *index < chars.len() {
|
||||||
|
if let Some(next_char) = chars.get(index.saturating_add(1)) {
|
||||||
|
if *next_char == '/' {
|
||||||
|
for _ in *index..chars.len() {
|
||||||
|
self.highlighting.push(highlighting::Type::Comment);
|
||||||
|
*index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn highlight_string(
|
||||||
|
&mut self,
|
||||||
|
index: &mut usize,
|
||||||
|
opts: HighlightingOptions,
|
||||||
|
c: char,
|
||||||
|
chars: &[char],
|
||||||
|
) -> bool {
|
||||||
|
if opts.strings() && c == '"' {
|
||||||
|
loop {
|
||||||
|
self.highlighting.push(highlighting::Type::String);
|
||||||
|
*index += 1;
|
||||||
|
|
||||||
|
if let Some(next_char) = chars.get(*index) {
|
||||||
|
if *next_char == '"' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let previous_highlight = if index > 0 {
|
self.highlighting.push(highlighting::Type::String);
|
||||||
highlighting
|
*index += 1;
|
||||||
.get(index - 1)
|
return true;
|
||||||
.unwrap_or(&highlighting::Type::None)
|
}
|
||||||
} else {
|
|
||||||
&highlighting::Type::None
|
|
||||||
};
|
|
||||||
|
|
||||||
if opts.characters() && !in_string && *c == '\'' {
|
false
|
||||||
prev_is_separator = true;
|
}
|
||||||
|
|
||||||
if let Some(next_char) = chars.get(index.saturating_add(1)) {
|
fn highlight_number(
|
||||||
let closing_index = if *next_char == '\\' {
|
&mut self,
|
||||||
index.saturating_add(3)
|
index: &mut usize,
|
||||||
} else {
|
opts: HighlightingOptions,
|
||||||
index.saturating_add(2)
|
c: char,
|
||||||
};
|
chars: &[char],
|
||||||
|
) -> bool {
|
||||||
if let Some(closing_char) = chars.get(closing_index) {
|
if opts.numbers() && c.is_ascii_digit() {
|
||||||
if *closing_char == '\'' {
|
if *index > 0 {
|
||||||
for _ in 0..=closing_index.saturating_sub(index) {
|
#[allow(clippy::indexing_slicing, clippy::integer_arithmetic)]
|
||||||
highlighting.push(highlighting::Type::Character);
|
let prev_char = chars[*index - 1];
|
||||||
index += 1;
|
if !prev_char.is_ascii_punctuation() && !prev_char.is_ascii_whitespace() {
|
||||||
}
|
return false;
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
highlighting.push(highlighting::Type::None);
|
loop {
|
||||||
index += 1;
|
self.highlighting.push(highlighting::Type::Number);
|
||||||
|
*index += 1;
|
||||||
|
if let Some(next_char) = chars.get(*index) {
|
||||||
|
if *next_char != '.' && !next_char.is_ascii_digit() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn highlight(&mut self, opts: HighlightingOptions, word: Option<&str>) {
|
||||||
|
self.highlighting = Vec::new();
|
||||||
|
let chars: Vec<char> = self.string.chars().collect();
|
||||||
|
let mut index = 0;
|
||||||
|
|
||||||
|
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_string(&mut index, opts, *c, &chars)
|
||||||
|
|| self.highlight_number(&mut index, opts, *c, &chars)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.strings() {
|
self.highlighting.push(highlighting::Type::None);
|
||||||
if in_string {
|
|
||||||
highlighting.push(highlighting::Type::String);
|
|
||||||
|
|
||||||
// Don't let an escaped character stop string highlighting
|
|
||||||
if *c == '\\' && index < self.len().saturating_sub(1) {
|
|
||||||
highlighting.push(highlighting::Type::String);
|
|
||||||
index += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if *c == '"' {
|
|
||||||
in_string = false;
|
|
||||||
prev_is_separator = true;
|
|
||||||
} else {
|
|
||||||
prev_is_separator = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
index += 1;
|
|
||||||
continue;
|
|
||||||
} else if prev_is_separator && *c == '"' {
|
|
||||||
highlighting.push(highlighting::Type::String);
|
|
||||||
|
|
||||||
in_string = true;
|
|
||||||
prev_is_separator = true;
|
|
||||||
index += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.comments() && *c == '/' {
|
|
||||||
if let Some(next_char) = chars.get(index.saturating_add(1)) {
|
|
||||||
if *next_char == '/' {
|
|
||||||
for _ in index..chars.len() {
|
|
||||||
highlighting.push(highlighting::Type::Comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.numbers() {
|
|
||||||
if (c.is_ascii_digit()
|
|
||||||
&& (prev_is_separator || *previous_highlight == highlighting::Type::Number))
|
|
||||||
|| (*c == '.' && *previous_highlight == highlighting::Type::Number)
|
|
||||||
{
|
|
||||||
highlighting.push(highlighting::Type::Number)
|
|
||||||
} else {
|
|
||||||
highlighting.push(highlighting::Type::None)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
highlighting.push(highlighting::Type::None)
|
|
||||||
}
|
|
||||||
|
|
||||||
prev_is_separator = c.is_ascii_punctuation() || c.is_ascii_whitespace();
|
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.highlighting = highlighting;
|
self.highlight_match(word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user