Added globset to helix-core. Moved globset building to config parsing.

pull/8696/head
ontley 10 months ago
parent 51d40c169d
commit 9909082f08

1
Cargo.lock generated

@ -1240,6 +1240,7 @@ dependencies = [
"dunce", "dunce",
"encoding_rs", "encoding_rs",
"etcetera", "etcetera",
"globset",
"hashbrown 0.14.3", "hashbrown 0.14.3",
"helix-loader", "helix-loader",
"helix-stdx", "helix-stdx",

@ -52,6 +52,7 @@ textwrap = "0.16.0"
nucleo.workspace = true nucleo.workspace = true
parking_lot = "0.12" parking_lot = "0.12"
globset = "0.4.14"
[dev-dependencies] [dev-dependencies]
quickcheck = { version = "1", default-features = false } quickcheck = { version = "1", default-features = false }

@ -10,6 +10,7 @@ use crate::{
use ahash::RandomState; use ahash::RandomState;
use arc_swap::{ArcSwap, Guard}; use arc_swap::{ArcSwap, Guard};
use bitflags::bitflags; use bitflags::bitflags;
use globset::GlobSet;
use hashbrown::raw::RawTable; use hashbrown::raw::RawTable;
use slotmap::{DefaultKey as LayerId, HopSlotMap}; use slotmap::{DefaultKey as LayerId, HopSlotMap};
@ -358,6 +359,22 @@ where
serializer.end() serializer.end()
} }
fn deserialize_required_root_patterns<'de, D>(deserializer: D) -> Result<Option<GlobSet>, D::Error>
where
D: serde::Deserializer<'de>,
{
let patterns = Vec::<String>::deserialize(deserializer)?;
if patterns.is_empty() {
return Ok(None);
}
let mut builder = globset::GlobSetBuilder::new();
for pattern in patterns {
let glob = globset::Glob::new(&pattern).map_err(serde::de::Error::custom)?;
builder.add(glob);
}
builder.build().map(Some).map_err(serde::de::Error::custom)
}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct LanguageServerConfiguration { pub struct LanguageServerConfiguration {
@ -371,9 +388,12 @@ pub struct LanguageServerConfiguration {
pub config: Option<serde_json::Value>, pub config: Option<serde_json::Value>,
#[serde(default = "default_timeout")] #[serde(default = "default_timeout")]
pub timeout: u64, pub timeout: u64,
#[serde(default)] #[serde(
#[serde(skip_serializing_if = "Vec::is_empty")] default,
pub required_root_patterns: Vec<String>, skip_serializing,
deserialize_with = "deserialize_required_root_patterns"
)]
pub required_root_patterns: Option<GlobSet>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]

@ -910,41 +910,16 @@ fn start_client(
let root_path = root.clone().unwrap_or_else(|| workspace.clone()); let root_path = root.clone().unwrap_or_else(|| workspace.clone());
let root_uri = root.and_then(|root| lsp::Url::from_file_path(root).ok()); let root_uri = root.and_then(|root| lsp::Url::from_file_path(root).ok());
let mut globset = globset::GlobSetBuilder::new(); if let Some(globset) = &ls_config.required_root_patterns {
let required_root_patterns = &ls_config.required_root_patterns;
if !required_root_patterns.is_empty() {
for required_root_pattern in required_root_patterns {
match globset::Glob::new(required_root_pattern) {
Ok(glob) => {
globset.add(glob);
}
Err(err) => {
log::warn!(
"Failed to build glob '{}' for language server '{}'",
required_root_pattern,
name
);
log::warn!("{}", err);
}
};
}
match globset.build() {
Ok(glob) => {
if !root_path if !root_path
.read_dir()? .read_dir()?
.flatten() .flatten()
.map(|entry| entry.file_name()) .map(|entry| entry.file_name())
.any(|entry| glob.is_match(entry)) .any(|entry| globset.is_match(entry))
{ {
return Ok(None); return Ok(None);
} }
} }
Err(err) => {
log::warn!("Failed to build globset for language server {name}");
log::warn!("{}", err);
}
};
}
let (client, incoming, initialize_notify) = Client::start( let (client, incoming, initialize_notify) = Client::start(
&ls_config.command, &ls_config.command,

Loading…
Cancel
Save