aboutsummaryrefslogtreecommitdiff
path: root/helix-core/src/syntax.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-core/src/syntax.rs')
-rw-r--r--helix-core/src/syntax.rs101
1 files changed, 59 insertions, 42 deletions
diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs
index ae058eb1..78623fd6 100644
--- a/helix-core/src/syntax.rs
+++ b/helix-core/src/syntax.rs
@@ -1,6 +1,8 @@
use crate::{regex::Regex, Change, Rope, RopeSlice, Transaction};
pub use helix_syntax::{get_language, get_language_name, Lang};
+use arc_swap::ArcSwap;
+
use std::{
borrow::Cow,
cell::RefCell,
@@ -143,35 +145,48 @@ fn read_query(language: &str, filename: &str) -> String {
}
impl LanguageConfiguration {
- pub fn highlight_config(&self, scopes: &[String]) -> Option<Arc<HighlightConfiguration>> {
- self.highlight_config
- .get_or_init(|| {
- let language = get_language_name(self.language_id).to_ascii_lowercase();
+ fn initialize_highlight(&self, scopes: &[String]) -> Option<Arc<HighlightConfiguration>> {
+ let language = get_language_name(self.language_id).to_ascii_lowercase();
- let highlights_query = read_query(&language, "highlights.scm");
- // always highlight syntax errors
- // highlights_query += "\n(ERROR) @error";
+ let highlights_query = read_query(&language, "highlights.scm");
+ // always highlight syntax errors
+ // highlights_query += "\n(ERROR) @error";
- let injections_query = read_query(&language, "injections.scm");
+ let injections_query = read_query(&language, "injections.scm");
- let locals_query = "";
+ let locals_query = "";
- if highlights_query.is_empty() {
- None
- } else {
- let language = get_language(self.language_id);
- let mut config = HighlightConfiguration::new(
- language,
- &highlights_query,
- &injections_query,
- locals_query,
- )
- .unwrap(); // TODO: no unwrap
- config.configure(scopes);
- Some(Arc::new(config))
- }
- })
- .clone()
+ if highlights_query.is_empty() {
+ None
+ } else {
+ let language = get_language(self.language_id);
+ let mut config = HighlightConfiguration::new(
+ language,
+ &highlights_query,
+ &injections_query,
+ locals_query,
+ )
+ .unwrap(); // TODO: no unwrap
+ config.configure(scopes);
+ Some(Arc::new(config))
+ }
+ }
+
+ pub fn highlight_config(&self, scopes: &[String]) -> Option<Arc<HighlightConfiguration>> {
+ if let Some(config) = self.highlight_config.get() {
+ if let Some(config) = config {
+ config.configure(scopes);
+ }
+ config.clone()
+ } else {
+ self.highlight_config
+ .get_or_init(|| self.initialize_highlight(scopes))
+ .clone()
+ }
+ }
+
+ pub fn is_highlight_initialized(&self) -> bool {
+ self.highlight_config.get().is_some()
}
pub fn indent_query(&self) -> Option<&IndentQuery> {
@@ -190,22 +205,18 @@ impl LanguageConfiguration {
}
}
-pub static LOADER: OnceCell<Loader> = OnceCell::new();
-
#[derive(Debug)]
pub struct Loader {
// highlight_names ?
language_configs: Vec<Arc<LanguageConfiguration>>,
language_config_ids_by_file_type: HashMap<String, usize>, // Vec<usize>
- scopes: Vec<String>,
}
impl Loader {
- pub fn new(config: Configuration, scopes: Vec<String>) -> 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 {
@@ -225,10 +236,6 @@ impl Loader {
loader
}
- pub fn scopes(&self) -> &[String] {
- &self.scopes
- }
-
pub fn language_config_for_file_name(&self, path: &Path) -> Option<Arc<LanguageConfiguration>> {
// Find all the language configurations that match this file name
// or a suffix of the file name.
@@ -253,6 +260,10 @@ impl Loader {
.find(|config| config.scope == scope)
.cloned()
}
+
+ pub fn language_configs_iter(&self) -> impl Iterator<Item = &Arc<LanguageConfiguration>> {
+ self.language_configs.iter()
+ }
}
pub struct TsParser {
@@ -771,7 +782,7 @@ pub struct HighlightConfiguration {
combined_injections_query: Option<Query>,
locals_pattern_index: usize,
highlights_pattern_index: usize,
- highlight_indices: Vec<Option<Highlight>>,
+ highlight_indices: ArcSwap<Vec<Option<Highlight>>>,
non_local_variable_patterns: Vec<bool>,
injection_content_capture_index: Option<u32>,
injection_language_capture_index: Option<u32>,
@@ -923,7 +934,7 @@ impl HighlightConfiguration {
}
}
- let highlight_indices = vec![None; query.capture_names().len()];
+ let highlight_indices = ArcSwap::from_pointee(vec![None; query.capture_names().len()]);
Ok(Self {
language,
query,
@@ -956,17 +967,20 @@ 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(&self, recognized_names: &[String]) {
let mut capture_parts = Vec::new();
- self.highlight_indices.clear();
- self.highlight_indices
- .extend(self.query.capture_names().iter().map(move |capture_name| {
+ let indices: Vec<_> = self
+ .query
+ .capture_names()
+ .iter()
+ .map(move |capture_name| {
capture_parts.clear();
capture_parts.extend(capture_name.split('.'));
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;
let mut len = 0;
let mut matches = true;
for part in recognized_name.split('.') {
@@ -982,7 +996,10 @@ impl HighlightConfiguration {
}
}
best_index.map(Highlight)
- }));
+ })
+ .collect();
+
+ self.highlight_indices.store(Arc::new(indices));
}
}
@@ -1561,7 +1578,7 @@ where
}
}
- let current_highlight = layer.config.highlight_indices[capture.index as usize];
+ let current_highlight = layer.config.highlight_indices.load()[capture.index as usize];
// If this node represents a local definition, then store the current
// highlight value on the local scope entry representing this node.