Skip to content

Commit

Permalink
ruff server: Introduce the ruff.printDebugInformation command (#1…
Browse files Browse the repository at this point in the history
…1831)

## Summary

Closes #11715.

Introduces a new command, `ruff.printDebugInformation`. This will print
useful information about the status of the server to `stderr`.

Right now, the information shown by this command includes:
* The path to the server executable
* The version of the executable
* The text encoding being used
* The number of open documents and workspaces
* A list of registered configuration files
* The capabilities of the client

## Test Plan

First, checkout and use [the corresponding `ruff-vscode`
PR](astral-sh/ruff-vscode#495).

Running the `Print debug information` command in VS Code should show
something like the following in the Output channel:

<img width="991" alt="Screenshot 2024-06-11 at 11 41 46 AM"
src="https://github.com/astral-sh/ruff/assets/19577865/ab93c009-bb7b-4291-b057-d44fdc6f9f86">
  • Loading branch information
snowsignal authored Jun 11, 2024
1 parent 507f5c1 commit 4e9d771
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 4 deletions.
43 changes: 41 additions & 2 deletions crates/ruff_server/src/server/api/requests/execute_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use lsp_server::ErrorCode;
use lsp_types::{self as types, request as req};
use serde::Deserialize;

#[derive(Debug)]
#[derive(Debug, PartialEq)]
enum Command {
Debug,
Format,
FixAll,
OrganizeImports,
Expand All @@ -33,13 +34,24 @@ impl super::RequestHandler for ExecuteCommand {
impl super::SyncRequestHandler for ExecuteCommand {
fn run(
session: &mut Session,
_notifier: client::Notifier,
notifier: client::Notifier,
requester: &mut client::Requester,
params: types::ExecuteCommandParams,
) -> server::Result<Option<serde_json::Value>> {
let command =
Command::from_str(&params.command).with_failure_code(ErrorCode::InvalidParams)?;

if command == Command::Debug {
let output = debug_information(session);
notifier
.notify::<types::notification::LogMessage>(types::LogMessageParams {
message: output,
typ: types::MessageType::INFO,
})
.with_failure_code(ErrorCode::InternalError)?;
return Ok(None);
}

// check if we can apply a workspace edit
if !session.resolved_client_capabilities().apply_edit {
return Err(anyhow::anyhow!("Cannot execute the '{}' command: the client does not support `workspace/applyEdit`", command.label())).with_failure_code(ErrorCode::InternalError);
Expand Down Expand Up @@ -87,6 +99,9 @@ impl super::SyncRequestHandler for ExecuteCommand {
.set_fixes_for_document(fixes, snapshot.query().version())
.with_failure_code(ErrorCode::InternalError)?;
}
Command::Debug => {
unreachable!("The debug command should have already been handled")
}
}
}

Expand All @@ -109,6 +124,7 @@ impl Command {
Self::FixAll => "Fix all auto-fixable problems",
Self::Format => "Format document",
Self::OrganizeImports => "Format imports",
Self::Debug => "Print debug information",
}
}
}
Expand All @@ -121,6 +137,7 @@ impl FromStr for Command {
"ruff.applyAutofix" => Self::FixAll,
"ruff.applyFormat" => Self::Format,
"ruff.applyOrganizeImports" => Self::OrganizeImports,
"ruff.printDebugInformation" => Self::Debug,
_ => return Err(anyhow::anyhow!("Invalid command `{name}`")),
})
}
Expand Down Expand Up @@ -148,3 +165,25 @@ fn apply_edit(
},
)
}

fn debug_information(session: &Session) -> String {
let executable = std::env::current_exe()
.map(|path| format!("{}", path.display()))
.unwrap_or_else(|_| "<unavailable>".to_string());
format!(
r#"executable = {executable}
version = {version}
encoding = {encoding:?}
open_document_count = {doc_count}
active_workspace_count = {workspace_count}
configuration_files = {config_files:?}
{client_capabilities}
"#,
version = crate::version(),
encoding = session.encoding(),
client_capabilities = session.resolved_client_capabilities(),
doc_count = session.num_documents(),
workspace_count = session.num_workspaces(),
config_files = session.list_config_files()
)
}
12 changes: 12 additions & 0 deletions crates/ruff_server/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,18 @@ impl Session {
Ok(())
}

