#![doc = include_str!("readme.md")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HighlightKind {
Keyword,
String,
Number,
Comment,
Identifier,
}
pub trait Highlighter {
fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)>;
}
pub struct MatlabHighlighter;
impl Default for MatlabHighlighter {
fn default() -> Self {
Self
}
}
impl MatlabHighlighter {
pub fn new() -> Self {
Self::default()
}
fn highlight_keywords(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
let mut highlights = Vec::new();
let keywords = ["break", "case", "catch", "classdef", "continue", "else", "elseif", "end", "for", "function", "global", "if", "otherwise", "parfor", "persistent", "return", "spmd", "switch", "try", "while"];
for keyword in &keywords {
let mut start = 0;
while let Some(pos) = text[start..].find(keyword) {
let absolute_pos = start + pos;
let end_pos = absolute_pos + keyword.len();
let is_word_boundary_before = absolute_pos == 0 || !text.chars().nth(absolute_pos - 1).unwrap_or(' ').is_alphanumeric();
let is_word_boundary_after = end_pos >= text.len() || !text.chars().nth(end_pos).unwrap_or(' ').is_alphanumeric();
if is_word_boundary_before && is_word_boundary_after {
highlights.push((absolute_pos, end_pos, HighlightKind::Keyword))
}
start = absolute_pos + 1
}
}
highlights
}
fn highlight_strings(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
let mut highlights = Vec::new();
let mut chars = text.char_indices().peekable();
while let Some((i, ch)) = chars.next() {
if ch == '\'' {
let start = i;
let mut end = i + 1;
while let Some((j, next_ch)) = chars.next() {
end = j + next_ch.len_utf8();
if next_ch == '\'' {
if let Some(&(_, peek_ch)) = chars.peek() {
if peek_ch == '\'' {
chars.next();
continue;
}
}
break;
}
}
highlights.push((start, end, HighlightKind::String))
}
}
highlights
}
}
impl Highlighter for MatlabHighlighter {
fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
let mut highlights = Vec::new();
highlights.extend(self.highlight_keywords(text));
highlights.extend(self.highlight_strings(text));
highlights.sort_by_key(|&(start, _, _)| start);
highlights
}
}