142 lines
3.7 KiB
Rust
142 lines
3.7 KiB
Rust
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<HighlightSpan>,
|
|
line_offsets: Vec<usize>,
|
|
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<usize>, 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,
|
|
}
|
|
}
|