mirror of https://github.com/helix-editor/helix
Merge 97ec8494a7
into ba54b6afe4
commit
675fe454c6
|
@ -142,7 +142,7 @@ These are the available options for a language server.
|
|||
| `config` | Language server initialization options |
|
||||
| `timeout` | The maximum time a request to the language server may take, in seconds. Defaults to `20` |
|
||||
| `environment` | Any environment variables that will be used when starting the language server `{ "KEY1" = "Value1", "KEY2" = "Value2" }` |
|
||||
| `required-root-patterns` | A list of `glob` patterns to look for in the working directory. The language server is started if at least one of them is found. |
|
||||
| `required-root-patterns` | A list of `glob` patterns to look for in the working directory. The language server is started if at least one of them is found. Patterns can be negated with `!` prefix (`\\!` for escape). |
|
||||
|
||||
A `format` sub-table within `config` can be used to pass extra formatting options to
|
||||
[Document Formatting Requests](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_formatting).
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
lld
|
||||
cargo-flamegraph
|
||||
rust-bin.nightly.latest.rust-analyzer
|
||||
rust-bin.nightly.latest.clippy
|
||||
]
|
||||
++ (lib.optional (stdenv.isx86_64 && stdenv.isLinux) cargo-tarpaulin)
|
||||
++ (lib.optional stdenv.isLinux lldb)
|
||||
|
|
|
@ -374,20 +374,41 @@ where
|
|||
serializer.end()
|
||||
}
|
||||
|
||||
fn deserialize_required_root_patterns<'de, D>(deserializer: D) -> Result<Option<GlobSet>, D::Error>
|
||||
/// Deserialize required-root-patterns with globset.
|
||||
///
|
||||
/// This function returns a tuple of positive globset and negative globset.
|
||||
fn deserialize_required_root_patterns<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<(GlobSet, 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();
|
||||
|
||||
let mut positive_builder = globset::GlobSetBuilder::new();
|
||||
let mut negative_builder = globset::GlobSetBuilder::new();
|
||||
for pattern in patterns {
|
||||
let glob = globset::Glob::new(&pattern).map_err(serde::de::Error::custom)?;
|
||||
builder.add(glob);
|
||||
// negative pattern
|
||||
if let Some(stripped) = pattern.strip_prefix("!") {
|
||||
let glob = globset::Glob::new(stripped).map_err(serde::de::Error::custom)?;
|
||||
negative_builder.add(glob);
|
||||
}
|
||||
// escaped pattern
|
||||
else if let Some(_stripped) = pattern.strip_prefix("\\!") {
|
||||
let glob = globset::Glob::new(&pattern[1..]).map_err(serde::de::Error::custom)?;
|
||||
positive_builder.add(glob);
|
||||
}
|
||||
// rest is positive
|
||||
else {
|
||||
let glob = globset::Glob::new(&pattern).map_err(serde::de::Error::custom)?;
|
||||
positive_builder.add(glob);
|
||||
}
|
||||
}
|
||||
builder.build().map(Some).map_err(serde::de::Error::custom)
|
||||
|
||||
let positive_globset = positive_builder.build().map_err(serde::de::Error::custom)?;
|
||||
let negative_globset = negative_builder.build().map_err(serde::de::Error::custom)?;
|
||||
|
||||
Ok((positive_globset, negative_globset))
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
|
@ -403,12 +424,13 @@ pub struct LanguageServerConfiguration {
|
|||
pub config: Option<serde_json::Value>,
|
||||
#[serde(default = "default_timeout")]
|
||||
pub timeout: u64,
|
||||
/// Positive and negative patterns.
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing,
|
||||
deserialize_with = "deserialize_required_root_patterns"
|
||||
)]
|
||||
pub required_root_patterns: Option<GlobSet>,
|
||||
pub required_root_patterns: (GlobSet, GlobSet),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
|
|
@ -888,16 +888,36 @@ fn start_client(
|
|||
let root_path = root.clone().unwrap_or_else(|| workspace.clone());
|
||||
let root_uri = root.and_then(|root| lsp::Url::from_file_path(root).ok());
|
||||
|
||||
if let Some(globset) = &ls_config.required_root_patterns {
|
||||
if !root_path
|
||||
.read_dir()?
|
||||
.flatten()
|
||||
.map(|entry| entry.file_name())
|
||||
.any(|entry| globset.is_match(entry))
|
||||
// match negative and positive root patterns
|
||||
let (positive_globset, negative_globset) = &ls_config.required_root_patterns;
|
||||
let file_names: Vec<_> = root_path
|
||||
.read_dir()?
|
||||
.flatten()
|
||||
.map(|entry| entry.file_name())
|
||||
.collect();
|
||||
// negative
|
||||
if !negative_globset.is_empty() {
|
||||
if let Some(occurence) = file_names
|
||||
.iter()
|
||||
.find(|name| negative_globset.is_match(name))
|
||||
{
|
||||
log::debug!(
|
||||
"negative root pattern {} met for {}",
|
||||
occurence.to_string_lossy(),
|
||||
name
|
||||
);
|
||||
return Err(StartupError::NoRequiredRootFound);
|
||||
}
|
||||
}
|
||||
// positive
|
||||
if !positive_globset.is_empty()
|
||||
&& !file_names
|
||||
.iter()
|
||||
.any(|name| positive_globset.is_match(name))
|
||||
{
|
||||
log::debug!("none of positive root patterns found for {}", name);
|
||||
return Err(StartupError::NoRequiredRootFound);
|
||||
}
|
||||
|
||||
let (client, incoming, initialize_notify) = Client::start(
|
||||
&ls_config.command,
|
||||
|
|
Loading…
Reference in New Issue