Skip to content

Commit 9dc226b

Browse files
authored
Add supported commands in server capabilities (#11850)
## Summary This PR updates the server capabilities to include the commands that Ruff supports. This is similar to how there's a list of possible code actions supported by the server. I noticed this when I was trying to find whether Helix supported workspace commands or not based on Jane's comment (#11831 (comment)) and I found the `:lsp-workspace-command` in the editor but it didn't show up anything in the picker. So, I looked at the implementation in Helix (https://github.com/helix-editor/helix/blob/9c479e6d2de3bca9dec304f9182cee2b1c0ad766/helix-term/src/commands/typed.rs#L1372-L1384) which made me realize that Ruff doesn't provide this in its capabilities. Currently, this does require `ruff` to be first in the list of language servers in the user config but that should be resolved by helix-editor/helix#10176. So, the following config should work: ```toml [[language]] name = "python" # Ruff should come first until helix-editor/helix#10176 is released language-servers = ["ruff", "pyright"] ``` ## Test Plan 1. Neovim's server capabilities output should include the supported commands: ``` executeCommandProvider = { commands = { "ruff.applyFormat", "ruff.applyAutofix", "ruff.applyOrganizeImports", "ruff.printDebugInformation" }, workDoneProgress = false }, ``` 2. Helix should now display the commands to pick from when `:lsp-workspace-command` is invoked: <img width="832" alt="Screenshot 2024-06-13 at 08 47 14" src="https://github.com/astral-sh/ruff/assets/67177269/09048ecd-c974-4e09-ab56-9482ff3d780b">
1 parent bcbddac commit 9dc226b

File tree

2 files changed

+70
-41
lines changed

2 files changed

+70
-41
lines changed

crates/ruff_server/src/server.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Scheduling, I/O, and API endpoints.
22
33
use std::num::NonZeroUsize;
4+
use std::str::FromStr;
45

56
use lsp_server as lsp;
67
use lsp_types as types;
@@ -276,6 +277,14 @@ impl Server {
276277
},
277278
},
278279
)),
280+
execute_command_provider: Some(types::ExecuteCommandOptions {
281+
commands: SupportedCommand::all()
282+
.map(|command| command.identifier().to_string())
283+
.to_vec(),
284+
work_done_progress_options: WorkDoneProgressOptions {
285+
work_done_progress: Some(false),
286+
},
287+
}),
279288
hover_provider: Some(types::HoverProviderCapability::Simple(true)),
280289
notebook_document_sync: Some(types::OneOf::Left(NotebookDocumentSyncOptions {
281290
save: Some(false),
@@ -354,3 +363,56 @@ impl SupportedCodeAction {
354363
.into_iter()
355364
}
356365
}
366+
367+
#[derive(Clone, Copy, Debug, PartialEq)]
368+
pub(crate) enum SupportedCommand {
369+
Debug,
370+
Format,
371+
FixAll,
372+
OrganizeImports,
373+
}
374+
375+
impl SupportedCommand {
376+
const fn label(self) -> &'static str {
377+
match self {
378+
Self::FixAll => "Fix all auto-fixable problems",
379+
Self::Format => "Format document",
380+
Self::OrganizeImports => "Format imports",
381+
Self::Debug => "Print debug information",
382+
}
383+
}
384+
385+
/// Returns the identifier of the command.
386+
const fn identifier(self) -> &'static str {
387+
match self {
388+
SupportedCommand::Format => "ruff.applyFormat",
389+
SupportedCommand::FixAll => "ruff.applyAutofix",
390+
SupportedCommand::OrganizeImports => "ruff.applyOrganizeImports",
391+
SupportedCommand::Debug => "ruff.printDebugInformation",
392+
}
393+
}
394+
395+
/// Returns all the commands that the server currently supports.
396+
const fn all() -> [SupportedCommand; 4] {
397+
[
398+
SupportedCommand::Format,
399+
SupportedCommand::FixAll,
400+
SupportedCommand::OrganizeImports,
401+
SupportedCommand::Debug,
402+
]
403+
}
404+
}
405+
406+
impl FromStr for SupportedCommand {
407+
type Err = anyhow::Error;
408+
409+
fn from_str(name: &str) -> anyhow::Result<Self, Self::Err> {
410+
Ok(match name {
411+
"ruff.applyAutofix" => Self::FixAll,
412+
"ruff.applyFormat" => Self::Format,
413+
"ruff.applyOrganizeImports" => Self::OrganizeImports,
414+
"ruff.printDebugInformation" => Self::Debug,
415+
_ => return Err(anyhow::anyhow!("Invalid command `{name}`")),
416+
})
417+
}
418+
}

