Include document specific debug info (#16215)

## Summary

Related https://github.com/astral-sh/ruff-vscode/pull/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`
This commit is contained in:
Dhruv Manilawala 2025-02-18 15:38:30 +05:30 committed by GitHub
parent bb2a712f6a
commit ed9c18d9b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 132 additions and 47 deletions

View file

@ -1,3 +1,4 @@
use std::fmt::Write;
use std::str::FromStr;
use crate::edit::WorkspaceEditTracker;
@ -5,10 +6,10 @@ use crate::server::api::LSPResult;
use crate::server::schedule::Task;
use crate::server::{client, SupportedCommand};
use crate::session::Session;
use crate::DIAGNOSTIC_NAME;
use crate::{edit::DocumentVersion, server};
use crate::{DocumentKey, DIAGNOSTIC_NAME};
use lsp_server::ErrorCode;
use lsp_types::{self as types, request as req};
use lsp_types::{self as types, request as req, TextDocumentIdentifier};
use serde::Deserialize;
pub(crate) struct ExecuteCommand;
@ -19,6 +20,17 @@ struct Argument {
version: DocumentVersion,
}
/// The argument schema for the `ruff.printDebugInformation` command.
#[derive(Default, Deserialize)]
#[serde(rename_all = "camelCase")]
struct DebugCommandArgument {
/// The URI of the document to print debug information for.
///
/// When provided, both document-specific debug information and global information are printed.
/// If not provided ([None]), only global debug information is printed.
text_document: Option<TextDocumentIdentifier>,
}
impl super::RequestHandler for ExecuteCommand {
type RequestType = req::ExecuteCommand;
}
@ -34,7 +46,12 @@ impl super::SyncRequestHandler for ExecuteCommand {
.with_failure_code(ErrorCode::InvalidParams)?;
if command == SupportedCommand::Debug {
let output = debug_information(session);
let argument: DebugCommandArgument = params.arguments.into_iter().next().map_or_else(
|| Ok(DebugCommandArgument::default()),
|value| serde_json::from_value(value).with_failure_code(ErrorCode::InvalidParams),
)?;
let output = debug_information(session, argument.text_document)
.with_failure_code(ErrorCode::InternalError)?;
notifier
.notify::<types::notification::LogMessage>(types::LogMessageParams {
message: output.clone(),
@ -134,23 +151,71 @@ fn apply_edit(
)
}
fn debug_information(session: &Session) -> String {
/// Returns a string with debug information about the session and the document at the given URI.
fn debug_information(
session: &Session,
text_document: Option<TextDocumentIdentifier>,
) -> crate::Result<String> {
let executable = std::env::current_exe()
.map(|path| format!("{}", path.display()))
.unwrap_or_else(|_| "<unavailable>".to_string());
format!(
"executable = {executable}
let mut buffer = String::new();
writeln!(
buffer,
"Global:
executable = {executable}
version = {version}
encoding = {encoding:?}
open_document_count = {doc_count}
active_workspace_count = {workspace_count}
configuration_files = {config_files:?}
{client_capabilities}",
position_encoding = {encoding:?}
workspace_root_folders = {workspace_folders:#?}
indexed_configuration_files = {config_files:#?}
open_documents_len = {open_documents_len}
client_capabilities = {client_capabilities:#?}
",
version = crate::version(),
encoding = session.encoding(),
workspace_folders = session.workspace_root_folders().collect::<Vec<_>>(),
config_files = session.config_file_paths().collect::<Vec<_>>(),
open_documents_len = session.open_documents_len(),
client_capabilities = session.resolved_client_capabilities(),
doc_count = session.num_documents(),
workspace_count = session.num_workspaces(),
config_files = session.list_config_files()
)
)?;
if let Some(TextDocumentIdentifier { uri }) = text_document {
let Some(snapshot) = session.take_snapshot(uri.clone()) else {
writeln!(buffer, "Unable to take a snapshot of the document at {uri}")?;
return Ok(buffer);
};
let query = snapshot.query();
writeln!(
buffer,
"Open document:
uri = {uri}
kind = {kind}
version = {version}
client_settings = {client_settings:#?}
config_path = {config_path:?}
{settings}
",
uri = uri.clone(),
kind = match session.key_from_url(uri) {
DocumentKey::Notebook(_) => "Notebook",
DocumentKey::NotebookCell(_) => "NotebookCell",
DocumentKey::Text(_) => "Text",
},
version = query.version(),
client_settings = snapshot.client_settings(),
config_path = query.settings().path(),
settings = query.settings(),
)?;
} else {
writeln!(
buffer,
"global_client_settings = {:#?}",
session.global_client_settings()
)?;
}
Ok(buffer)
}