Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement LSP workspace/configuration and workspace/didChangeConfiguration #1684

Merged
merged 4 commits into from
Feb 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions helix-lsp/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,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
Expand Down Expand Up @@ -243,6 +247,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 {
Expand Down Expand Up @@ -327,6 +338,16 @@ impl Client {
self.exit().await
}

// -------------------------------------------------------------------------------------------
// Workspace
// -------------------------------------------------------------------------------------------

pub fn did_change_configuration(&self, settings: Value) -> impl Future<Output = Result<()>> {
self.notify::<lsp::notification::DidChangeConfiguration>(
lsp::DidChangeConfigurationParams { settings },
)
}

// -------------------------------------------------------------------------------------------
// Text document
// -------------------------------------------------------------------------------------------
Expand Down
7 changes: 7 additions & 0 deletions helix-lsp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ pub mod util {
pub enum MethodCall {
WorkDoneProgressCreate(lsp::WorkDoneProgressCreateParams),
ApplyWorkspaceEdit(lsp::ApplyWorkspaceEditParams),
WorkspaceConfiguration(lsp::ConfigurationParams),
}

impl MethodCall {
Expand All @@ -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;
Expand Down
38 changes: 38 additions & 0 deletions helix-term/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,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)
});
Expand Down Expand Up @@ -807,6 +814,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),
Expand Down