aboutsummaryrefslogtreecommitdiff
path: root/helix-lsp/src
diff options
context:
space:
mode:
authorontley2024-02-12 01:35:25 +0000
committerGitHub2024-02-12 01:35:25 +0000
commit6a90166d0a3d8fd0e2e96e4ac8e196b2b2989760 (patch)
treee722b996e123813e2fb0f9972136fa6002ca1839 /helix-lsp/src
parentac8d1f62a126781fbac087aa374aad540dd659b1 (diff)
Add required-root-patterns for situational lsp activation (#8696)
* Added required-root-patterns for situational lsp activation using globbing * Replaced filter_map with flatten * updated book to include required-root-patterns option * fixed wrong function name for path * Added globset to helix-core. Moved globset building to config parsing. * Normalize implements AsRef * cargo fmt * Revert "cargo fmt" This reverts commit ca8ce123e8d77d2ae8ed84d5273a9b554101b0db.
Diffstat (limited to 'helix-lsp/src')
-rw-r--r--helix-lsp/src/client.rs21
-rw-r--r--helix-lsp/src/lib.rs63
2 files changed, 49 insertions, 35 deletions
diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs
index 94bad6fa..0d3a2a56 100644
--- a/helix-lsp/src/client.rs
+++ b/helix-lsp/src/client.rs
@@ -177,12 +177,11 @@ impl Client {
args: &[String],
config: Option<Value>,
server_environment: HashMap<String, String>,
- root_markers: &[String],
- manual_roots: &[PathBuf],
+ root_path: PathBuf,
+ root_uri: Option<lsp::Url>,
id: usize,
name: String,
req_timeout: u64,
- doc_path: Option<&std::path::PathBuf>,
) -> Result<(Self, UnboundedReceiver<(usize, Call)>, Arc<Notify>)> {
// Resolve path to the binary
let cmd = helix_stdx::env::which(cmd)?;
@@ -206,22 +205,6 @@ impl Client {
let (server_rx, server_tx, initialize_notify) =
Transport::start(reader, writer, stderr, id, name.clone());
- let (workspace, workspace_is_cwd) = find_workspace();
- let workspace = path::normalize(workspace);
- let root = find_lsp_workspace(
- doc_path
- .and_then(|x| x.parent().and_then(|x| x.to_str()))
- .unwrap_or("."),
- root_markers,
- manual_roots,
- &workspace,
- workspace_is_cwd,
- );
-
- // `root_uri` and `workspace_folder` can be empty in case there is no workspace
- // `root_url` can not, use `workspace` as a fallback
- 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 workspace_folders = root_uri
.clone()
diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs
index 4ce445ae..05764418 100644
--- a/helix-lsp/src/lib.rs
+++ b/helix-lsp/src/lib.rs
@@ -680,7 +680,7 @@ impl Registry {
doc_path: Option<&std::path::PathBuf>,
root_dirs: &[PathBuf],
enable_snippets: bool,
- ) -> Result<Arc<Client>> {
+ ) -> Result<Option<Arc<Client>>> {
let config = self
.syn_loader
.language_server_configs()
@@ -688,7 +688,7 @@ impl Registry {
.ok_or_else(|| anyhow::anyhow!("Language server '{name}' not defined"))?;
let id = self.counter;
self.counter += 1;
- let NewClient(client, incoming) = start_client(
+ if let Some(NewClient(client, incoming)) = start_client(
id,
name,
ls_config,
@@ -696,9 +696,12 @@ impl Registry {
doc_path,
root_dirs,
enable_snippets,
- )?;
- self.incoming.push(UnboundedReceiverStream::new(incoming));
- Ok(client)
+ )? {
+ self.incoming.push(UnboundedReceiverStream::new(incoming));
+ Ok(Some(client))
+ } else {
+ Ok(None)
+ }
}
/// If this method is called, all documents that have a reference to language servers used by the language config have to refresh their language servers,
@@ -723,8 +726,8 @@ impl Registry {
root_dirs,
enable_snippets,
) {
- Ok(client) => client,
- error => return Some(error),
+ Ok(client) => client?,
+ Err(error) => return Some(Err(error)),
};
let old_clients = self
.inner
@@ -764,13 +767,13 @@ impl Registry {
root_dirs: &'a [PathBuf],
enable_snippets: bool,
) -> impl Iterator<Item = (LanguageServerName, Result<Arc<Client>>)> + 'a {
- language_config.language_servers.iter().map(
+ language_config.language_servers.iter().filter_map(
move |LanguageServerFeatures { name, .. }| {
if let Some(clients) = self.inner.get(name) {
if let Some((_, client)) = clients.iter().enumerate().find(|(i, client)| {
client.try_add_doc(&language_config.roots, root_dirs, doc_path, *i == 0)
}) {
- return (name.to_owned(), Ok(client.clone()));
+ return Some((name.to_owned(), Ok(client.clone())));
}
}
match self.start_client(
@@ -781,13 +784,14 @@ impl Registry {
enable_snippets,
) {
Ok(client) => {
+ let client = client?;
self.inner
.entry(name.to_owned())
.or_default()
.push(client.clone());
- (name.clone(), Ok(client))
+ Some((name.clone(), Ok(client)))
}
- Err(err) => (name.to_owned(), Err(err)),
+ Err(err) => Some((name.to_owned(), Err(err))),
}
},
)
@@ -888,18 +892,45 @@ fn start_client(
doc_path: Option<&std::path::PathBuf>,
root_dirs: &[PathBuf],
enable_snippets: bool,
-) -> Result<NewClient> {
+) -> Result<Option<NewClient>> {
+ let (workspace, workspace_is_cwd) = helix_loader::find_workspace();
+ let workspace = path::normalize(workspace);
+ let root = find_lsp_workspace(
+ doc_path
+ .and_then(|x| x.parent().and_then(|x| x.to_str()))
+ .unwrap_or("."),
+ &config.roots,
+ config.workspace_lsp_roots.as_deref().unwrap_or(root_dirs),
+ &workspace,
+ workspace_is_cwd,
+ );
+
+ // `root_uri` and `workspace_folder` can be empty in case there is no workspace
+ // `root_url` can not, use `workspace` as a fallback
+ 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))
+ {
+ return Ok(None);
+ }
+ }
+
let (client, incoming, initialize_notify) = Client::start(
&ls_config.command,
&ls_config.args,
ls_config.config.clone(),
ls_config.environment.clone(),
- &config.roots,
- config.workspace_lsp_roots.as_deref().unwrap_or(root_dirs),
+ root_path,
+ root_uri,
id,
name,
ls_config.timeout,
- doc_path,
)?;
let client = Arc::new(client);
@@ -938,7 +969,7 @@ fn start_client(
initialize_notify.notify_one();
});
- Ok(NewClient(client, incoming))
+ Ok(Some(NewClient(client, incoming)))
}
/// Find an LSP workspace of a file using the following mechanism: