140 lines
5.1 KiB
Rust
140 lines
5.1 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};
|
|
|
|
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 {
|
|
match kind {
|
|
0 => Color::from_rgb(0.804, 0.569, 0.945), // keyword - mauve
|
|
1 => Color::from_rgb(0.537, 0.706, 0.980), // function - blue
|
|
2 => Color::from_rgb(0.604, 0.831, 0.898), // function.builtin - teal
|
|
3 => Color::from_rgb(0.976, 0.827, 0.522), // type - yellow
|
|
4 => Color::from_rgb(0.976, 0.827, 0.522), // type.builtin - yellow
|
|
5 => Color::from_rgb(0.569, 0.878, 0.800), // constructor - teal
|
|
6 => Color::from_rgb(0.988, 0.702, 0.529), // constant - peach
|
|
7 => Color::from_rgb(0.988, 0.702, 0.529), // constant.builtin - peach
|
|
8 => Color::from_rgb(0.651, 0.890, 0.631), // string - green
|
|
9 => Color::from_rgb(0.988, 0.702, 0.529), // number - peach
|
|
10 => Color::from_rgb(0.424, 0.443, 0.537), // comment - overlay0
|
|
11 => Color::from_rgb(0.804, 0.839, 0.957), // variable - text
|
|
12 => Color::from_rgb(0.949, 0.604, 0.584), // variable.builtin - red
|
|
13 => Color::from_rgb(0.949, 0.773, 0.584), // variable.parameter - flamingo
|
|
14 => Color::from_rgb(0.604, 0.831, 0.898), // operator - sky
|
|
15 => Color::from_rgb(0.580, 0.612, 0.733), // punctuation - overlay2
|
|
16 => Color::from_rgb(0.580, 0.612, 0.733), // punctuation.bracket - overlay2
|
|
17 => Color::from_rgb(0.580, 0.612, 0.733), // punctuation.delimiter - overlay2
|
|
18 => Color::from_rgb(0.537, 0.706, 0.980), // property - blue
|
|
19 => Color::from_rgb(0.804, 0.569, 0.945), // tag - mauve
|
|
20 => Color::from_rgb(0.976, 0.827, 0.522), // attribute - yellow
|
|
21 => Color::from_rgb(0.569, 0.878, 0.800), // label - teal
|
|
22 => Color::from_rgb(0.949, 0.604, 0.584), // escape - red
|
|
23 => Color::from_rgb(0.804, 0.839, 0.957), // embedded - text
|
|
24 => Color::from_rgb(0.651, 0.890, 0.631), // eval result - green
|
|
25 => Color::from_rgb(0.890, 0.400, 0.400), // eval error - muted red
|
|
_ => Color::from_rgb(0.804, 0.839, 0.957), // default text
|
|
}
|
|
}
|