Skip to content

Commit a252feb

Browse files
committed
set server and check client capabilities for commands and workspace edits
1 parent e18effd commit a252feb

File tree

4 files changed

+119
-9
lines changed

4 files changed

+119
-9
lines changed

crates/lsp-server/src/dispatch.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,13 @@ impl<'a> Dispatcher<'a> {
9595

9696
// Sends response (if any).
9797
if let Some(mut resp) = result {
98-
// Intercept non-empty `createProject` responses and create the project as a workspace edit.
99-
if let Some(project) = is_execute_command
100-
.then_some(resp.result.as_ref())
101-
.flatten()
102-
.and_then(|value| {
103-
serde_json::from_value::<CreateProjectResponse>(value.clone()).ok()
104-
})
98+
// Intercept non-empty `createProject` responses and create the project as a workspace edit
99+
// (only if the client supports the resource operations and document changes).
100+
if let Some(project) = (is_execute_command
101+
&& utils::can_create_project_via_workspace_edit(&self.client_capabilities))
102+
.then_some(resp.result.as_ref())
103+
.flatten()
104+
.and_then(|value| serde_json::from_value::<CreateProjectResponse>(value.clone()).ok())
105105
{
106106
// Return an empty response.
107107
resp.result = Some(serde_json::Value::Null);

crates/lsp-server/src/initialize.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ pub fn server_capabilities(
8787
retrigger_characters: None,
8888
work_done_progress_options: Default::default(),
8989
}),
90+
execute_command_provider: Some(lsp_types::ExecuteCommandOptions {
91+
commands: vec!["createProject".to_string()],
92+
work_done_progress_options: Default::default(),
93+
}),
9094
..Default::default()
9195
}
9296
}

crates/lsp-server/src/utils.rs

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,32 @@ pub fn request_id_as_str(id: RequestId) -> Option<String> {
104104
.map(ToString::to_string)
105105
}
106106

107+
/// Returns true if the LSP client advertises capabilities needed to create new projects via workspace edit, or false otherwise.
108+
pub fn can_create_project_via_workspace_edit(client_capabilities: &ClientCapabilities) -> bool {
109+
client_capabilities.workspace.as_ref().map_or(false, |it| {
110+
// Checks support for workspace/applyEdit requests.
111+
it.apply_edit.unwrap_or(false)
112+
&& it.workspace_edit.as_ref().map_or(false, |it| {
113+
// Checks support for versioned document changes.
114+
it.document_changes.unwrap_or(false)
115+
// Checks support for create file operation.
116+
&& it.resource_operations.as_ref().map_or(false, |it| {
117+
it.contains(&lsp_types::ResourceOperationKind::Create)
118+
})
119+
})
120+
})
121+
}
122+
107123
#[cfg(test)]
108124
mod tests {
109125
use super::*;
110126
use crate::utils::{code_actions_kinds, position_encoding, SERVER_CODE_ACTION_KINDS};
111127
use lsp_types::{
112128
CodeActionClientCapabilities, CodeActionKindLiteralSupport, CodeActionLiteralSupport,
113129
CompletionClientCapabilities, CompletionItemCapability, GeneralClientCapabilities,
114-
ParameterInformationSettings, SignatureHelpClientCapabilities,
115-
SignatureInformationSettings, TextDocumentClientCapabilities,
130+
ParameterInformationSettings, ResourceOperationKind, SignatureHelpClientCapabilities,
131+
SignatureInformationSettings, TextDocumentClientCapabilities, WorkspaceClientCapabilities,
132+
WorkspaceEditClientCapabilities,
116133
};
117134

118135
fn config_with_encodings(encodings: Option<Vec<PositionEncodingKind>>) -> ClientCapabilities {
@@ -183,6 +200,25 @@ mod tests {
183200
}
184201
}
185202

203+
fn config_with_workspace_edit_capabilities(
204+
apply_edit: Option<bool>,
205+
document_changes: Option<bool>,
206+
resource_operations: Option<Vec<ResourceOperationKind>>,
207+
) -> ClientCapabilities {
208+
ClientCapabilities {
209+
workspace: Some(WorkspaceClientCapabilities {
210+
apply_edit,
211+
workspace_edit: Some(WorkspaceEditClientCapabilities {
212+
document_changes,
213+
resource_operations,
214+
..Default::default()
215+
}),
216+
..Default::default()
217+
}),
218+
..Default::default()
219+
}
220+
}
221+
186222
#[test]
187223
fn position_encoding_works() {
188224
for (client_capabilities, expected_encoding) in [
@@ -366,4 +402,61 @@ mod tests {
366402
assert_eq!(signature_support(&client_capabilities), expected_result);
367403
}
368404
}
405+
406+
#[test]
407+
fn can_create_project_via_workspace_edit_works() {
408+
for (client_capabilities, expected_result) in [
409+
// Default is `false`.
410+
(ClientCapabilities::default(), false),
411+
// None is `false`.
412+
(
413+
config_with_workspace_edit_capabilities(None, None, None),
414+
false,
415+
),
416+
// Partial support for some conditions fails.
417+
(
418+
config_with_workspace_edit_capabilities(Some(true), None, None),
419+
false,
420+
),
421+
(
422+
config_with_workspace_edit_capabilities(None, Some(true), None),
423+
false,
424+
),
425+
(
426+
config_with_workspace_edit_capabilities(
427+
None,
428+
None,
429+
Some(vec![ResourceOperationKind::Create]),
430+
),
431+
false,
432+
),
433+
(
434+
config_with_workspace_edit_capabilities(
435+
Some(true),
436+
Some(true),
437+
// Missing create operation.
438+
Some(vec![
439+
ResourceOperationKind::Delete,
440+
ResourceOperationKind::Rename,
441+
]),
442+
),
443+
false,
444+
),
445+
// Full support for all conditions works.
446+
(
447+
config_with_workspace_edit_capabilities(
448+
Some(true),
449+
Some(true),
450+
Some(vec![ResourceOperationKind::Create]),
451+
),
452+
true,
453+
),
454+
] {
455+
// Verifies the expected result based on client capabilities.
456+
assert_eq!(
457+
can_create_project_via_workspace_edit(&client_capabilities),
458+
expected_result
459+
);
460+
}
461+
}
369462
}

crates/test-utils/src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,19 @@ pub fn simple_client_config() -> lsp_types::ClientCapabilities {
145145
}),
146146
..Default::default()
147147
}),
148+
workspace: Some(lsp_types::WorkspaceClientCapabilities {
149+
apply_edit: Some(true),
150+
workspace_edit: Some(lsp_types::WorkspaceEditClientCapabilities {
151+
document_changes: Some(true),
152+
resource_operations: Some(vec![
153+
lsp_types::ResourceOperationKind::Create,
154+
lsp_types::ResourceOperationKind::Delete,
155+
lsp_types::ResourceOperationKind::Rename,
156+
]),
157+
..Default::default()
158+
}),
159+
..Default::default()
160+
}),
148161
..Default::default()
149162
}
150163
}

0 commit comments

Comments
 (0)