Skip to content

Commit

Permalink
add multi-line comments
Browse files Browse the repository at this point in the history
  • Loading branch information
artem-streltsov committed Feb 24, 2024
1 parent beda86d commit 18fc687
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 30 deletions.
44 changes: 27 additions & 17 deletions src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ impl Document {
let file_type = FileType::from(filename);
let mut rows = Vec::new();
for value in contents.lines() {
let mut row = Row::from(value);
row.highlight(&file_type.highlighting_options(), None);
rows.push(row);
rows.push(Row::from(value));
}
Ok(Self {
rows,
Expand All @@ -46,20 +44,25 @@ impl Document {
self.dirty = true;
if c == '\n' {
self.insert_newline(at);
return;
}
if at.y == self.rows.len() {
} else if at.y == self.rows.len() {
let mut row = Row::default();
row.insert(0, c);
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);
}
self.unhighlight_rows(at.y);
}

fn unhighlight_rows(&mut self, start: usize) {
let start = start.saturating_sub(1);
for row in self.rows.iter_mut().skip(start) {
row.is_highlighted = false;
}
}

#[allow(clippy::indexing_slicing)]
pub fn delete(&mut self, at: &Position) {
let len = self.rows.len();
Expand All @@ -72,12 +75,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);
} else {
let row = &mut self.rows[at.y];
row.delete(at.x);
row.highlight(&self.file_type.highlighting_options(), None);
}
self.unhighlight_rows(at.y)
}
fn insert_newline(&mut self, at: &Position) {
if at.y > self.rows.len() {
Expand All @@ -89,9 +91,7 @@ impl Document {
}
#[allow(clippy::indexing_slicing)]
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);
let new_row = current_row.split(at.x);
self.rows.insert(at.y + 1, new_row);
}
pub fn save(&mut self) -> Result<(), Error> {
Expand All @@ -101,7 +101,6 @@ 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)
}
self.dirty = false;
}
Expand Down Expand Up @@ -148,9 +147,20 @@ impl Document {
}
None
}
pub fn highlight(&mut self, word: Option<&str>) {
for row in &mut self.rows {
row.highlight(&self.file_type.highlighting_options(), word);
pub fn highlight(&mut self, word: &Option<String>, until: Option<usize>) {
let mut start_with_comment = false;
let until = if let Some(until) = until {
if until.saturating_add(1) < self.rows.len() {
until.saturating_add(1)
} else {
self.rows.len()
}
} else {
self.rows.len()
};
#[allow(clippy::indexing_slicing)]
for row in &mut self.rows[..until] {
start_with_comment = row.highlight(&self.file_type.highlighting_options(), word, start_with_comment);
}
}
pub fn file_type(&self) -> String {
Expand Down
13 changes: 8 additions & 5 deletions src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ pub struct Editor {
document: Document,
offset: Position,
status_message: StatusMessage,
quit_times: u8
quit_times: u8,
highlighted_word: Option<String>
}

impl Editor {
Expand Down Expand Up @@ -87,17 +88,19 @@ impl Editor {
cursor_position: Position::default(),
offset: Position::default(),
status_message: StatusMessage::from(initial_status),
quit_times: QUIT_TIMES
quit_times: QUIT_TIMES,
highlighted_word: None,
}
}

fn refresh_screen(&self) -> Result<(), std::io::Error> {
fn refresh_screen(&mut self) -> Result<(), std::io::Error> {
Terminal::cursor_hide();
Terminal::cursor_position(&Position::default());
if self.should_quit {
Terminal::clear_screen();
println!("Goodbye.\r");
} else {
self.document.highlight(&self.highlighted_word, Some(self.offset.y.saturating_add(self.terminal.size().height as usize)));
self.draw_rows();
self.draw_status_bar();
self.draw_message_bar();
Expand Down Expand Up @@ -388,15 +391,15 @@ impl Editor {
} else if moved {
editor.move_cursor(Key::Left);
}
editor.document.highlight(Some(query));
editor.highlighted_word = Some(query.to_string());
}
).unwrap_or(None);

if query.is_none() {
self.cursor_position = old_position;
self.scroll();
}
self.document.highlight(None);
self.highlighted_word = None;
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/filetype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub struct HighlightingOptions {
strings: bool,
characters: bool,
comments: bool,
multiline_comments: bool,
primary_keywords: Vec<String>,
secondary_keywords: Vec<String>,
}
Expand Down Expand Up @@ -38,6 +39,7 @@ impl FileType {
strings: true,
characters: true,
comments: true,
multiline_comments: true,
primary_keywords: vec![
"as".to_string(),
"break".to_string(),
Expand Down Expand Up @@ -133,4 +135,7 @@ impl HighlightingOptions {
pub fn secondary_keywords(&self) -> &Vec<String> {
&self.secondary_keywords
}
pub fn multiline_comments(&self) -> bool {
self.multiline_comments
}
}
3 changes: 2 additions & 1 deletion src/highlighting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub enum Type {
String,
Character,
Comment,
MultulineComment,
PrimaryKeywords,
SecondaryKeywords,
}
Expand All @@ -19,7 +20,7 @@ impl Type {
Type::Match => color::Rgb(38, 139, 210),
Type::String => color::Rgb(255, 255, 255),
Type::Character => color::Rgb(108, 113, 196),
Type::Comment => color::Rgb(133, 153, 9),
Type::Comment | Type::MultulineComment => color::Rgb(133, 153, 9),
Type::PrimaryKeywords => color::Rgb(181, 137, 0),
Type::SecondaryKeywords => color::Rgb(42, 161, 152),
_ => color::Rgb(255, 255, 255),
Expand Down
73 changes: 66 additions & 7 deletions src/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ use unicode_segmentation::UnicodeSegmentation;
pub struct Row {
string: String,
len: usize,
highlighting: Vec<highlighting::Type>
highlighting: Vec<highlighting::Type>,
pub is_highlighted: bool
}

impl From<&str> for Row {
fn from(slice: &str) -> Self {
Self {
string: String::from(slice),
len: slice.graphemes(true).count(),
highlighting: Vec::new()
highlighting: Vec::new(),
is_highlighted: false
}
}
}
Expand Down Expand Up @@ -110,10 +112,12 @@ impl Row {
}
self.string = row;
self.len = length;
self.is_highlighted = false;
Self {
string: splitted_row,
len: splitted_length,
highlighting: Vec::new()
highlighting: Vec::new(),
is_highlighted: false
}
}
pub fn as_bytes(&self) -> &[u8] {
Expand Down Expand Up @@ -153,7 +157,7 @@ impl Row {
None
}

fn highlight_match(&mut self, word: Option<&str>) {
fn highlight_match(&mut self, word: &Option<String>) {
if let Some(word) = word {
if word.is_empty() {
return;
Expand Down Expand Up @@ -272,6 +276,27 @@ impl Row {
false
}

fn highlight_multiline_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 == '*' {
let closing_index = if let Some(closing_index) = self.string[*index + 2..].find("*/") {
*index + closing_index + 4
} else {
chars.len()
};

for _ in *index..closing_index {
self.highlighting.push(highlighting::Type::MultulineComment);
*index += 1;
}
return true;
}
};
}
false
}

fn highlight_string(&mut self, index: &mut usize, opts: &HighlightingOptions, c: char, chars: &[char]) -> bool {
if opts.strings() && c == '"' {
loop {
Expand Down Expand Up @@ -316,12 +341,41 @@ impl Row {
}
false
}

pub fn highlight(&mut self, opts: &HighlightingOptions, word: Option<&str>) {
self.highlighting = Vec::new();
#[allow(clippy::indexing_slicing)]
pub fn highlight(&mut self, opts: &HighlightingOptions, word: &Option<String>, start_with_comment: bool) -> bool {
let chars: Vec<char> = self.string.chars().collect();
if self.is_highlighted && word.is_none() {
if let Some(hl_type) = self.highlighting.last() {
if *hl_type == highlighting::Type::MultulineComment
&& self.string.len() > 1
&& self.string[self.string.len() - 2..] == *"*/"
{
return true;
}
}
return false;
}
self.highlighting = Vec::new();
let mut index = 0;
let mut in_ml_comment = start_with_comment;
if in_ml_comment {
let closing_index = if let Some(closing_index) = self.string.find("*/") {
closing_index + 2
} else {
chars.len()
};
for _ in 0..closing_index {
self.highlighting.push(highlighting::Type::MultulineComment);
}
index = closing_index;
}
while let Some(c) = chars.get(index) {
if self.highlight_multiline_comment(&mut index, &opts, *c, &chars) {
in_ml_comment = true;
continue;
}
in_ml_comment = false;
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)
Expand All @@ -335,6 +389,11 @@ impl Row {
index += 1;
}
self.highlight_match(word);
if in_ml_comment && &self.string[self.string.len().saturating_sub(2)..] != "*/" {
return true;
}
self.is_highlighted = true;
false
}
}

Expand Down

0 comments on commit 18fc687

Please sign in to comment.