crates/ruff_server/src/server/api/requests/execute_command.rs

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,15 @@ use std::str::FromStr;
22

33
use crate::edit::WorkspaceEditTracker;
44
use crate::server::api::LSPResult;
5-
use crate::server::client;
65
use crate::server::schedule::Task;
6+
use crate::server::{client, SupportedCommand};
77
use crate::session::Session;
88
use crate::DIAGNOSTIC_NAME;
99
use crate::{edit::DocumentVersion, server};
1010
use lsp_server::ErrorCode;
1111
use lsp_types::{self as types, request as req};
1212
use serde::Deserialize;
1313

14-
#[derive(Debug, PartialEq)]
15-
enum Command {
16-
Debug,
17-
Format,
18-
FixAll,
19-
OrganizeImports,
20-
}
21-
2214
pub(crate) struct ExecuteCommand;
2315

2416
#[derive(Deserialize)]
@@ -38,10 +30,10 @@ impl super::SyncRequestHandler for ExecuteCommand {
3830
requester: &mut client::Requester,
3931
params: types::ExecuteCommandParams,
4032
) -> server::Result<Option<serde_json::Value>> {
41-
let command =
42-
Command::from_str(&params.command).with_failure_code(ErrorCode::InvalidParams)?;
33+
let command = SupportedCommand::from_str(&params.command)
34+
.with_failure_code(ErrorCode::InvalidParams)?;
4335

44-
if command == Command::Debug {
36+
if command == SupportedCommand::Debug {
4537
let output = debug_information(session);
4638
notifier
4739
.notify::<types::notification::LogMessage>(types::LogMessageParams {
@@ -74,7 +66,7 @@ impl super::SyncRequestHandler for ExecuteCommand {
7466
return Ok(None);
7567
};
7668
match command {
77-
Command::FixAll => {
69+
SupportedCommand::FixAll => {
7870
let fixes = super::code_action_resolve::fix_all_edit(
7971
snapshot.query(),
8072
snapshot.encoding(),
@@ -84,13 +76,13 @@ impl super::SyncRequestHandler for ExecuteCommand {
8476
.set_fixes_for_document(fixes, snapshot.query().version())
8577
.with_failure_code(ErrorCode::InternalError)?;
8678
}
87-
Command::Format => {
79+
SupportedCommand::Format => {
8880
let fixes = super::format::format_full_document(&snapshot)?;
8981
edit_tracker
9082
.set_fixes_for_document(fixes, version)
9183
.with_failure_code(ErrorCode::InternalError)?;
9284
}
93-
Command::OrganizeImports => {
85+
SupportedCommand::OrganizeImports => {
9486
let fixes = super::code_action_resolve::organize_imports_edit(
9587
snapshot.query(),
9688
snapshot.encoding(),
@@ -100,7 +92,7 @@ impl super::SyncRequestHandler for ExecuteCommand {
10092
.set_fixes_for_document(fixes, snapshot.query().version())
10193
.with_failure_code(ErrorCode::InternalError)?;
10294
}
103-
Command::Debug => {
95+
SupportedCommand::Debug => {
10496
unreachable!("The debug command should have already been handled")
10597
}
10698
}
@@ -119,31 +111,6 @@ impl super::SyncRequestHandler for ExecuteCommand {
119111
}
120112
}
121113

122-
impl Command {
123-
fn label(&self) -> &str {
124-
match self {
125-
Self::FixAll => "Fix all auto-fixable problems",
126-
Self::Format => "Format document",
127-
Self::OrganizeImports => "Format imports",
128-
Self::Debug => "Print debug information",
129-
}
130-
}
131-
}
132-
133-
impl FromStr for Command {
134-
type Err = anyhow::Error;
135-
136-
fn from_str(name: &str) -> Result<Self, Self::Err> {
137-
Ok(match name {
138-
"ruff.applyAutofix" => Self::FixAll,
139-
"ruff.applyFormat" => Self::Format,
140-
"ruff.applyOrganizeImports" => Self::OrganizeImports,
141-
"ruff.printDebugInformation" => Self::Debug,
142-
_ => return Err(anyhow::anyhow!("Invalid command `{name}`")),
143-
})
144-
}
145-
}
146-
147114
fn apply_edit(
148115
requester: &mut client::Requester,
149116
label: &str,

0 commit comments

Comments
 (0)