mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 20:42:10 +00:00
Enable ruff-specific source actions (#10916)
## Summary Fixes #10780. The server now send code actions to the client with a Ruff-specific kind, `source.*.ruff`. The kind filtering logic has also been reworked to support this. ## Test Plan Add this to your `settings.json` in VS Code: ```json { "[python]": { "editor.codeActionsOnSave": { "source.organizeImports.ruff": "explicit", }, } } ``` Imports should be automatically organized when you manually save with `Ctrl/Cmd+S`.
This commit is contained in:
parent
cffc55576f
commit
eab3c4e334
3 changed files with 40 additions and 47 deletions
|
@ -224,7 +224,7 @@ impl Server {
|
||||||
CodeActionOptions {
|
CodeActionOptions {
|
||||||
code_action_kinds: Some(
|
code_action_kinds: Some(
|
||||||
SupportedCodeAction::all()
|
SupportedCodeAction::all()
|
||||||
.flat_map(|action| action.kinds().into_iter())
|
.map(SupportedCodeAction::to_kind)
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
work_done_progress_options: WorkDoneProgressOptions {
|
work_done_progress_options: WorkDoneProgressOptions {
|
||||||
|
@ -284,18 +284,21 @@ pub(crate) enum SupportedCodeAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SupportedCodeAction {
|
impl SupportedCodeAction {
|
||||||
/// Returns the possible LSP code action kind(s) that map to this code action.
|
/// Returns the LSP code action kind that map to this code action.
|
||||||
fn kinds(self) -> Vec<CodeActionKind> {
|
fn to_kind(self) -> CodeActionKind {
|
||||||
match self {
|
match self {
|
||||||
Self::QuickFix => vec![CodeActionKind::QUICKFIX],
|
Self::QuickFix => CodeActionKind::QUICKFIX,
|
||||||
Self::SourceFixAll => vec![CodeActionKind::SOURCE_FIX_ALL, crate::SOURCE_FIX_ALL_RUFF],
|
Self::SourceFixAll => crate::SOURCE_FIX_ALL_RUFF,
|
||||||
Self::SourceOrganizeImports => vec![
|
Self::SourceOrganizeImports => crate::SOURCE_ORGANIZE_IMPORTS_RUFF,
|
||||||
CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
|
|
||||||
crate::SOURCE_ORGANIZE_IMPORTS_RUFF,
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_kind(kind: CodeActionKind) -> impl Iterator<Item = Self> {
|
||||||
|
Self::all().filter(move |supported_kind| {
|
||||||
|
supported_kind.to_kind().as_str().starts_with(kind.as_str())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns all code actions kinds that the server currently supports.
|
/// Returns all code actions kinds that the server currently supports.
|
||||||
fn all() -> impl Iterator<Item = Self> {
|
fn all() -> impl Iterator<Item = Self> {
|
||||||
[
|
[
|
||||||
|
@ -306,16 +309,3 @@ impl SupportedCodeAction {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<CodeActionKind> for SupportedCodeAction {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(kind: CodeActionKind) -> std::result::Result<Self, Self::Error> {
|
|
||||||
for supported_kind in Self::all() {
|
|
||||||
if supported_kind.kinds().contains(&kind) {
|
|
||||||
return Ok(supported_kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -112,14 +112,14 @@ fn fix_all(snapshot: &DocumentSnapshot) -> crate::Result<CodeActionOrCommand> {
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let action = types::CodeAction {
|
|
||||||
|
Ok(CodeActionOrCommand::CodeAction(types::CodeAction {
|
||||||
title: format!("{DIAGNOSTIC_NAME}: Fix all auto-fixable problems"),
|
title: format!("{DIAGNOSTIC_NAME}: Fix all auto-fixable problems"),
|
||||||
kind: Some(types::CodeActionKind::SOURCE_FIX_ALL),
|
kind: Some(crate::SOURCE_FIX_ALL_RUFF),
|
||||||
edit,
|
edit,
|
||||||
data,
|
data,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
}))
|
||||||
Ok(types::CodeActionOrCommand::CodeAction(action))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn organize_imports(snapshot: &DocumentSnapshot) -> crate::Result<CodeActionOrCommand> {
|
fn organize_imports(snapshot: &DocumentSnapshot) -> crate::Result<CodeActionOrCommand> {
|
||||||
|
@ -147,14 +147,14 @@ fn organize_imports(snapshot: &DocumentSnapshot) -> crate::Result<CodeActionOrCo
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let action = types::CodeAction {
|
|
||||||
|
Ok(CodeActionOrCommand::CodeAction(types::CodeAction {
|
||||||
title: format!("{DIAGNOSTIC_NAME}: Organize imports"),
|
title: format!("{DIAGNOSTIC_NAME}: Organize imports"),
|
||||||
kind: Some(types::CodeActionKind::SOURCE_ORGANIZE_IMPORTS),
|
kind: Some(crate::SOURCE_ORGANIZE_IMPORTS_RUFF),
|
||||||
edit,
|
edit,
|
||||||
data,
|
data,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
}))
|
||||||
Ok(types::CodeActionOrCommand::CodeAction(action))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `action_filter` is `None`, this returns [`SupportedCodeActionKind::all()`]. Otherwise,
|
/// If `action_filter` is `None`, this returns [`SupportedCodeActionKind::all()`]. Otherwise,
|
||||||
|
@ -166,14 +166,8 @@ fn supported_code_actions(
|
||||||
return SupportedCodeAction::all().collect();
|
return SupportedCodeAction::all().collect();
|
||||||
};
|
};
|
||||||
|
|
||||||
SupportedCodeAction::all()
|
action_filter
|
||||||
.filter(move |action| {
|
.into_iter()
|
||||||
action_filter.iter().any(|filter| {
|
.flat_map(SupportedCodeAction::from_kind)
|
||||||
action
|
|
||||||
.kinds()
|
|
||||||
.iter()
|
|
||||||
.any(|kind| kind.as_str().starts_with(filter.as_str()))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,14 +30,23 @@ impl super::BackgroundDocumentRequestHandler for CodeActionResolve {
|
||||||
) -> Result<types::CodeAction> {
|
) -> Result<types::CodeAction> {
|
||||||
let document = snapshot.document();
|
let document = snapshot.document();
|
||||||
|
|
||||||
let action_kind: SupportedCodeAction = action
|
let code_actions = SupportedCodeAction::from_kind(
|
||||||
.kind
|
action
|
||||||
.clone()
|
.kind
|
||||||
.ok_or(anyhow::anyhow!("No kind was given for code action"))
|
.clone()
|
||||||
.with_failure_code(ErrorCode::InvalidParams)?
|
.ok_or(anyhow::anyhow!("No kind was given for code action"))
|
||||||
.try_into()
|
.with_failure_code(ErrorCode::InvalidParams)?,
|
||||||
.map_err(|()| anyhow::anyhow!("Code action was of an invalid kind"))
|
)
|
||||||
.with_failure_code(ErrorCode::InvalidParams)?;
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Ensure that the code action maps to _exactly one_ supported code action
|
||||||
|
let [action_kind] = code_actions.as_slice() else {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"Code action resolver did not expect code action kind {:?}",
|
||||||
|
action.kind.as_ref().unwrap()
|
||||||
|
))
|
||||||
|
.with_failure_code(ErrorCode::InvalidParams);
|
||||||
|
};
|
||||||
|
|
||||||
action.edit = match action_kind {
|
action.edit = match action_kind {
|
||||||
SupportedCodeAction::SourceFixAll => Some(
|
SupportedCodeAction::SourceFixAll => Some(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue