Skip to content

Commit ed9c18d

Browse files
authored
Include document specific debug info (#16215)
## Summary Related astral-sh/ruff-vscode#692. ## Test Plan **When there's no active text document:** ``` [Info - 10:57:03 PM] Global: executable = /Users/dhruv/work/astral/ruff/target/debug/ruff version = 0.9.6 position_encoding = UTF16 workspace_root_folders = [ "/Users/dhruv/playground/ruff", ] indexed_configuration_files = [ "/Users/dhruv/playground/ruff/pyproject.toml", "/Users/dhruv/playground/ruff/formatter/ruff.toml", ] open_documents = 0 client_capabilities = ResolvedClientCapabilities { code_action_deferred_edit_resolution: true, apply_edit: true, document_changes: true, workspace_refresh: true, pull_diagnostics: true, } global_client_settings = ResolvedClientSettings { fix_all: true, organize_imports: true, lint_enable: true, disable_rule_comment_enable: true, fix_violation_enable: true, show_syntax_errors: true, editor_settings: ResolvedEditorSettings { configuration: None, lint_preview: None, format_preview: None, select: None, extend_select: None, ignore: None, exclude: None, line_length: None, configuration_preference: EditorFirst, }, } ``` **When there's an active text document that's been passed as param:** ``` [Info - 10:53:33 PM] Global: executable = /Users/dhruv/work/astral/ruff/target/debug/ruff version = 0.9.6 position_encoding = UTF16 workspace_root_folders = [ "/Users/dhruv/playground/ruff", ] indexed_configuration_files = [ "/Users/dhruv/playground/ruff/pyproject.toml", "/Users/dhruv/playground/ruff/formatter/ruff.toml", ] open_documents = 1 client_capabilities = ResolvedClientCapabilities { code_action_deferred_edit_resolution: true, apply_edit: true, document_changes: true, workspace_refresh: true, pull_diagnostics: true, } Document: uri = file:///Users/dhruv/playground/ruff/lsp/play.py kind = Text version = 1 client_settings = ResolvedClientSettings { fix_all: true, organize_imports: true, lint_enable: true, disable_rule_comment_enable: true, fix_violation_enable: true, show_syntax_errors: true, editor_settings: ResolvedEditorSettings { configuration: None, lint_preview: None, format_preview: None, select: None, extend_select: None, ignore: None, exclude: None, line_length: None, configuration_preference: EditorFirst, }, } config_path = Some("/Users/dhruv/playground/ruff/pyproject.toml") ... ``` Replace `...` at the end with the output of `ruff check --show-settings path.py`
1 parent bb2a712 commit ed9c18d

File tree

4 files changed

+130
-45
lines changed

4 files changed

+130
-45
lines changed

crates/ruff_server/src/server/api/requests/execute_command.rs

+80-15
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1+
use std::fmt::Write;
12
use std::str::FromStr;
23

34
use crate::edit::WorkspaceEditTracker;
45
use crate::server::api::LSPResult;
56
use crate::server::schedule::Task;
67
use crate::server::{client, SupportedCommand};
78
use crate::session::Session;
8-
use crate::DIAGNOSTIC_NAME;
99
use crate::{edit::DocumentVersion, server};
10+
use crate::{DocumentKey, DIAGNOSTIC_NAME};
1011
use lsp_server::ErrorCode;
11-
use lsp_types::{self as types, request as req};
12+
use lsp_types::{self as types, request as req, TextDocumentIdentifier};
1213
use serde::Deserialize;
1314

1415
pub(crate) struct ExecuteCommand;
@@ -19,6 +20,17 @@ struct Argument {
1920
version: DocumentVersion,
2021
}
2122

23+
/// The argument schema for the `ruff.printDebugInformation` command.
24+
#[derive(Default, Deserialize)]
25+
#[serde(rename_all = "camelCase")]
26+
struct DebugCommandArgument {
27+
/// The URI of the document to print debug information for.
28+
///
29+
/// When provided, both document-specific debug information and global information are printed.
30+
/// If not provided ([None]), only global debug information is printed.
31+
text_document: Option<TextDocumentIdentifier>,
32+
}
33+
2234
impl super::RequestHandler for ExecuteCommand {
2335
type RequestType = req::ExecuteCommand;
2436
}
@@ -34,7 +46,12 @@ impl super::SyncRequestHandler for ExecuteCommand {
3446
.with_failure_code(ErrorCode::InvalidParams)?;
3547

3648
if command == SupportedCommand::Debug {
37-
let output = debug_information(session);
49+
let argument: DebugCommandArgument = params.arguments.into_iter().next().map_or_else(
50+
|| Ok(DebugCommandArgument::default()),
51+
|value| serde_json::from_value(value).with_failure_code(ErrorCode::InvalidParams),
52+
)?;
53+
let output = debug_information(session, argument.text_document)
54+
.with_failure_code(ErrorCode::InternalError)?;
3855
notifier
3956
.notify::<types::notification::LogMessage>(types::LogMessageParams {
4057
message: output.clone(),
@@ -134,23 +151,71 @@ fn apply_edit(
134151
)
135152
}
136153

137-
fn debug_information(session: &Session) -> String {
154+
/// Returns a string with debug information about the session and the document at the given URI.
155+
fn debug_information(
156+
session: &Session,
157+
text_document: Option<TextDocumentIdentifier>,
158+
) -> crate::Result<String> {
138159
let executable = std::env::current_exe()
139160
.map(|path| format!("{}", path.display()))
140161
.unwrap_or_else(|_| "<unavailable>".to_string());
141-
format!(
142-
"executable = {executable}
162+
163+
let mut buffer = String::new();
164+
165+
writeln!(
166+
buffer,
167+
"Global:
168+
executable = {executable}
143169
version = {version}
144-
encoding = {encoding:?}
145-
open_document_count = {doc_count}
146-
active_workspace_count = {workspace_count}
147-
configuration_files = {config_files:?}
148-
{client_capabilities}",
170+
position_encoding = {encoding:?}
171+
workspace_root_folders = {workspace_folders:#?}
172+
indexed_configuration_files = {config_files:#?}
173+
open_documents_len = {open_documents_len}
174+
client_capabilities = {client_capabilities:#?}
175+
",
149176
version = crate::version(),
150177
encoding = session.encoding(),
178+
workspace_folders = session.workspace_root_folders().collect::<Vec<_>>(),
179+
config_files = session.config_file_paths().collect::<Vec<_>>(),
180+
open_documents_len = session.open_documents_len(),
151181
client_capabilities = session.resolved_client_capabilities(),
152-
doc_count = session.num_documents(),
153-
workspace_count = session.num_workspaces(),
154-
config_files = session.list_config_files()
155-
)
182+
)?;
183+
184+
if let Some(TextDocumentIdentifier { uri }) = text_document {
185+
let Some(snapshot) = session.take_snapshot(uri.clone()) else {
186+
writeln!(buffer, "Unable to take a snapshot of the document at {uri}")?;
187+
return Ok(buffer);
188+
};
189+
let query = snapshot.query();
190+
191+
writeln!(
192+
buffer,
193+
"Open document:
194+
uri = {uri}
195+
kind = {kind}
196+
version = {version}
197+
client_settings = {client_settings:#?}
198+
config_path = {config_path:?}
199+
{settings}
200+
",
201+
uri = uri.clone(),
202+
kind = match session.key_from_url(uri) {
203+
DocumentKey::Notebook(_) => "Notebook",
204+
DocumentKey::NotebookCell(_) => "NotebookCell",
205+
DocumentKey::Text(_) => "Text",
206+
},
207+
version = query.version(),
208+
client_settings = snapshot.client_settings(),
209+
config_path = query.settings().path(),
210+
settings = query.settings(),
211+
)?;
212+
} else {
213+
writeln!(
214+
buffer,
215+
"global_client_settings = {:#?}",
216+
session.global_client_settings()
217+
)?;
218+
}
219+
220+
Ok(buffer)
156221
}

crates/ruff_server/src/session.rs

+20-10
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//! Data model, state management, and configuration resolution.
22
3+
use std::path::Path;
34
use std::sync::Arc;
45

56
use lsp_types::{ClientCapabilities, FileEvent, NotebookDocumentCellChange, Url};
7+
use settings::ResolvedClientSettings;
68

79
use crate::edit::{DocumentKey, DocumentVersion, NotebookDocument};
810
use crate::server::Workspaces;
@@ -147,24 +149,32 @@ impl Session {
147149
Ok(())
148150
}
149151

150-
pub(crate) fn num_documents(&self) -> usize {
151-
self.index.num_documents()
152+
pub(crate) fn resolved_client_capabilities(&self) -> &ResolvedClientCapabilities {
153+
&self.resolved_client_capabilities
152154
}
153155

154-
pub(crate) fn num_workspaces(&self) -> usize {
155-
self.index.num_workspaces()
156+
pub(crate) fn encoding(&self) -> PositionEncoding {
157+
self.position_encoding
156158
}
157159

158-
pub(crate) fn list_config_files(&self) -> Vec<&std::path::Path> {
159-
self.index.list_config_files()
160+
/// Returns an iterator over the paths to the configuration files in the index.
161+
pub(crate) fn config_file_paths(&self) -> impl Iterator<Item = &Path> {
162+
self.index.config_file_paths()
160163
}
161164

162-
pub(crate) fn resolved_client_capabilities(&self) -> &ResolvedClientCapabilities {
163-
&self.resolved_client_capabilities
165+
/// Returns the resolved global client settings.
166+
pub(crate) fn global_client_settings(&self) -> ResolvedClientSettings {
167+
ResolvedClientSettings::global(&self.global_settings)
164168
}
165169

166-
pub(crate) fn encoding(&self) -> PositionEncoding {
167-
self.position_encoding
170+
/// Returns the number of open documents in the session.
171+
pub(crate) fn open_documents_len(&self) -> usize {
172+
self.index.open_documents_len()
173+
}
174+
175+
/// Returns an iterator over the workspace root folders in the session.
176+
pub(crate) fn workspace_root_folders(&self) -> impl Iterator<Item = &Path> {
177+
self.index.workspace_root_folders()
168178
}
169179
}
170180

crates/ruff_server/src/session/index.rs

+17-15
Original file line numberDiff line numberDiff line change
@@ -177,21 +177,6 @@ impl Index {
177177
.register_workspace(&Workspace::new(url), global_settings)
178178
}
179179

180-
pub(super) fn num_documents(&self) -> usize {
181-
self.documents.len()
182-
}
183-
184-
pub(super) fn num_workspaces(&self) -> usize {
185-
self.settings.len()
186-
}
187-
188-
pub(super) fn list_config_files(&self) -> Vec<&Path> {
189-
self.settings
190-
.values()
191-
.flat_map(|WorkspaceSettings { ruff_settings, .. }| ruff_settings.list_files())
192-
.collect()
193-
}
194-
195180
pub(super) fn close_workspace_folder(&mut self, workspace_url: &Url) -> crate::Result<()> {
196181
let workspace_path = workspace_url.to_file_path().map_err(|()| {
197182
anyhow!("Failed to convert workspace URL to file path: {workspace_url}")
@@ -404,6 +389,23 @@ impl Index {
404389
.next_back()
405390
.map(|(_, settings)| settings)
406391
}
392+
393+
/// Returns an iterator over the workspace root folders contained in this index.
394+
pub(super) fn workspace_root_folders(&self) -> impl Iterator<Item = &Path> {
395+
self.settings.keys().map(PathBuf::as_path)
396+
}
397+
398+
/// Returns the number of open documents.
399+
pub(super) fn open_documents_len(&self) -> usize {
400+
self.documents.len()
401+
}
402+
403+
/// Returns an iterator over the paths to the configuration files in the index.
404+
pub(super) fn config_file_paths(&self) -> impl Iterator<Item = &Path> {
405+
self.settings
406+
.values()
407+
.flat_map(|WorkspaceSettings { ruff_settings, .. }| ruff_settings.config_file_paths())
408+
}
407409
}
408410

409411
/// Maps a workspace folder root to its settings.

crates/ruff_server/src/session/index/ruff_settings.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use ruff_workspace::{
2020

2121
use crate::session::settings::{ConfigurationPreference, ResolvedEditorSettings};
2222

23+
#[derive(Debug)]
2324
pub struct RuffSettings {
2425
/// The path to this configuration file, used for debugging.
2526
/// The default fallback configuration does not have a file path.
@@ -28,6 +29,12 @@ pub struct RuffSettings {
2829
settings: Settings,
2930
}
3031

32+
impl RuffSettings {
33+
pub(crate) fn path(&self) -> Option<&Path> {
34+
self.path.as_deref()
35+
}
36+
}
37+
3138
impl Deref for RuffSettings {
3239
type Target = Settings;
3340

@@ -298,15 +305,16 @@ impl RuffSettingsIndex {
298305
.clone()
299306
}
300307

301-
pub(crate) fn list_files(&self) -> impl Iterator<Item = &Path> {
308+
pub(super) fn fallback(&self) -> Arc<RuffSettings> {
309+
self.fallback.clone()
310+
}
311+
312+
/// Returns an iterator over the paths to the configuration files in the index.
313+
pub(crate) fn config_file_paths(&self) -> impl Iterator<Item = &Path> {
302314
self.index
303315
.values()
304316
.filter_map(|settings| settings.path.as_deref())
305317
}
306-
307-
pub(super) fn fallback(&self) -> Arc<RuffSettings> {
308-
self.fallback.clone()
309-
}
310318
}
311319

312320
struct EditorConfigurationTransformer<'a>(&'a ResolvedEditorSettings, &'a Path);

0 commit comments

Comments
 (0)