Start of multiline comment highlighting
This commit is contained in:
parent
2cecadb3aa
commit
ca51d8f1f5
127
src/editor.rs
127
src/editor.rs
@ -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 = ¤t_syntax.keywords1;
|
||||
let keywords2 = ¤t_syntax.keywords2;
|
||||
|
||||
let scs = current_syntax.singleline_comment_start.clone();
|
||||
let scs = ¤t_syntax.singleline_comment_start;
|
||||
let mcs = ¤t_syntax.multiline_comment_start;
|
||||
let mce = ¤t_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,20 +512,46 @@ impl Editor {
|
||||
for &keyword in keywords1 {
|
||||
let matches = row.render.match_indices(keyword);
|
||||
for (start, _) in matches {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for &keyword in keywords2 {
|
||||
let matches = row.render.match_indices(keyword);
|
||||
for (start, _) in matches {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user