aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTriton1712022-02-28 08:57:22 +0000
committerGitHub2022-02-28 08:57:22 +0000
commitf044059a2a44c65533aa4704fffd911476060c05 (patch)
tree1aa79c761b570109c4ca683b8770ab7336a05d26
parentc15996aff597aa8cb63850c6080bc69470bb84a5 (diff)
Implement LSP `workspace/configuration` and `workspace/didChangeConfiguration` (#1684)
* Implement LSP `workspace/configuration` request * Implement LSP `workspace/didChangeConfiguration` notification. * Simplify retrieval of LSP configuration * Implement suggestions from PR discussion Co-authored-by: Triton171 <triton0171@gmail.com>
-rw-r--r--helix-lsp/src/client.rs21
-rw-r--r--helix-lsp/src/lib.rs7
-rw-r--r--helix-term/src/application.rs38
3 files changed, 66 insertions, 0 deletions
diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs
index 362498cb..1ce5158b 100644
--- a/helix-lsp/src/client.rs
+++ b/helix-lsp/src/client.rs
@@ -113,6 +113,10 @@ impl Client {
self.offset_encoding
}
+ pub fn config(&self) -> Option<&Value> {
+ self.config.as_ref()
+ }
+
/// Execute a RPC request on the language server.
async fn request<R: lsp::request::Request>(&self, params: R::Params) -> Result<R::Result>
where
@@ -246,6 +250,13 @@ impl Client {
root_uri: root,
initialization_options: self.config.clone(),
capabilities: lsp::ClientCapabilities {
+ workspace: Some(lsp::WorkspaceClientCapabilities {
+ configuration: Some(true),
+ did_change_configuration: Some(lsp::DynamicRegistrationClientCapabilities {
+ dynamic_registration: Some(false),
+ }),
+ ..Default::default()
+ }),
text_document: Some(lsp::TextDocumentClientCapabilities {
completion: Some(lsp::CompletionClientCapabilities {
completion_item: Some(lsp::CompletionItemCapability {
@@ -331,6 +342,16 @@ impl Client {
}
// -------------------------------------------------------------------------------------------
+ // Workspace
+ // -------------------------------------------------------------------------------------------
+
+ pub fn did_change_configuration(&self, settings: Value) -> impl Future<Output = Result<()>> {
+ self.notify::<lsp::notification::DidChangeConfiguration>(
+ lsp::DidChangeConfigurationParams { settings },
+ )
+ }
+
+ // -------------------------------------------------------------------------------------------
// Text document
// -------------------------------------------------------------------------------------------
diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs
index 109546d0..389dfb4d 100644
--- a/helix-lsp/src/lib.rs
+++ b/helix-lsp/src/lib.rs
@@ -191,6 +191,7 @@ pub mod util {
pub enum MethodCall {
WorkDoneProgressCreate(lsp::WorkDoneProgressCreateParams),
ApplyWorkspaceEdit(lsp::ApplyWorkspaceEditParams),
+ WorkspaceConfiguration(lsp::ConfigurationParams),
}
impl MethodCall {
@@ -209,6 +210,12 @@ impl MethodCall {
.expect("Failed to parse ApplyWorkspaceEdit params");
Self::ApplyWorkspaceEdit(params)
}
+ lsp::request::WorkspaceConfiguration::METHOD => {
+ let params: lsp::ConfigurationParams = params
+ .parse()
+ .expect("Failed to parse WorkspaceConfiguration params");
+ Self::WorkspaceConfiguration(params)
+ }
_ => {
log::warn!("unhandled lsp request: {}", method);
return None;
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs
index 986df703..2a7c9c21 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -532,6 +532,13 @@ impl Application {
}
};
+ // Trigger a workspace/didChangeConfiguration notification after initialization.
+ // This might not be required by the spec but Neovim does this as well, so it's
+ // probably a good idea for compatibility.
+ if let Some(config) = language_server.config() {
+ tokio::spawn(language_server.did_change_configuration(config.clone()));
+ }
+
let docs = self.editor.documents().filter(|doc| {
doc.language_server().map(|server| server.id()) == Some(server_id)
});
@@ -788,6 +795,37 @@ impl Application {
})),
));
}
+ MethodCall::WorkspaceConfiguration(params) => {
+ let language_server =
+ match self.editor.language_servers.get_by_id(server_id) {
+ Some(language_server) => language_server,
+ None => {
+ warn!("can't find language server with id `{}`", server_id);
+ return;
+ }
+ };
+ let result: Vec<_> = params
+ .items
+ .iter()
+ .map(|item| {
+ let mut config = match &item.scope_uri {
+ Some(scope) => {
+ let path = scope.to_file_path().ok()?;
+ let doc = self.editor.document_by_path(path)?;
+ doc.language_config()?.config.as_ref()?
+ }
+ None => language_server.config()?,
+ };
+ if let Some(section) = item.section.as_ref() {
+ for part in section.split('.') {
+ config = config.get(part)?;
+ }
+ }
+ Some(config)
+ })
+ .collect();
+ tokio::spawn(language_server.reply(id, Ok(json!(result))));
+ }
}
}
e => unreachable!("{:?}", e),