From 136286ae5c75edba14a2eb1be726ad91faafc925 Mon Sep 17 00:00:00 2001 From: wojciechkepka Date: Sat, 19 Jun 2021 08:46:31 +0200 Subject: [PATCH] Use same scopes on all themes As a consequence of this change, themes that do not have a scope defined will default to the scope of the default theme. --- helix-core/src/syntax.rs | 13 ++----- helix-term/src/application.rs | 5 +-- helix-term/src/ui/editor.rs | 7 ++-- helix-term/src/ui/markdown.rs | 8 ++-- helix-view/src/document.rs | 24 ++++-------- helix-view/src/editor.rs | 6 +-- helix-view/src/theme.rs | 72 ++++++++++++++++++++++++++++++----- 7 files changed, 82 insertions(+), 53 deletions(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index fef605dc17743..f6ad730b51330 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -143,7 +143,7 @@ fn read_query(language: &str, filename: &str) -> String { } impl LanguageConfiguration { - pub fn highlight_config(&self, scopes: &[String]) -> Option> { + pub fn highlight_config(&self, scopes: &[&str]) -> Option> { self.highlight_config .get_or_init(|| { let language = get_language_name(self.language_id).to_ascii_lowercase(); @@ -195,15 +195,13 @@ pub struct Loader { // highlight_names ? language_configs: Vec>, language_config_ids_by_file_type: HashMap, // Vec - scopes: Vec, } impl Loader { - pub fn new(config: Configuration, scopes: Vec) -> Self { + pub fn new(config: Configuration) -> Self { let mut loader = Self { language_configs: Vec::new(), language_config_ids_by_file_type: HashMap::new(), - scopes, }; for config in config.language { @@ -223,10 +221,6 @@ impl Loader { loader } - pub fn scopes(&self) -> &[String] { - &self.scopes - } - pub fn language_config_for_file_name(&self, path: &Path) -> Option> { // Find all the language configurations that match this file name // or a suffix of the file name. @@ -954,7 +948,7 @@ impl HighlightConfiguration { /// /// When highlighting, results are returned as `Highlight` values, which contain the index /// of the matched highlight this list of highlight names. - pub fn configure(&mut self, recognized_names: &[String]) { + pub fn configure>(&mut self, recognized_names: &[S]) { let mut capture_parts = Vec::new(); self.highlight_indices.clear(); self.highlight_indices @@ -965,6 +959,7 @@ impl HighlightConfiguration { let mut best_index = None; let mut best_match_len = 0; for (i, recognized_name) in recognized_names.iter().enumerate() { + let recognized_name = recognized_name.as_ref(); let mut len = 0; let mut matches = true; for part in recognized_name.split('.') { diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 83bd913bbb682..2730fcf888ac4 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -72,10 +72,7 @@ impl Application { }; let syn_loader_conf = toml::from_slice(lang_conf).expect("Could not parse languages.toml"); - let syn_loader = std::sync::Arc::new(syntax::Loader::new( - syn_loader_conf, - theme.scopes().to_vec(), - )); + let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf)); let mut editor = Editor::new(size, theme_loader.clone(), syn_loader.clone()); diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index b29c445fa3172..ee7d76c306a7c 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -11,7 +11,7 @@ use helix_core::{ syntax::{self, HighlightEvent}, Position, Range, }; -use helix_view::{document::Mode, Document, Editor, Theme, View}; +use helix_view::{document::Mode, theme, Document, Editor, Theme, View}; use std::borrow::Cow; use crossterm::{ @@ -163,10 +163,9 @@ impl EditorView { // .collect::>() // ); let style = match spans.first() { - Some(span) => theme - .scopes() + Some(span) => theme::DEFAULT_SCOPES .get(span.0) - .map(|s| theme.get(s.as_str())) + .map(|s| theme.get(s)) .unwrap_or_else(|| theme.get("ui.text")), None => theme.get("ui.text"), }; diff --git a/helix-term/src/ui/markdown.rs b/helix-term/src/ui/markdown.rs index eee641b0fc0d8..ef3e12d6ad98b 100644 --- a/helix-term/src/ui/markdown.rs +++ b/helix-term/src/ui/markdown.rs @@ -10,7 +10,7 @@ use tui::{ use std::{borrow::Cow, sync::Arc}; use helix_core::{syntax, Position}; -use helix_view::{Editor, Theme}; +use helix_view::{theme, Editor, Theme}; pub struct Markdown { contents: String, @@ -90,7 +90,7 @@ fn parse<'a>( let rope = Rope::from(text.as_ref()); let syntax = loader .language_config_for_scope(&format!("source.{}", language)) - .and_then(|config| config.highlight_config(theme.scopes())) + .and_then(|config| config.highlight_config(&theme::DEFAULT_SCOPES)) .map(|config| Syntax::new(&rope, config)); if let Some(mut syntax) = syntax { @@ -108,9 +108,7 @@ fn parse<'a>( } HighlightEvent::Source { start, end } => { let style = match highlights.first() { - Some(span) => { - theme.get(theme.scopes()[span.0].as_str()) - } + Some(span) => theme.get(theme::DEFAULT_SCOPES[span.0]), None => text_style, }; diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index f666e6627eaf6..b19697f460a90 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -13,7 +13,7 @@ use helix_core::{ ChangeSet, Diagnostic, Rope, Selection, State, Syntax, Transaction, }; -use crate::{DocumentId, ViewId}; +use crate::{theme, DocumentId, ViewId}; use std::collections::HashMap; @@ -221,7 +221,7 @@ impl Document { doc.detect_indent_style(); if let Some(loader) = config_loader { - doc.detect_language(None, loader); + doc.detect_language(loader); } Ok(doc) @@ -297,19 +297,10 @@ impl Document { } } - pub fn detect_language( - &mut self, - theme: Option<&crate::Theme>, - config_loader: &syntax::Loader, - ) { + pub fn detect_language(&mut self, config_loader: &syntax::Loader) { if let Some(path) = &self.path { let language_config = config_loader.language_config_for_file_name(path); - let scopes = if let Some(theme) = theme { - theme.scopes() - } else { - config_loader.scopes() - }; - self.set_language(language_config, scopes); + self.set_language(language_config); } } @@ -452,10 +443,10 @@ impl Document { pub fn set_language( &mut self, language_config: Option>, - scopes: &[String], ) { if let Some(language_config) = language_config { - if let Some(highlight_config) = language_config.highlight_config(scopes) { + if let Some(highlight_config) = language_config.highlight_config(&theme::DEFAULT_SCOPES) + { let syntax = Syntax::new(&self.text, highlight_config); self.syntax = Some(syntax); // TODO: config.configure(scopes) is now delayed, is that ok? @@ -470,9 +461,8 @@ impl Document { pub fn set_language2(&mut self, scope: &str, config_loader: Arc) { let language_config = config_loader.language_config_for_scope(scope); - let scopes = config_loader.scopes(); - self.set_language(language_config, scopes); + self.set_language(language_config); } pub fn set_language_server(&mut self, language_server: Option>) { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 51754c60f0d2f..30d4f7ff22e37 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -78,12 +78,8 @@ impl Editor { } pub fn set_theme(&mut self, theme: Theme) { - let config_loader = self.syn_loader.as_ref(); - for (_, doc) in self.documents.iter_mut() { - doc.detect_language(Some(&theme), config_loader); - } - self._refresh(); self.theme = theme; + self._refresh(); } pub fn set_theme_from_name(&mut self, theme: &str) { diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 6987997a8cbb4..314a9510563f6 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -168,9 +168,60 @@ impl Loader { } } +/// A list of all theme scopes. +pub static DEFAULT_SCOPES: Lazy> = Lazy::new(|| { + let mut scopes = vec![ + "attribute", + "comment", + "constant", + "constant.builtin", + "constructor", + "error", + "escape", + "function", + "function.builtin", + "function.macro", + "hint", + "info", + "keyword", + "keyword.directive", + "label", + "module", + "namespace", + "number", + "operator", + "property", + "punctuation", + "punctuation.delimiter", + "special", + "string", + "type", + "type.builtin", + "ui.background", + "ui.help", + "ui.linenr", + "ui.linenr.selected", + "ui.menu.selected", + "ui.popup", + "ui.selection", + "ui.statusline", + "ui.text", + "ui.text.focus", + "ui.window", + "variable", + "variable.builtin", + "variable.parameter", + "warning", + ]; + + // this has to be in alphabetical order so in case of human error + // we sort it + scopes.sort(); + scopes +}); + #[derive(Clone, Debug)] pub struct Theme { - scopes: Vec, styles: HashMap, } @@ -192,10 +243,18 @@ impl<'de> Deserialize<'de> for Theme { } } - let mut scopes: Vec<_> = styles.keys().map(ToString::to_string).collect(); - scopes.sort(); + // This is required so that all themes have the same scopes defined, + // otherwise changing the theme without upgrading `HighlighConfiguration` + // on `LanguageConfiguration` breaks the highlighting and there is no + // easy way to mutate the configuration. + let scopes: Vec<_> = styles.keys().map(ToString::to_string).collect(); + DEFAULT_SCOPES.iter().for_each(|scope| { + if !scopes.iter().find(|s| s == scope).is_some() { + styles.insert(scope.to_string(), DEFAULT_THEME.get(scope)); + } + }); - Ok(Self { scopes, styles }) + Ok(Self { styles }) } } @@ -291,11 +350,6 @@ impl Theme { pub fn try_get(&self, scope: &str) -> Option