//! Iced adapter for the core language lexer. Tokens are computed once per draft, //! then split into line-local UTF-8 ranges (including multiline comments). use iced::{ Color, Font, Theme, advanced::text::{Highlighter, highlighter::Format}, }; use oa_core::language::{TokenClass, tokenize}; use std::{ops::Range, sync::Arc}; pub struct ArcadiaHighlighter { lines: Vec, TokenClass)>>, current: usize, } impl Highlighter for ArcadiaHighlighter { type Settings = Arc; type Highlight = TokenClass; type Iterator<'a> = std::vec::IntoIter<(Range, TokenClass)>; fn new(source: &Self::Settings) -> Self { let mut offsets = vec![0]; offsets.extend(source.match_indices('\n').map(|(offset, _)| offset + 1)); let mut lines = vec![Vec::new(); offsets.len()]; for token in tokenize(source) { if matches!(token.class, TokenClass::Whitespace) { continue; } let first = offsets .partition_point(|offset| *offset <= token.span.start) .saturating_sub(1); for line in first..offsets.len() { let start = offsets[line]; if start >= token.span.end { break; } let end = offsets.get(line + 1).copied().unwrap_or(source.len()); let local = token.span.start.max(start) - start..token.span.end.min(end) - start; if !local.is_empty() { lines[line].push((local, token.class)); } } } Self { lines, current: 0 } } fn update(&mut self, source: &Self::Settings) { *self = Self::new(source); } fn change_line(&mut self, line: usize) { self.current = line; } fn highlight_line(&mut self, _line: &str) -> Self::Iterator<'_> { let spans = self.lines.get(self.current).cloned().unwrap_or_default(); self.current += 1; spans.into_iter() } fn current_line(&self) -> usize { self.current } } pub fn format(class: &TokenClass, _theme: &Theme) -> Format { let color = match class { TokenClass::Keyword => Color::from_rgb8(118, 62, 160), TokenClass::Identifier => Color::from_rgb8(20, 93, 139), TokenClass::String => Color::from_rgb8(24, 113, 79), TokenClass::Number => Color::from_rgb8(163, 78, 30), TokenClass::Comment => Color::from_rgb8(111, 121, 132), TokenClass::Error => Color::from_rgb8(186, 38, 62), TokenClass::Punctuation | TokenClass::Whitespace => Color::from_rgb8(91, 101, 117), }; Format { color: Some(color), font: None, } }