A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/text/semantic_tokens.rs')
| -rw-r--r-- | src/text/semantic_tokens.rs | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/text/semantic_tokens.rs b/src/text/semantic_tokens.rs new file mode 100644 index 0000000..196f1ff --- /dev/null +++ b/src/text/semantic_tokens.rs @@ -0,0 +1,197 @@ +use dsb::cell::Style; +use log::error; +use lsp_types::{SemanticToken, SemanticTokensLegend}; +use serde_derive::{Deserialize, Serialize}; + +macro_rules! modified { + ($count:literal $($x:literal . $mod:literal $color:literal $($style:expr)?,)+ $(,)?) => { + pub const MODIFIED: [(&str, &str); $count] = [ + $(($x, $mod),)+ + ]; + pub const MCOLORS: [[u8;3]; MODIFIED.len()] = car::map!([$($color),+], |x| color(x)); + pub const MSTYLE: [u8; MODIFIED.len()] = [$(($($style, )? 0, ).0 ,)+]; + } +} +use super::color; +macro_rules! theme { + ($($x:literal $color:literal $($style:expr)?),+ $(,)?) => { + #[rustfmt::skip] + pub const NAMES: [&str; [$($x),+].len()] = [$($x),+]; + #[rustfmt::skip] + pub const COLORS: [[u8; 3]; NAMES.len()] = car::map!([$($color),+], |x| color(x)); + pub const STYLES: [u8; NAMES.len()] = [$( + ($($style, )? 0, ).0 + ),+]; + }; +} +pub(crate) use theme; +theme! { +"constructor" b"#FFAD66", +"field" b"#cccac2", + +"comment" b"#5c6773" Style::ITALIC, +// "decorator" b"#cccac2", +"function" b"#FFD173" Style::ITALIC, +"interface" b"#5CCFE6", +"keyword" b"#FFAD66" Style::ITALIC | Style::BOLD, +"macro" b"#fbc351" Style::BOLD, +"method" b"#FFD173" Style::ITALIC, +// "namespace" b"#cccac2", +"number" b"#dfbfff", +"operator" b"#F29E74", +// "property" b"#cccac2", +"string" b"#D5FF80", +// "struct" b"#cccac2", +// "typeParameter" b"#cccac2", +"class" b"#73b9ff", +"enumMember" b"#73b9ff", +"enum" b"#73b9ff" Style::ITALIC | Style::BOLD, +"builtinType" b"#73d0ff" Style::ITALIC, +// "type" b"#73d0ff" Style::ITALIC | Style::BOLD, +"typeAlias" b"#69caed" Style::ITALIC | Style::BOLD, +"struct" b"#73d0ff" Style::ITALIC | Style::BOLD, +"variable" b"#cccac2", +// "angle" b"#cccac2", +// "arithmetic" b"#cccac2", +// "attributeBracket" b"#cccac2", +"parameter" b"#DFBFFF", +"namespace" b"#73d0ff", +// "attributeBracket" b"#cccac2", +// "attribute" b"#cccac2", +// "bitwise" b"#cccac2", +// "boolean" b"#cccac2", +// "brace" b"#cccac2", +// "bracket" b"#cccac2", +// "builtinAttribute" b"#cccac2", +// "character" b"#cccac2", +// "colon" b"#cccac2", +// "comma" b"#cccac2", +// "comparison" b"#cccac2", +// "constParameter" b"#cccac2", +"const" b"#DFBFFF", +// "deriveHelper" b"#cccac2", +// "derive" b"#cccac2", +// "dot" b"#cccac2", +// "escapeSequence" b"#cccac2", +// "formatSpecifier" b"#cccac2", +// "generic" b"#cccac2", +// "invalidEscapeSequence" b"#cccac2", +// "label" b"#cccac2", +// "lifetime" b"#cccac2", +// "logical" b"#cccac2", +"macroBang" b"#f28f74", +// "parenthesis" b"#cccac2", +// "procMacro" b"#cccac2", +// "punctuation" b"#cccac2", +"selfKeyword" b"#FFAD66" Style::ITALIC | Style::BOLD, +"selfTypeKeyword" b"#FFAD66" Style::ITALIC | Style::BOLD, +// "semicolon" b"#cccac2", +// "static" b"#cccac2", +// "toolModule" b"#cccac2", +// "union" b"#cccac2", +// "unresolvedReference" b"#cccac2", +} +const fn of(x: &'static str) -> usize { + let mut i = 0; + while i < NAMES.len() { + if NAMES[i] == x { + return i; + } + i += 1; + } + panic!() +} + +modified! { 2 + "function" . "unsafe" b"#F28779", + "variable" . "mutable" b"#e6dab6", +} +use crate::text::TextArea; + +#[derive( + Copy, Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, +)] +pub struct TokenD { + pub ty: u32, + pub modifiers: u32, +} +impl TokenD { + pub fn style(self, leg: &SemanticTokensLegend) -> Style { + let mut sty = Style::new(crate::FG, crate::BG); + let Some(tty) = leg.token_types.get(self.ty as usize) else { + error!( + "issue while loading semantic token {self:?}; couldnt \ + find in legend" + ); + return sty; + }; + if let Some(f) = NAMES.iter().position(|&x| x == tty.as_str()) { + // cells + // .get_range_enumerated((x1, ln as _), (x2, ln as _)) + // .filter(|(_, i)| { + // matches!(src_map.get(i.0), Some(Mapping::Char(..))) + // }) + // .for_each(|(x, _)| { + sty.fg = COLORS[f]; + sty.flags |= STYLES[f]; + // }); + } + // println!( + // "{tty:?}: {}", + // slice.iter().flat_map(|x| x.letter).collect::<String>() + // ); + let mut modi = self.modifiers; + while modi != 0 { + let bit = modi.trailing_zeros(); + + leg.token_modifiers + .get(bit as usize) + .and_then(|modi| { + MODIFIED.iter().position(|&(x, y)| { + (x == tty.as_str()) & (y == modi.as_str()) + }) + }) + .map(|i| { + sty.fg = MCOLORS[i]; + sty.flags |= MSTYLE[i]; + }); + + modi &= !(1 << bit); + } + sty + } +} +impl TextArea { + pub fn set_toks(&mut self, toks: &[SemanticToken]) { + let mut ln = 0; + let mut ch = 0; + self.tokens.clear(); + for t in toks { + ln += t.delta_line; + ch = match t.delta_line { + 1.. => t.delta_start, + 0 => ch + t.delta_start, + }; + let Ok((x1, x2)): ropey::Result<_> = (try { + let p1 = self.rope.try_byte_to_char( + self.rope.try_line_to_byte(ln as _)? + ch as usize, + )?; + let p2 = self.rope.try_byte_to_char( + self.rope.try_line_to_byte(ln as _)? + + ch as usize + + t.length as usize, + )?; + (p1 as u32, p2 as u32) + }) else { + continue; + }; + self.tokens.insert( + x1..x2, + TokenD { + ty: t.token_type, + modifiers: t.token_modifiers_bitset, + }, + ); + } + } +} |