use std::ops::Range; use iced_wgpu::core::text::highlighter; use iced_wgpu::core::Color; use acord_core::highlight::{highlight_source, HighlightSpan}; use crate::editor::{RESULT_PREFIX, ERROR_PREFIX}; use crate::palette; pub const EVAL_RESULT_KIND: u8 = 24; pub const EVAL_ERROR_KIND: u8 = 25; #[derive(Clone, PartialEq)] pub struct SyntaxSettings { pub lang: String, pub source: String, } #[derive(Clone, Copy, Debug)] pub struct SyntaxHighlight { pub kind: u8, } pub struct SyntaxHighlighter { lang: String, spans: Vec, line_offsets: Vec, current_line: usize, } impl SyntaxHighlighter { fn rebuild(&mut self, source: &str) { self.spans = highlight_source(source, &self.lang); self.line_offsets.clear(); let mut offset = 0; for line in source.split('\n') { self.line_offsets.push(offset); offset += line.len() + 1; } self.current_line = 0; } } impl highlighter::Highlighter for SyntaxHighlighter { type Settings = SyntaxSettings; type Highlight = SyntaxHighlight; type Iterator<'a> = std::vec::IntoIter<(Range, SyntaxHighlight)>; fn new(settings: &Self::Settings) -> Self { let mut h = SyntaxHighlighter { lang: settings.lang.clone(), spans: Vec::new(), line_offsets: Vec::new(), current_line: 0, }; h.rebuild(&settings.source); h } fn update(&mut self, new_settings: &Self::Settings) { self.lang = new_settings.lang.clone(); self.rebuild(&new_settings.source); } fn change_line(&mut self, line: usize) { self.current_line = self.current_line.min(line); } fn highlight_line(&mut self, _line: &str) -> Self::Iterator<'_> { let ln = self.current_line; self.current_line += 1; let trimmed = _line.trim_start(); if trimmed.starts_with(RESULT_PREFIX) { return vec![(0.._line.len(), SyntaxHighlight { kind: EVAL_RESULT_KIND })].into_iter(); } if trimmed.starts_with(ERROR_PREFIX) { return vec![(0.._line.len(), SyntaxHighlight { kind: EVAL_ERROR_KIND })].into_iter(); } if ln >= self.line_offsets.len() { return Vec::new().into_iter(); } let line_start = self.line_offsets[ln]; let line_end = if ln + 1 < self.line_offsets.len() { self.line_offsets[ln + 1] - 1 } else { line_start + _line.len() }; let mut result = Vec::new(); for span in &self.spans { if span.end <= line_start || span.start >= line_end { continue; } let start = span.start.max(line_start) - line_start; let end = span.end.min(line_end) - line_start; if start < end { result.push((start..end, SyntaxHighlight { kind: span.kind })); } } result.into_iter() } fn current_line(&self) -> usize { self.current_line } } pub fn highlight_color(kind: u8) -> Color { let p = palette::current(); match kind { 0 => p.mauve, 1 => p.blue, 2 => p.teal, 3 => p.yellow, 4 => p.yellow, 5 => p.teal, 6 => p.peach, 7 => p.peach, 8 => p.green, 9 => p.peach, 10 => p.overlay0, 11 => p.text, 12 => p.red, 13 => p.flamingo, 14 => p.sky, 15 => p.overlay2, 16 => p.overlay2, 17 => p.overlay2, 18 => p.blue, 19 => p.mauve, 20 => p.yellow, 21 => p.teal, 22 => p.red, 23 => p.text, 24 => p.green, 25 => p.maroon, _ => p.text, } }