ruff server refreshes diagnostics for open files when file configuration is changed (#10988)

## Summary

The server now requests a [workspace diagnostic
refresh](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh)
when a configuration file gets changed. This means that diagnostics for
all open files will be automatically re-requested by the client on a
config change.

## Test Plan

You can test this by opening several files in VS Code, setting `select`
in your file configuration to `[]`, and observing that the diagnostics
go away once the file is saved (besides any `Pylance` diagnostics).
Restore it to what it was before, and you should see the diagnostics
automatically return once a save happens.
This commit is contained in:
Jane Lewis 2024-04-17 09:14:45 -07:00 committed by GitHub
parent 518b29a9ef
commit 0a6327418d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 42 additions and 10 deletions

View file

@ -123,8 +123,8 @@ fn local_notification_task<'a, N: traits::SyncNotificationHandler>(
notif: server::Notification, notif: server::Notification,
) -> super::Result<Task<'a>> { ) -> super::Result<Task<'a>> {
let (id, params) = cast_notification::<N>(notif)?; let (id, params) = cast_notification::<N>(notif)?;
Ok(Task::local(move |session, notifier, _, _| { Ok(Task::local(move |session, notifier, requester, _| {
if let Err(err) = N::run(session, notifier, params) { if let Err(err) = N::run(session, notifier, requester, params) {
tracing::error!("An error occurred while running {id}: {err}"); tracing::error!("An error occurred while running {id}: {err}");
show_err_msg!("Ruff encountered a problem. Check the logs for more details."); show_err_msg!("Ruff encountered a problem. Check the logs for more details.");
} }

View file

@ -1,4 +1,4 @@
use crate::server::client::Notifier; use crate::server::client::{Notifier, Requester};
use crate::server::Result; use crate::server::Result;
use crate::session::Session; use crate::session::Session;
use lsp_types as types; use lsp_types as types;
@ -15,6 +15,7 @@ impl super::SyncNotificationHandler for Cancel {
fn run( fn run(
_session: &mut Session, _session: &mut Session,
_notifier: Notifier, _notifier: Notifier,
_requester: &mut Requester,
_params: types::CancelParams, _params: types::CancelParams,
) -> Result<()> { ) -> Result<()> {
// TODO(jane): Handle this once we have task cancellation in the scheduler. // TODO(jane): Handle this once we have task cancellation in the scheduler.

View file

@ -1,5 +1,5 @@
use crate::server::api::LSPResult; use crate::server::api::LSPResult;
use crate::server::client::Notifier; use crate::server::client::{Notifier, Requester};
use crate::server::Result; use crate::server::Result;
use crate::session::Session; use crate::session::Session;
use lsp_types as types; use lsp_types as types;
@ -16,6 +16,7 @@ impl super::SyncNotificationHandler for DidChange {
fn run( fn run(
session: &mut Session, session: &mut Session,
_notifier: Notifier, _notifier: Notifier,
_requester: &mut Requester,
types::DidChangeTextDocumentParams { types::DidChangeTextDocumentParams {
text_document: text_document:
types::VersionedTextDocumentIdentifier { types::VersionedTextDocumentIdentifier {

View file

@ -1,4 +1,4 @@
use crate::server::client::Notifier; use crate::server::client::{Notifier, Requester};
use crate::server::Result; use crate::server::Result;
use crate::session::Session; use crate::session::Session;
use lsp_types as types; use lsp_types as types;
@ -14,6 +14,7 @@ impl super::SyncNotificationHandler for DidChangeConfiguration {
fn run( fn run(
_session: &mut Session, _session: &mut Session,
_notifier: Notifier, _notifier: Notifier,
_requester: &mut Requester,
_params: types::DidChangeConfigurationParams, _params: types::DidChangeConfigurationParams,
) -> Result<()> { ) -> Result<()> {
// TODO(jane): get this wired up after the pre-release // TODO(jane): get this wired up after the pre-release

View file

@ -1,5 +1,6 @@
use crate::server::api::LSPResult; use crate::server::api::LSPResult;
use crate::server::client::Notifier; use crate::server::client::{Notifier, Requester};
use crate::server::schedule::Task;
use crate::server::Result; use crate::server::Result;
use crate::session::Session; use crate::session::Session;
use lsp_types as types; use lsp_types as types;
@ -15,13 +16,21 @@ impl super::SyncNotificationHandler for DidChangeWatchedFiles {
fn run( fn run(
session: &mut Session, session: &mut Session,
_notifier: Notifier, _notifier: Notifier,
requester: &mut Requester,
params: types::DidChangeWatchedFilesParams, params: types::DidChangeWatchedFilesParams,
) -> Result<()> { ) -> Result<()> {
for change in params.changes { for change in &params.changes {
session session
.reload_settings(&change.uri) .reload_settings(&change.uri)
.with_failure_code(lsp_server::ErrorCode::InternalError)?; .with_failure_code(lsp_server::ErrorCode::InternalError)?;
} }
if session.resolved_client_capabilities().workspace_refresh && !params.changes.is_empty() {
requester
.request::<types::request::WorkspaceDiagnosticRefresh>((), |()| Task::nothing())
.with_failure_code(lsp_server::ErrorCode::InternalError)?;
}
Ok(()) Ok(())
} }
} }

View file

@ -1,5 +1,5 @@
use crate::server::api::LSPResult; use crate::server::api::LSPResult;
use crate::server::client::Notifier; use crate::server::client::{Notifier, Requester};
use crate::server::Result; use crate::server::Result;
use crate::session::Session; use crate::session::Session;
use lsp_types as types; use lsp_types as types;
@ -15,6 +15,7 @@ impl super::SyncNotificationHandler for DidChangeWorkspace {
fn run( fn run(
session: &mut Session, session: &mut Session,
_notifier: Notifier, _notifier: Notifier,
_requester: &mut Requester,
params: types::DidChangeWorkspaceFoldersParams, params: types::DidChangeWorkspaceFoldersParams,
) -> Result<()> { ) -> Result<()> {
for new in params.event.added { for new in params.event.added {

View file

@ -1,5 +1,5 @@
use crate::server::api::LSPResult; use crate::server::api::LSPResult;
use crate::server::client::Notifier; use crate::server::client::{Notifier, Requester};
use crate::server::Result; use crate::server::Result;
use crate::session::Session; use crate::session::Session;
use lsp_types as types; use lsp_types as types;
@ -16,6 +16,7 @@ impl super::SyncNotificationHandler for DidClose {
fn run( fn run(
session: &mut Session, session: &mut Session,
_notifier: Notifier, _notifier: Notifier,
_requester: &mut Requester,
types::DidCloseTextDocumentParams { types::DidCloseTextDocumentParams {
text_document: types::TextDocumentIdentifier { uri }, text_document: types::TextDocumentIdentifier { uri },
}: types::DidCloseTextDocumentParams, }: types::DidCloseTextDocumentParams,

View file

@ -1,4 +1,4 @@
use crate::server::client::Notifier; use crate::server::client::{Notifier, Requester};
use crate::server::Result; use crate::server::Result;
use crate::session::Session; use crate::session::Session;
use lsp_types as types; use lsp_types as types;
@ -15,6 +15,7 @@ impl super::SyncNotificationHandler for DidOpen {
fn run( fn run(
session: &mut Session, session: &mut Session,
_notifier: Notifier, _notifier: Notifier,
_requester: &mut Requester,
types::DidOpenTextDocumentParams { types::DidOpenTextDocumentParams {
text_document: text_document:
types::TextDocumentItem { types::TextDocumentItem {

View file

@ -56,6 +56,7 @@ pub(super) trait SyncNotificationHandler: NotificationHandler {
fn run( fn run(
session: &mut Session, session: &mut Session,
notifier: Notifier, notifier: Notifier,
requester: &mut Requester,
params: <<Self as NotificationHandler>::NotificationType as LSPNotification>::Params, params: <<Self as NotificationHandler>::NotificationType as LSPNotification>::Params,
) -> super::Result<()>; ) -> super::Result<()>;
} }

View file

@ -1,10 +1,12 @@
use lsp_types::ClientCapabilities; use lsp_types::ClientCapabilities;
#[derive(Debug, Clone, PartialEq, Eq, Default)] #[derive(Debug, Clone, PartialEq, Eq, Default)]
#[allow(clippy::struct_excessive_bools)]
pub(crate) struct ResolvedClientCapabilities { pub(crate) struct ResolvedClientCapabilities {
pub(crate) code_action_deferred_edit_resolution: bool, pub(crate) code_action_deferred_edit_resolution: bool,
pub(crate) apply_edit: bool, pub(crate) apply_edit: bool,
pub(crate) document_changes: bool, pub(crate) document_changes: bool,
pub(crate) workspace_refresh: bool,
} }
impl ResolvedClientCapabilities { impl ResolvedClientCapabilities {
@ -33,11 +35,25 @@ impl ResolvedClientCapabilities {
.and_then(|workspace_edit| workspace_edit.document_changes) .and_then(|workspace_edit| workspace_edit.document_changes)
.unwrap_or_default(); .unwrap_or_default();
let workspace_refresh = true;
// TODO(jane): Once the bug involving workspace.diagnostic(s) deserialization has been fixed,
// uncomment this.
/*
let workspace_refresh = client_capabilities
.workspace
.as_ref()
.and_then(|workspace| workspace.diagnostic.as_ref())
.and_then(|diagnostic| diagnostic.refresh_support)
.unwrap_or_default();
*/
Self { Self {
code_action_deferred_edit_resolution: code_action_data_support code_action_deferred_edit_resolution: code_action_data_support
&& code_action_edit_resolution, && code_action_edit_resolution,
apply_edit, apply_edit,
document_changes, document_changes,
workspace_refresh,
} }
} }
} }