#![doc = include_str!("readme.md")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HighlightKind {
Key,
String,
Number,
Boolean,
Comment,
DateTime,
Punctuation,
}
pub trait Highlighter {
fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)>;
}
pub struct TomlHighlighter {
pub use_parser: bool,
}
impl Default for TomlHighlighter {
fn default() -> Self {
Self { use_parser: false }
}
}
impl TomlHighlighter {
pub fn new() -> Self {
Self::default()
}
fn highlight_comments(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
let mut highlights = Vec::new();
let mut start = 0;
while let Some(pos) = text[start..].find('#') {
let absolute_pos = start + pos;
let end_of_line = text[absolute_pos..].find('\n').map(|i| absolute_pos + i).unwrap_or(text.len());
highlights.push((absolute_pos, end_of_line, HighlightKind::Comment));
start = end_of_line;
}
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 == '"' || ch == '\'' {
let quote = ch;
let start = i;
let mut end = i + 1;
let mut escaped = false;
while let Some((j, next_ch)) = chars.next() {
end = j + next_ch.len_utf8();
if escaped {
escaped = false;
}
else if next_ch == '\\' && quote == '"' {
escaped = true;
}
else if next_ch == quote {
break;
}
}
highlights.push((start, end, HighlightKind::String));
}
}
highlights
}
}
impl Highlighter for TomlHighlighter {
fn highlight(&self, text: &str) -> Vec<(usize, usize, HighlightKind)> {
let mut highlights = Vec::new();
highlights.extend(self.highlight_comments(text));
highlights.extend(self.highlight_strings(text));
highlights.sort_by_key(|h| h.0);
highlights
}
}