Start of multiline comment highlighting

This commit is contained in:
Timothy Warren 2019-09-05 12:09:53 -04:00
parent 2cecadb3aa
commit ca51d8f1f5
1 changed files with 123 additions and 16 deletions

View File

@ -38,6 +38,8 @@ pub struct EditorSyntax {
keywords1: Vec<&'static str>,
keywords2: Vec<&'static str>,
singleline_comment_start: String,
multiline_comment_start: String,
multiline_comment_end: String,
flags: EditorSyntaxFlags,
}
@ -48,14 +50,18 @@ impl EditorSyntax {
keywords1: Vec<&'static str>,
keywords2: Vec<&'static str>,
single_line_comment_start: &str,
multi_line_comment_start: &str,
multi_line_comment_end: &str,
flags: EditorSyntaxFlags,
) -> Self {
EditorSyntax {
file_type: String::from(file_type),
file_type: file_type.to_owned(),
file_match,
keywords1,
keywords2,
singleline_comment_start: String::from(single_line_comment_start),
singleline_comment_start: single_line_comment_start.to_owned(),
multiline_comment_start: multi_line_comment_start.to_owned(),
multiline_comment_end: multi_line_comment_end.to_owned(),
flags,
}
}
@ -65,6 +71,7 @@ impl EditorSyntax {
pub enum Highlight {
Normal,
LineComment,
MultiLineComment,
Keyword1,
Keyword2,
String,
@ -380,15 +387,18 @@ impl Editor {
let keywords1 = &current_syntax.keywords1;
let keywords2 = &current_syntax.keywords2;
let scs = current_syntax.singleline_comment_start.clone();
let scs = &current_syntax.singleline_comment_start;
let mcs = &current_syntax.multiline_comment_start;
let mce = &current_syntax.multiline_comment_end;
let mut prev_separator = false;
let mut in_string = false;
let mut str_start = '\0';
let mut in_comment = false;
let mut i = 0;
let bytes = row.render.clone().into_bytes();
while i < row.render.len() {
'outer: while i < row.render.len() {
let c = bytes[i] as char;
let prev_highlight = if i > 0 {
row.highlight[i - 1]
@ -398,7 +408,7 @@ impl Editor {
// Single line comments
if scs.len() > 0 && !in_string {
let comment = row.render.find(&scs);
let comment = row.render.find(scs);
if comment.is_some() {
// Pretty simple, highlight from the match to the end of the line
let comment_start = comment.unwrap();
@ -408,6 +418,47 @@ impl Editor {
}
}
// Multi-line comments
if mcs.len() > 0 && mce.len() > 0 && !in_string {
let mce_slice_range = if i as usize + mce.len() >= row.render.len() {
i as usize..row.render.len()
} else {
i as usize..(i as usize + mce.len())
};
let mcs_slice_range = if i as usize + mcs.len() >= row.render.len() {
i as usize..row.render.len()
} else {
i as usize..(i as usize + mcs.len())
};
if in_comment {
row.highlight[i as usize] = Highlight::MultiLineComment;
// End of a comment
if &row.render[mce_slice_range.clone()] == mce {
for x in mce_slice_range {
row.highlight[x] = Highlight::MultiLineComment;
}
i += mce.len();
in_comment = false;
prev_separator = true;
continue;
} else {
i += 1;
continue;
}
} else if &row.render[mcs_slice_range.clone()] == mcs {
// Start of a multi-line comment
for x in mcs_slice_range {
row.highlight[x] = Highlight::MultiLineComment;
}
i += mcs.len();
in_comment = true;
continue;
}
}
// Strings
if current_syntax
.flags
@ -431,7 +482,7 @@ impl Editor {
prev_separator = true;
continue;
} else {
if c == '"' || c == '\'' {
if (c == '"' || c == '\'') && prev_separator {
in_string = true;
str_start = c;
row.highlight[i as usize] = Highlight::String;
@ -461,9 +512,22 @@ impl Editor {
for &keyword in keywords1 {
let matches = row.render.match_indices(keyword);
for (start, _) in matches {
let end = start + keyword.len();
for x in start..end {
row.highlight[x] = Highlight::Keyword1;
let next_char_offset = start + keyword.len() + 1;
let is_end_of_line = next_char_offset >= row.render.len();
let next_char = if is_end_of_line {
'\0'
} else {
bytes[next_char_offset] as char
};
if is_separator(next_char) {
let end = start + keyword.len();
for x in start..end {
row.highlight[x] = Highlight::Keyword1;
}
i += keyword.len();
prev_separator = false;
continue 'outer;
}
}
}
@ -471,9 +535,22 @@ impl Editor {
for &keyword in keywords2 {
let matches = row.render.match_indices(keyword);
for (start, _) in matches {
let end = start + keyword.len();
for x in start..end {
row.highlight[x] = Highlight::Keyword2;
let next_char_offset = start + keyword.len() + 1;
let is_end_of_line = next_char_offset >= row.render.len();
let next_char = if is_end_of_line {
'\0'
} else {
bytes[next_char_offset] as char
};
if is_separator(next_char) {
let end = start + keyword.len();
for x in start..end {
row.highlight[x] = Highlight::Keyword2;
}
i += keyword.len();
prev_separator = false;
continue 'outer;
}
}
}
@ -491,6 +568,7 @@ impl Editor {
Keyword1 => 33, // Yellow
Keyword2 => 32, // Green
LineComment => 36, // Cyan
MultiLineComment => 36,
Normal => 37,
Number => 31, // Red
SearchMatch => 34, // Blue
@ -815,7 +893,23 @@ impl Editor {
let mut current_color: i32 = -1;
for (x, ch) in output.char_indices() {
if self.rows[file_row].highlight[x] == Highlight::Normal {
if ch.is_ascii_control() {
// Display unprintable characters in inverted colors
let sym = if ch as u8 <= 26 {
('@' as u8 + ch as u8) as char
} else {
'?'
};
self.append_out("\x1b[7m");
self.append_out_char(sym);
self.append_out("\x1b[m");
if current_color != -1 {
let code = format!("\x1b[{}m", current_color);
self.append_out(&code);
}
} else if self.rows[file_row].highlight[x] == Highlight::Normal {
if current_color != -1 {
self.append_out("\x1b[39m");
current_color = -1;
@ -1276,6 +1370,8 @@ fn get_syntax_db() -> Vec<EditorSyntax> {
],
vec!["int", "long", "double", "float", "char", "unsigned", "signed", "void"],
"//",
"/*",
"*/",
EditorSyntaxFlags::HIGHLIGHT_NUMBERS | EditorSyntaxFlags::HIGHLIGHT_STRINGS,
),
EditorSyntax::new(
@ -1345,21 +1441,27 @@ fn get_syntax_db() -> Vec<EditorSyntax> {
"f64"
],
"//",
"/*",
"*/",
EditorSyntaxFlags::HIGHLIGHT_NUMBERS | EditorSyntaxFlags::HIGHLIGHT_STRINGS,
),
]
}
fn is_separator(c: char) -> bool {
fn is_separator(input_char: char) -> bool {
if input_char.is_ascii_whitespace() || input_char == '\0' {
return true;
}
let separator_chars = ",.()+-/*=~%<>[];";
for ch in separator_chars.chars() {
if c == ch {
if input_char == ch {
return true;
}
}
c.is_ascii_whitespace() || c == '\0'
false
}
#[cfg(test)]
@ -1377,4 +1479,9 @@ mod tests {
assert_eq!(editor.syntax.as_ref(), Some(&langs[0]));
}
#[test]
fn is_separator_works() {
assert_eq!(is_separator(' '), true);
assert_eq!(is_separator('_'), false);
}
}