mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 05:45:24 +00:00
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:
parent
1b31d4e9f1
commit
c11e6d709c
13 changed files with 379 additions and 96 deletions
|
@ -4,12 +4,16 @@ mod document;
|
|||
mod range;
|
||||
mod replacement;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub use document::Document;
|
||||
pub(crate) use document::DocumentVersion;
|
||||
use lsp_types::PositionEncodingKind;
|
||||
pub(crate) use range::{RangeExt, ToRangeExt};
|
||||
pub(crate) use replacement::Replacement;
|
||||
|
||||
use crate::session::ResolvedClientCapabilities;
|
||||
|
||||
/// A convenient enumeration for supported text encodings. Can be converted to [`lsp_types::PositionEncodingKind`].
|
||||
// Please maintain the order from least to greatest priority for the derived `Ord` impl.
|
||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
@ -25,6 +29,14 @@ pub enum PositionEncoding {
|
|||
UTF8,
|
||||
}
|
||||
|
||||
/// Tracks multi-document edits to eventually merge into a `WorkspaceEdit`.
|
||||
/// Compatible with clients that don't support `workspace.workspaceEdit.documentChanges`.
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum WorkspaceEditTracker {
|
||||
DocumentChanges(Vec<lsp_types::TextDocumentEdit>),
|
||||
Changes(HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>),
|
||||
}
|
||||
|
||||
impl From<PositionEncoding> for lsp_types::PositionEncodingKind {
|
||||
fn from(value: PositionEncoding) -> Self {
|
||||
match value {
|
||||
|
@ -50,3 +62,70 @@ impl TryFrom<&lsp_types::PositionEncodingKind> for PositionEncoding {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl WorkspaceEditTracker {
|
||||
pub(crate) fn new(client_capabilities: &ResolvedClientCapabilities) -> Self {
|
||||
if client_capabilities.document_changes {
|
||||
Self::DocumentChanges(Vec::default())
|
||||
} else {
|
||||
Self::Changes(HashMap::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the edits made to a specific document. This should only be called
|
||||
/// once for each document `uri`, and will fail if this is called for the same `uri`
|
||||
/// multiple times.
|
||||
pub(crate) fn set_edits_for_document(
|
||||
&mut self,
|
||||
uri: lsp_types::Url,
|
||||
version: DocumentVersion,
|
||||
edits: Vec<lsp_types::TextEdit>,
|
||||
) -> crate::Result<()> {
|
||||
match self {
|
||||
Self::DocumentChanges(document_edits) => {
|
||||
if document_edits
|
||||
.iter()
|
||||
.any(|document| document.text_document.uri == uri)
|
||||
{
|
||||
return Err(anyhow::anyhow!(
|
||||
"Attempted to add edits for a document that was already edited"
|
||||
));
|
||||
}
|
||||
document_edits.push(lsp_types::TextDocumentEdit {
|
||||
text_document: lsp_types::OptionalVersionedTextDocumentIdentifier {
|
||||
uri,
|
||||
version: Some(version),
|
||||
},
|
||||
edits: edits.into_iter().map(lsp_types::OneOf::Left).collect(),
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
Self::Changes(changes) => {
|
||||
if changes.get(&uri).is_some() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Attempted to add edits for a document that was already edited"
|
||||
));
|
||||
}
|
||||
changes.insert(uri, edits);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
match self {
|
||||
Self::DocumentChanges(document_edits) => document_edits.is_empty(),
|
||||
Self::Changes(changes) => changes.is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_workspace_edit(self) -> lsp_types::WorkspaceEdit {
|
||||
match self {
|
||||
Self::DocumentChanges(document_edits) => lsp_types::WorkspaceEdit {
|
||||
document_changes: Some(lsp_types::DocumentChanges::Edits(document_edits)),
|
||||
..Default::default()
|
||||
},
|
||||
Self::Changes(changes) => lsp_types::WorkspaceEdit::new(changes),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue