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