pub(crate) fn num_documents(&self) -> usize {
self.index.num_documents()
}

pub(crate) fn num_workspaces(&self) -> usize {
self.index.num_workspaces()
}

pub(crate) fn list_config_files(&self) -> Vec<&std::path::Path> {
self.index.list_config_files()
}

pub(crate) fn resolved_client_capabilities(&self) -> &ResolvedClientCapabilities {
&self.resolved_client_capabilities
}
Expand Down
18 changes: 18 additions & 0 deletions crates/ruff_server/src/session/capabilities.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use lsp_types::ClientCapabilities;
use ruff_linter::display_settings;

#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[allow(clippy::struct_excessive_bools)]
Expand Down Expand Up @@ -65,3 +66,20 @@ impl ResolvedClientCapabilities {
}
}
}

impl std::fmt::Display for ResolvedClientCapabilities {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
display_settings! {
formatter = f,
namespace = "capabilities",
fields = [
self.code_action_deferred_edit_resolution,
self.apply_edit,
self.document_changes,
self.workspace_refresh,
self.pull_diagnostics,
]
};
Ok(())
}
}
15 changes: 15 additions & 0 deletions crates/ruff_server/src/session/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,21 @@ impl Index {
Self::register_workspace_settings(&mut self.settings, url, None, global_settings)
}

pub(super) fn num_documents(&self) -> usize {
self.documents.len()
}

pub(super) fn num_workspaces(&self) -> usize {
self.settings.len()
}

pub(super) fn list_config_files(&self) -> Vec<&Path> {
self.settings
.values()
.flat_map(|WorkspaceSettings { ruff_settings, .. }| ruff_settings.list_files())
.collect()
}

fn register_workspace_settings(
settings_index: &mut SettingsIndex,
workspace_url: &Url,
Expand Down
19 changes: 17 additions & 2 deletions crates/ruff_server/src/session/index/ruff_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ use walkdir::WalkDir;
use crate::session::settings::{ConfigurationPreference, ResolvedEditorSettings};

pub(crate) struct RuffSettings {
/// The path to this configuration file, used for debugging.
/// The default fallback configuration does not have a file path.
path: Option<PathBuf>,
/// Settings used to manage file inclusion and exclusion.
file_resolver: ruff_workspace::FileResolverSettings,
/// Settings to pass into the Ruff linter.
Expand Down Expand Up @@ -48,14 +51,17 @@ impl std::fmt::Display for RuffSettings {

impl RuffSettings {
pub(crate) fn fallback(editor_settings: &ResolvedEditorSettings, root: &Path) -> RuffSettings {
let mut path = None;
let fallback = find_user_settings_toml()
.and_then(|user_settings| {
ruff_workspace::resolver::resolve_root_settings(
let settings = ruff_workspace::resolver::resolve_root_settings(
&user_settings,
Relativity::Cwd,
&EditorConfigurationTransformer(editor_settings, root),
)
.ok()
.ok();
path = Some(user_settings);
settings
})
.unwrap_or_else(|| {
let default_configuration = Configuration::default();
Expand All @@ -68,6 +74,7 @@ impl RuffSettings {
});

RuffSettings {
path,
file_resolver: fallback.file_resolver,
formatter: fallback.formatter,
linter: fallback.linter,
Expand Down Expand Up @@ -108,6 +115,7 @@ impl RuffSettingsIndex {
index.insert(
directory.to_path_buf(),
Arc::new(RuffSettings {
path: Some(pyproject),
file_resolver: settings.file_resolver,
linter: settings.linter,
formatter: settings.formatter,
Expand Down Expand Up @@ -176,6 +184,7 @@ impl RuffSettingsIndex {
index.insert(
directory,
Arc::new(RuffSettings {
path: Some(pyproject),
file_resolver: settings.file_resolver,
linter: settings.linter,
formatter: settings.formatter,
Expand All @@ -198,6 +207,12 @@ impl RuffSettingsIndex {
.clone()
}

pub(crate) fn list_files(&self) -> impl Iterator<Item = &Path> {
self.index
.values()
.filter_map(|settings| settings.path.as_deref())
}

pub(super) fn fallback(&self) -> Arc<RuffSettings> {
self.fallback.clone()
}
Expand Down

0 comments on commit 4e9d771

Please sign in to comment.