diff --git a/crates/ruff_server/src/server/api/requests/code_action.rs b/crates/ruff_server/src/server/api/requests/code_action.rs index 255cfdf0ad..ca43ed6cd5 100644 --- a/crates/ruff_server/src/server/api/requests/code_action.rs +++ b/crates/ruff_server/src/server/api/requests/code_action.rs @@ -48,7 +48,15 @@ impl super::BackgroundDocumentRequestHandler for CodeActions { if snapshot.client_settings().fix_all() { if supported_code_actions.contains(&SupportedCodeAction::SourceFixAll) { - response.push(fix_all(&snapshot).with_failure_code(ErrorCode::InternalError)?); + if snapshot.is_notebook_cell() { + // This is ignore here because the client requests this code action for each + // cell in parallel and the server would send a workspace edit with the same + // content which would result in applying the same edit multiple times + // resulting in (possibly) duplicate code. + tracing::debug!("Ignoring `source.fixAll` code action for a notebook cell"); + } else { + response.push(fix_all(&snapshot).with_failure_code(ErrorCode::InternalError)?); + } } else if supported_code_actions.contains(&SupportedCodeAction::NotebookSourceFixAll) { response .push(notebook_fix_all(&snapshot).with_failure_code(ErrorCode::InternalError)?); @@ -57,8 +65,19 @@ impl super::BackgroundDocumentRequestHandler for CodeActions { if snapshot.client_settings().organize_imports() { if supported_code_actions.contains(&SupportedCodeAction::SourceOrganizeImports) { - response - .push(organize_imports(&snapshot).with_failure_code(ErrorCode::InternalError)?); + if snapshot.is_notebook_cell() { + // This is ignore here because the client requests this code action for each + // cell in parallel and the server would send a workspace edit with the same + // content which would result in applying the same edit multiple times + // resulting in (possibly) duplicate code. + tracing::debug!( + "Ignoring `source.organizeImports` code action for a notebook cell" + ); + } else { + response.push( + organize_imports(&snapshot).with_failure_code(ErrorCode::InternalError)?, + ); + } } else if supported_code_actions .contains(&SupportedCodeAction::NotebookSourceOrganizeImports) { diff --git a/crates/ruff_server/src/server/api/requests/code_action_resolve.rs b/crates/ruff_server/src/server/api/requests/code_action_resolve.rs index 0cdd026539..ed7e3c22b4 100644 --- a/crates/ruff_server/src/server/api/requests/code_action_resolve.rs +++ b/crates/ruff_server/src/server/api/requests/code_action_resolve.rs @@ -50,6 +50,21 @@ impl super::BackgroundDocumentRequestHandler for CodeActionResolve { .with_failure_code(ErrorCode::InvalidParams); }; + match action_kind { + SupportedCodeAction::SourceFixAll | SupportedCodeAction::SourceOrganizeImports + if snapshot.is_notebook_cell() => + { + // This should never occur because we ignore generating these code actions for a + // notebook cell in the `textDocument/codeAction` request handler. + return Err(anyhow::anyhow!( + "Code action resolver cannot resolve {:?} for a notebook cell", + action_kind.to_kind().as_str() + )) + .with_failure_code(ErrorCode::InvalidParams); + } + _ => {} + } + action.edit = match action_kind { SupportedCodeAction::SourceFixAll | SupportedCodeAction::NotebookSourceFixAll => Some( resolve_edit_for_fix_all( diff --git a/crates/ruff_server/src/session.rs b/crates/ruff_server/src/session.rs index f26a6ae4b1..743fae4ecf 100644 --- a/crates/ruff_server/src/session.rs +++ b/crates/ruff_server/src/session.rs @@ -184,4 +184,15 @@ impl DocumentSnapshot { pub(crate) fn encoding(&self) -> PositionEncoding { self.position_encoding } + + /// Returns `true` if this snapshot represents a notebook cell. + pub(crate) const fn is_notebook_cell(&self) -> bool { + matches!( + &self.document_ref, + index::DocumentQuery::Notebook { + cell_url: Some(_), + .. + } + ) + } }