Cargo.lock 🔗
@@ -9390,6 +9390,7 @@ dependencies = [
"smol",
"streaming-iterator",
"strsim",
+ "strum 0.27.2",
"sum_tree",
"task",
"text",
MrSubidubi created
Cargo.lock | 1
crates/extension_host/src/extension_host.rs | 32 +++--------
crates/gpui_util/src/lib.rs | 14 +++++
crates/language/Cargo.toml | 1
crates/language/src/language.rs | 4
crates/language/src/language_registry.rs | 63 +++++++++++++++++-----
crates/languages/src/lib.rs | 29 +++++-----
crates/util/src/util.rs | 8 ++
8 files changed, 96 insertions(+), 56 deletions(-)
@@ -9390,6 +9390,7 @@ dependencies = [
"smol",
"streaming-iterator",
"strsim",
+ "strum 0.27.2",
"sum_tree",
"task",
"text",
@@ -37,8 +37,8 @@ use gpui::{
};
use http_client::{AsyncBody, HttpClient, HttpClientWithUrl};
use language::{
- LanguageConfig, LanguageMatcher, LanguageName, LanguageQueries, LoadedLanguage,
- QUERY_FILENAME_PREFIXES, Rope,
+ LanguageConfig, LanguageMatcher, LanguageName, LanguageQueries, LanguageQuery, LoadedLanguage,
+ Rope,
};
use node_runtime::NodeRuntime;
use project::ContextProviderWithTasks;
@@ -1877,26 +1877,14 @@ impl ExtensionStore {
fn load_plugin_queries(root_path: &Path) -> LanguageQueries {
let mut result = LanguageQueries::default();
- if let Some(entries) = std::fs::read_dir(root_path).log_err() {
- for entry in entries {
- let Some(entry) = entry.log_err() else {
- continue;
- };
- let path = entry.path();
- if let Some(remainder) = path.strip_prefix(root_path).ok().and_then(|p| p.to_str()) {
- if !remainder.ends_with(".scm") {
- continue;
- }
- for (name, query) in QUERY_FILENAME_PREFIXES {
- if remainder.starts_with(name) {
- if let Some(contents) = std::fs::read_to_string(&path).log_err() {
- match query(&mut result) {
- None => *query(&mut result) = Some(contents.into()),
- Some(r) => r.to_mut().push_str(contents.as_ref()),
- }
- }
- break;
- }
+ if std::fs::metadata(root_path).is_ok_and(|metadata| metadata.is_dir()) {
+ for query in LanguageQuery::variants() {
+ let query_path = query.query_path(&root_path);
+ if let Some(contents) = std::fs::read_to_string(&query_path).log_err() {
+ let query = query.query_mut(&mut result);
+ match query {
+ None => *query = Some(contents.into()),
+ Some(r) => r.to_mut().push_str(contents.as_ref()),
}
}
}
@@ -82,6 +82,10 @@ pub trait ResultExt<E> {
/// Assert that this result should never be an error in development or tests.
fn debug_assert_ok(self, reason: &str) -> Self;
fn warn_on_err(self) -> Option<Self::Ok>;
+ fn is_err_or<F>(self, f: F) -> bool
+ where
+ F: FnOnce(Self::Ok) -> bool;
+
fn log_with_level(self, level: log::Level) -> Option<Self::Ok>;
fn anyhow(self) -> anyhow::Result<Self::Ok>
where
@@ -112,6 +116,16 @@ where
self.log_with_level(log::Level::Warn)
}
+ fn is_err_or<F>(self, f: F) -> bool
+ where
+ F: FnOnce(T) -> bool,
+ {
+ match self {
+ Ok(value) => f(value),
+ Err(_) => true,
+ }
+ }
+
#[track_caller]
fn log_with_level(self, level: log::Level) -> Option<T> {
match self {
@@ -58,6 +58,7 @@ smallvec.workspace = true
smol.workspace = true
streaming-iterator.workspace = true
strsim.workspace = true
+strum.workspace = true
sum_tree.workspace = true
task.workspace = true
text.workspace = true
@@ -83,8 +83,8 @@ pub use buffer::Operation;
pub use buffer::*;
pub use diagnostic_set::{DiagnosticEntry, DiagnosticEntryRef, DiagnosticGroup};
pub use language_registry::{
- AvailableLanguage, BinaryStatus, LanguageNotFound, LanguageQueries, LanguageRegistry,
- QUERY_FILENAME_PREFIXES,
+ AvailableLanguage, BinaryStatus, LanguageNotFound, LanguageQueries, LanguageQuery,
+ LanguageRegistry,
};
pub use lsp::{LanguageServerId, LanguageServerName};
pub use outline::*;
@@ -232,22 +232,53 @@ impl std::fmt::Display for LanguageNotFound {
}
}
-pub const QUERY_FILENAME_PREFIXES: &[(
- &str,
- fn(&mut LanguageQueries) -> &mut Option<Cow<'static, str>>,
-)] = &[
- ("highlights", |q| &mut q.highlights),
- ("brackets", |q| &mut q.brackets),
- ("outline", |q| &mut q.outline),
- ("indents", |q| &mut q.indents),
- ("injections", |q| &mut q.injections),
- ("overrides", |q| &mut q.overrides),
- ("redactions", |q| &mut q.redactions),
- ("runnables", |q| &mut q.runnables),
- ("debugger", |q| &mut q.debugger),
- ("textobjects", |q| &mut q.text_objects),
- ("imports", |q| &mut q.imports),
-];
+#[derive(Copy, Clone, PartialEq, Eq, strum::Display, strum::EnumIter)]
+#[strum(serialize_all = "snake_case")]
+pub enum LanguageQuery {
+ Highlights,
+ Brackets,
+ Outline,
+ Indents,
+ Injections,
+ Overrides,
+ Runnables,
+ Debugger,
+ Textobjects,
+ Imports,
+}
+
+impl LanguageQuery {
+ pub fn variants() -> impl Iterator<Item = Self> {
+ use strum::IntoEnumIterator;
+ Self::iter()
+ }
+
+ pub fn query_mut<'a>(
+ &self,
+ queries: &'a mut LanguageQueries,
+ ) -> &'a mut Option<Cow<'static, str>> {
+ match self {
+ LanguageQuery::Highlights => &mut queries.highlights,
+ LanguageQuery::Brackets => &mut queries.brackets,
+ LanguageQuery::Outline => &mut queries.outline,
+ LanguageQuery::Indents => &mut queries.indents,
+ LanguageQuery::Injections => &mut queries.injections,
+ LanguageQuery::Overrides => &mut queries.overrides,
+ LanguageQuery::Runnables => &mut queries.runnables,
+ LanguageQuery::Debugger => &mut queries.debugger,
+ LanguageQuery::Textobjects => &mut queries.text_objects,
+ LanguageQuery::Imports => &mut queries.imports,
+ }
+ }
+
+ pub fn query_path(&self, folder_path: &Path) -> PathBuf {
+ folder_path.join(self.file_name())
+ }
+
+ pub fn file_name(&self) -> String {
+ format!("{self}.scm")
+ }
+}
/// Tree-sitter language queries for a given language.
#[derive(Debug, Default)]
@@ -8,7 +8,7 @@ use rust_embed::RustEmbed;
use settings::{SemanticTokenRules, SettingsStore};
use smol::stream::StreamExt;
use std::{str, sync::Arc};
-use util::{ResultExt, asset_str};
+use util::{ResultExt, embedded_file_to_str};
pub use language::*;
@@ -436,20 +436,19 @@ fn load_config(name: &str) -> LanguageConfig {
fn load_queries(name: &str) -> LanguageQueries {
let mut result = LanguageQueries::default();
- for path in LanguageDir::iter() {
- if let Some(remainder) = path.strip_prefix(name).and_then(|p| p.strip_prefix('/')) {
- if !remainder.ends_with(".scm") {
- continue;
- }
- for (name, query) in QUERY_FILENAME_PREFIXES {
- if remainder.starts_with(name) {
- let contents = asset_str::<LanguageDir>(path.as_ref());
- match query(&mut result) {
- None => *query(&mut result) = Some(contents),
- Some(r) => r.to_mut().push_str(contents.as_ref()),
- }
- }
- }
+ for query in LanguageQuery::variants() {
+ let Some(contents) = LanguageDir::get(&format!(
+ "{name}/{query_filename}",
+ query_filename = query.file_name()
+ ))
+ .map(embedded_file_to_str) else {
+ continue;
+ };
+
+ let query = query.query_mut(&mut result);
+ match query {
+ None => *query = Some(contents),
+ Some(r) => r.to_mut().push_str(contents.as_ref()),
}
}
result
@@ -20,6 +20,7 @@ pub mod time;
use anyhow::Result;
use itertools::Either;
use regex::Regex;
+use rust_embed::EmbeddedFile;
use std::path::{Path, PathBuf};
use std::sync::LazyLock;
use std::{
@@ -594,7 +595,12 @@ pub use rng::RandomCharIter;
/// Get an embedded file as a string.
pub fn asset_str<A: rust_embed::RustEmbed>(path: &str) -> Cow<'static, str> {
- match A::get(path).expect(path).data {
+ let asset = A::get(path).expect(path);
+ embedded_file_to_str(asset)
+}
+
+pub fn embedded_file_to_str(file: EmbeddedFile) -> Cow<'static, str> {
+ match file.data {
Cow::Borrowed(bytes) => Cow::Borrowed(std::str::from_utf8(bytes).unwrap()),
Cow::Owned(bytes) => Cow::Owned(String::from_utf8(bytes).unwrap()),
}