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 |
|
| `config` | Language server initialization options |
|
||||||
| `timeout` | The maximum time a request to the language server may take, in seconds. Defaults to `20` |
|
| `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" }` |
|
| `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
|
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).
|
[Document Formatting Requests](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_formatting).
|
||||||
|
|
|
@ -75,6 +75,7 @@
|
||||||
lld
|
lld
|
||||||
cargo-flamegraph
|
cargo-flamegraph
|
||||||
rust-bin.nightly.latest.rust-analyzer
|
rust-bin.nightly.latest.rust-analyzer
|
||||||
|
rust-bin.nightly.latest.clippy
|
||||||
]
|
]
|
||||||
++ (lib.optional (stdenv.isx86_64 && stdenv.isLinux) cargo-tarpaulin)
|
++ (lib.optional (stdenv.isx86_64 && stdenv.isLinux) cargo-tarpaulin)
|
||||||
++ (lib.optional stdenv.isLinux lldb)
|
++ (lib.optional stdenv.isLinux lldb)
|
||||||
|
|
|
@ -374,20 +374,41 @@ where
|
||||||
serializer.end()
|
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
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
let patterns = Vec::<String>::deserialize(deserializer)?;
|
let patterns = Vec::<String>::deserialize(deserializer)?;
|
||||||
if patterns.is_empty() {
|
|
||||||
return Ok(None);
|
let mut positive_builder = globset::GlobSetBuilder::new();
|
||||||
}
|
let mut negative_builder = globset::GlobSetBuilder::new();
|
||||||
let mut builder = globset::GlobSetBuilder::new();
|
|
||||||
for pattern in patterns {
|
for pattern in patterns {
|
||||||
let glob = globset::Glob::new(&pattern).map_err(serde::de::Error::custom)?;
|
// negative pattern
|
||||||
builder.add(glob);
|
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)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
@ -403,12 +424,13 @@ 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,
|
||||||
|
/// Positive and negative patterns.
|
||||||
#[serde(
|
#[serde(
|
||||||
default,
|
default,
|
||||||
skip_serializing,
|
skip_serializing,
|
||||||
deserialize_with = "deserialize_required_root_patterns"
|
deserialize_with = "deserialize_required_root_patterns"
|
||||||
)]
|
)]
|
||||||
pub required_root_patterns: Option<GlobSet>,
|
pub required_root_patterns: (GlobSet, GlobSet),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|
|
@ -888,16 +888,36 @@ 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());
|
||||||
|
|
||||||
if let Some(globset) = &ls_config.required_root_patterns {
|
// match negative and positive root patterns
|
||||||
if !root_path
|
let (positive_globset, negative_globset) = &ls_config.required_root_patterns;
|
||||||
.read_dir()?
|
let file_names: Vec<_> = root_path
|
||||||
.flatten()
|
.read_dir()?
|
||||||
.map(|entry| entry.file_name())
|
.flatten()
|
||||||
.any(|entry| globset.is_match(entry))
|
.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);
|
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(
|
let (client, incoming, initialize_notify) = Client::start(
|
||||||
&ls_config.command,
|
&ls_config.command,
|
||||||
|
|
Loading…
Reference in New Issue