ruff server now supports commands for auto-fixing, organizing imports, and formatting (#10654)

## Summary

This builds off of the work in
https://github.com/astral-sh/ruff/pull/10652 to implement a command
executor, backwards compatible with the commands from the previous LSP
(`ruff.applyAutofix`, `ruff.applyFormat` and
`ruff.applyOrganizeImports`).

This involved a lot of refactoring and tweaks to the code action
resolution code - the most notable change is that workspace edits are
specified in a slightly different way, using the more general `changes`
field instead of the `document_changes` field (which isn't supported on
all LSP clients). Additionally, the API for synchronous request handlers
has been updated to include access to the `Requester`, which we use to
send a `workspace/applyEdit` request to the client.

## Test Plan



7932e30f-d944-4e35-b828-1d81aa56c087
This commit is contained in:
Jane Lewis 2024-04-05 16:27:35 -07:00 committed by GitHub
parent 1b31d4e9f1
commit c11e6d709c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 379 additions and 96 deletions

View file

@ -1,3 +1,4 @@
use crate::edit::WorkspaceEditTracker;
use crate::lint::fixes_for_diagnostics;
use crate::server::api::LSPResult;
use crate::server::SupportedCodeAction;
@ -50,30 +51,34 @@ impl super::BackgroundDocumentRequestHandler for CodeActions {
fn quick_fix(
snapshot: &DocumentSnapshot,
diagnostics: Vec<types::Diagnostic>,
) -> crate::Result<impl Iterator<Item = CodeActionOrCommand> + '_> {
) -> crate::Result<Vec<CodeActionOrCommand>> {
let document = snapshot.document();
let fixes = fixes_for_diagnostics(
document,
snapshot.url(),
snapshot.encoding(),
document.version(),
diagnostics,
)?;
let fixes = fixes_for_diagnostics(document, snapshot.encoding(), diagnostics)?;
Ok(fixes.into_iter().map(|fix| {
types::CodeActionOrCommand::CodeAction(types::CodeAction {
title: format!("{DIAGNOSTIC_NAME} ({}): {}", fix.code, fix.title),
kind: Some(types::CodeActionKind::QUICKFIX),
edit: Some(types::WorkspaceEdit {
document_changes: Some(types::DocumentChanges::Edits(fix.document_edits.clone())),
fixes
.into_iter()
.map(|fix| {
let mut tracker = WorkspaceEditTracker::new(snapshot.resolved_client_capabilities());
tracker.set_edits_for_document(
snapshot.url().clone(),
document.version(),
fix.edits,
)?;
Ok(types::CodeActionOrCommand::CodeAction(types::CodeAction {
title: format!("{DIAGNOSTIC_NAME} ({}): {}", fix.code, fix.title),
kind: Some(types::CodeActionKind::QUICKFIX),
edit: Some(tracker.into_workspace_edit()),
diagnostics: Some(vec![fix.fixed_diagnostic.clone()]),
data: Some(
serde_json::to_value(snapshot.url()).expect("document url to serialize"),
),
..Default::default()
}),
diagnostics: Some(vec![fix.fixed_diagnostic.clone()]),
data: Some(serde_json::to_value(snapshot.url()).expect("document url to serialize")),
..Default::default()
}))
})
}))
.collect()
}
fn fix_all(snapshot: &DocumentSnapshot) -> crate::Result<CodeActionOrCommand> {
@ -92,9 +97,11 @@ fn fix_all(snapshot: &DocumentSnapshot) -> crate::Result<CodeActionOrCommand> {
(
Some(resolve_edit_for_fix_all(
document,
snapshot.resolved_client_capabilities(),
snapshot.url(),
&snapshot.configuration().linter,
snapshot.encoding(),
document.version(),
)?),
None,
)
@ -125,9 +132,11 @@ fn organize_imports(snapshot: &DocumentSnapshot) -> crate::Result<CodeActionOrCo
(
Some(resolve_edit_for_organize_imports(
document,
snapshot.resolved_client_capabilities(),
snapshot.url(),
&snapshot.configuration().linter,
snapshot.encoding(),
document.version(),
)?),
None,
)