77 lines
2.7 KiB
Rust
77 lines
2.7 KiB
Rust
//! 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<Vec<(Range<usize>, TokenClass)>>,
|
|
current: usize,
|
|
}
|
|
|
|
impl Highlighter for ArcadiaHighlighter {
|
|
type Settings = Arc<str>;
|
|
type Highlight = TokenClass;
|
|
type Iterator<'a> = std::vec::IntoIter<(Range<usize>, 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<Font> {
|
|
let color = match class {
|
|
TokenClass::Keyword => Color::from_rgb8(51, 23, 72),
|
|
TokenClass::Identifier => Color::from_rgb8(4, 39, 61),
|
|
TokenClass::String => Color::from_rgb8(4, 42, 27),
|
|
TokenClass::Number => Color::from_rgb8(63, 26, 6),
|
|
TokenClass::Comment => Color::from_rgb8(33, 37, 41),
|
|
TokenClass::Error => Color::from_rgb8(76, 9, 20),
|
|
TokenClass::Punctuation | TokenClass::Whitespace => Color::from_rgb8(32, 37, 44),
|
|
};
|
|
Format {
|
|
color: Some(color),
|
|
font: None,
|
|
}
|
|
}
|