use syntect::easy::HighlightLines;
use syntect::highlighting::ThemeSet;
use syntect::parsing::SyntaxSet;
use syntect::util::as_24_bit_terminal_escaped;
pub struct SyntaxHighlighter {
syntax_set: SyntaxSet,
theme_set: ThemeSet,
}
impl SyntaxHighlighter {
pub fn new() -> Self {
Self {
syntax_set: SyntaxSet::load_defaults_newlines(),
theme_set: ThemeSet::load_defaults(),
}
}
pub fn highlight_line(&self, line: &str) -> String {
let syntax = self
.syntax_set
.find_syntax_by_extension("rs")
.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());
let theme = &self.theme_set.themes["base16-ocean.dark"];
let mut highlighter = HighlightLines::new(syntax, theme);
match highlighter.highlight_line(line, &self.syntax_set) {
Ok(ranges) => {
as_24_bit_terminal_escaped(&ranges[..], false)
}
Err(_) => {
line.to_string()
}
}
}
pub fn highlight_lines(&self, lines: &[&str]) -> Vec<String> {
lines.iter().map(|line| self.highlight_line(line)).collect()
}
pub fn is_available() -> bool {
true
}
}
impl Default for SyntaxHighlighter {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_highlighter_creation() {
let _highlighter = SyntaxHighlighter::new();
assert!(SyntaxHighlighter::is_available());
}
#[test]
fn test_highlight_simple_line() {
let highlighter = SyntaxHighlighter::new();
let line = "let x = 42";
let highlighted = highlighter.highlight_line(line);
assert!(highlighted.len() >= line.len());
}
#[test]
fn test_highlight_function() {
let highlighter = SyntaxHighlighter::new();
let line = "fn main() {";
let highlighted = highlighter.highlight_line(line);
assert!(highlighted.len() >= line.len());
}
#[test]
fn test_highlight_multiple_lines() {
let highlighter = SyntaxHighlighter::new();
let lines = vec!["let x = 42", "let y = \"hello\"", "println!(x)"];
let highlighted = highlighter.highlight_lines(&lines);
assert_eq!(highlighted.len(), 3);
}
}