From e0785135383fb0d4c03feb51bf5becdc680c87b2 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 24 Dec 2024 15:34:50 +0100 Subject: feat: make Highlighter generic over any T that is text_editor::Catalog --- src/lib.rs | 138 ++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 87 insertions(+), 51 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index f203289..960cdfa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,10 @@ //! A custom syntax highlighter for iced. //! //! It uses the colors from your app's Theme, based on the current [`Scope`] -use iced_core::font::Font; -use iced_core::text::highlighter::{self, Format}; -use iced_core::Theme; +use iced_widget::core::font::Font; +use iced_widget::core::text::highlighter::{self, Format}; +use iced_widget::text_editor::Catalog; +use iced_widget::Theme; use once_cell::sync::Lazy; use std::collections::HashSet; @@ -12,28 +13,37 @@ use std::str::FromStr; use syntect::highlighting; use syntect::parsing; -static SYNTAXES: Lazy = Lazy::new(parsing::SyntaxSet::load_defaults_nonewlines); +static SYNTAXES: Lazy = + Lazy::new(parsing::SyntaxSet::load_defaults_nonewlines); const LINES_PER_SNAPSHOT: usize = 50; -type ScopeSelectorsResult = - core::result::Result; +type ScopeSelectorsResult = core::result::Result< + highlighting::ScopeSelectors, + parsing::ParseScopeError, +>; /// A syntax highlighter. #[derive(Debug)] -pub struct Highlighter { +pub struct Highlighter +where + T: Catalog + 'static + Clone + PartialEq, +{ syntax: &'static parsing::SyntaxReference, custom_scopes: Vec, - style: Option Format>, + style: fn(&T, Scope) -> Format, caches: Vec<(parsing::ParseState, parsing::ScopeStack)>, current_line: usize, } -impl highlighter::Highlighter for Highlighter { - type Settings = Settings; - type Highlight = Highlight; +impl highlighter::Highlighter + for Highlighter +{ + type Settings = Settings; + type Highlight = Highlight; - type Iterator<'a> = Box, Self::Highlight)> + 'a>; + type Iterator<'a> = + Box, Self::Highlight)> + 'a>; fn new(settings: &Self::Settings) -> Self { let syntax = SYNTAXES @@ -79,32 +89,35 @@ impl highlighter::Highlighter for Highlighter { self.current_line = 0; } - let (parser, stack) = self.caches.last().cloned().unwrap_or_else(|| { - ( - parsing::ParseState::new(self.syntax), - parsing::ScopeStack::new(), - ) - }); + let (parser, stack) = + self.caches.last().cloned().unwrap_or_else(|| { + ( + parsing::ParseState::new(self.syntax), + parsing::ScopeStack::new(), + ) + }); self.caches.push((parser, stack)); } fn highlight_line(&mut self, line: &str) -> Self::Iterator<'_> { if self.current_line / LINES_PER_SNAPSHOT >= self.caches.len() { - let (parser, stack) = self.caches.last().expect("Caches must not be empty"); + let (parser, stack) = + self.caches.last().expect("Caches must not be empty"); self.caches.push((parser.clone(), stack.clone())); } self.current_line += 1; - let (parser, stack) = self.caches.last_mut().expect("Caches must not be empty"); + let (parser, stack) = + self.caches.last_mut().expect("Caches must not be empty"); let ops = parser.parse_line(line, &SYNTAXES).unwrap_or_default(); - let style = &self.style; let custom_scopes = &self.custom_scopes; + let style = &self.style; Box::new( ScopeRangeIterator { ops, @@ -121,7 +134,10 @@ impl highlighter::Highlighter for Highlighter { Some(( range, Highlight { - scope: Scope::from_scopestack(stack.clone(), custom_scopes.clone()), + scope: Scope::from_scopestack( + stack.clone(), + custom_scopes.clone(), + ), style: style.clone(), }, )) @@ -137,7 +153,10 @@ impl highlighter::Highlighter for Highlighter { /// The settings of a [`Highlighter`]. #[derive(Debug, Clone, PartialEq)] -pub struct Settings { +pub struct Settings +where + T: Catalog, +{ /// Custom scopes used for parsing the code. /// /// It extends [`Scope::ALL`]. @@ -146,10 +165,9 @@ pub struct Settings { /// The styling method of the [`Highlighter`]. /// /// It dictates how text matching a certain scope will be highlighted. - /// If set to None, [`default_style`] will be used. /// /// [`default_style`]: Highlight::default_style - pub style: Option Format>, + pub style: fn(&T, Scope) -> Format, /// The extension of the file or the name of the language to highlight. /// @@ -157,11 +175,11 @@ pub struct Settings { pub token: String, } -impl Settings { +impl Settings { /// Creates a new [`Settings`] struct with the given values. pub fn new( custom_scopes: Vec, - style: Option Format>, + style: fn(&T, Scope) -> Format, token: impl Into, ) -> Self { Self { @@ -174,39 +192,44 @@ impl Settings { /// A highlight produced by a [`Highlighter`]. #[derive(Debug)] -pub struct Highlight { +pub struct Highlight +where + T: Catalog, +{ scope: Scope, - style: Option Format>, + style: fn(&T, Scope) -> Format, } -impl Highlight { +impl Highlight { /// Returns the [`Format`] of the [`Highlight`]. /// /// It contains both the [`color`] and the [`font`]. /// - /// [`color`]: iced_core::Color - /// [`font`]: iced_core::Font - pub fn to_format(&self, theme: &Theme) -> Format { - match self.style { - Some(style) => style(theme, self.scope.clone()), - None => Self::default_style(theme, self.scope.clone()), - } + /// [`color`]: iced_widget::core::Color + /// [`font`]: iced_widget::core::Font + pub fn to_format(&self, theme: &T) -> Format { + (self.style)(theme, self.scope.clone()) } +} +impl Highlight { /// The defalt styling function of a [`Highlight`]. pub fn default_style(theme: &Theme, scope: Scope) -> Format { let color = match scope { - Scope::Comment | Scope::TagStart => theme.extended_palette().background.weak.color, + Scope::Comment | Scope::TagStart => { + theme.extended_palette().background.weak.color + } Scope::String | Scope::RegExp | Scope::QuotedString => { theme.extended_palette().primary.base.color } - Scope::EscapeSequence | Scope::SupportConstruct | Scope::Continuation => { - theme.extended_palette().danger.base.color - } + Scope::EscapeSequence + | Scope::SupportConstruct + | Scope::Continuation => theme.extended_palette().danger.base.color, Scope::Number => theme.extended_palette().secondary.weak.color, - Scope::Variable | Scope::VariableStart | Scope::TagName | Scope::Brackets => { - theme.extended_palette().primary.weak.color - } + Scope::Variable + | Scope::VariableStart + | Scope::TagName + | Scope::Brackets => theme.extended_palette().primary.weak.color, Scope::VariableFunction | Scope::FunctionName => { theme.extended_palette().success.base.color } @@ -219,7 +242,9 @@ impl Highlight { | Scope::StorageType | Scope::Class | Scope::LibraryClass - | Scope::LibraryFunction => theme.extended_palette().success.base.color, + | Scope::LibraryFunction => { + theme.extended_palette().success.base.color + } Scope::QuotedSingle => theme.palette().text, Scope::BuiltinConstant | Scope::UserDefinedConstant => { theme.extended_palette().danger.base.color @@ -228,8 +253,12 @@ impl Highlight { Scope::Special => theme.extended_palette().danger.strong.color, Scope::Import => theme.extended_palette().primary.weak.color, Scope::Exception => theme.extended_palette().danger.base.color, - Scope::Parantheses | Scope::Braces => theme.extended_palette().background.strong.color, - Scope::Other | Scope::Custom { .. } => theme.extended_palette().primary.strong.color, + Scope::Parantheses | Scope::Braces => { + theme.extended_palette().background.strong.color + } + Scope::Other | Scope::Custom { .. } => { + theme.extended_palette().primary.strong.color + } }; Format { @@ -326,7 +355,10 @@ impl Scope { ]; /// Creates a new custom [`Scope`]. - pub fn custom(name: impl Into, scope_string: impl Into) -> Self { + pub fn custom( + name: impl Into, + scope_string: impl Into, + ) -> Self { Self::Custom { name: name.into(), scope_string: scope_string.into(), @@ -375,11 +407,15 @@ impl Scope { } } - fn from_scopestack(stack: parsing::ScopeStack, custom_scopes: Vec) -> Self { + fn from_scopestack( + stack: parsing::ScopeStack, + custom_scopes: Vec, + ) -> Self { let scopes: Vec; if custom_scopes.len() > 0 { - let mut hashset: HashSet = (*Self::ALL).to_vec().into_iter().collect(); + let mut hashset: HashSet = + (*Self::ALL).to_vec().into_iter().collect(); hashset.extend(custom_scopes); scopes = hashset.into_iter().collect(); } else { @@ -413,7 +449,7 @@ impl Scope { } } -impl From for Result { +impl From for ScopeSelectorsResult { fn from(value: Scope) -> Self { highlighting::ScopeSelectors::from_str(value.scope_str()) } -- cgit v1.2.3