mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-26 20:10:09 +00:00
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:
parent
bb2a712f6a
commit
ed9c18d9b4
4 changed files with 132 additions and 47 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
use std::fmt::Write;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::edit::WorkspaceEditTracker;
|
use crate::edit::WorkspaceEditTracker;
|
||||||
|
@ -5,10 +6,10 @@ use crate::server::api::LSPResult;
|
||||||
use crate::server::schedule::Task;
|
use crate::server::schedule::Task;
|
||||||
use crate::server::{client, SupportedCommand};
|
use crate::server::{client, SupportedCommand};
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
use crate::DIAGNOSTIC_NAME;
|
|
||||||
use crate::{edit::DocumentVersion, server};
|
use crate::{edit::DocumentVersion, server};
|
||||||
|
use crate::{DocumentKey, DIAGNOSTIC_NAME};
|
||||||
use lsp_server::ErrorCode;
|
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;
|
use serde::Deserialize;
|
||||||
|
|
||||||
pub(crate) struct ExecuteCommand;
|
pub(crate) struct ExecuteCommand;
|
||||||
|
@ -19,6 +20,17 @@ struct Argument {
|
||||||
version: DocumentVersion,
|
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 {
|
impl super::RequestHandler for ExecuteCommand {
|
||||||
type RequestType = req::ExecuteCommand;
|
type RequestType = req::ExecuteCommand;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +46,12 @@ impl super::SyncRequestHandler for ExecuteCommand {
|
||||||
.with_failure_code(ErrorCode::InvalidParams)?;
|
.with_failure_code(ErrorCode::InvalidParams)?;
|
||||||
|
|
||||||
if command == SupportedCommand::Debug {
|
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
|
notifier
|
||||||
.notify::<types::notification::LogMessage>(types::LogMessageParams {
|
.notify::<types::notification::LogMessage>(types::LogMessageParams {
|
||||||
message: output.clone(),
|
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()
|
let executable = std::env::current_exe()
|
||||||
.map(|path| format!("{}", path.display()))
|
.map(|path| format!("{}", path.display()))
|
||||||
.unwrap_or_else(|_| "<unavailable>".to_string());
|
.unwrap_or_else(|_| "<unavailable>".to_string());
|
||||||
format!(
|
|
||||||
"executable = {executable}
|
let mut buffer = String::new();
|
||||||
|
|
||||||
|
writeln!(
|
||||||
|
buffer,
|
||||||
|
"Global:
|
||||||
|
executable = {executable}
|
||||||
version = {version}
|
version = {version}
|
||||||
encoding = {encoding:?}
|
position_encoding = {encoding:?}
|
||||||
open_document_count = {doc_count}
|
workspace_root_folders = {workspace_folders:#?}
|
||||||
active_workspace_count = {workspace_count}
|
indexed_configuration_files = {config_files:#?}
|
||||||
configuration_files = {config_files:?}
|
open_documents_len = {open_documents_len}
|
||||||
{client_capabilities}",
|
client_capabilities = {client_capabilities:#?}
|
||||||
|
",
|
||||||
version = crate::version(),
|
version = crate::version(),
|
||||||
encoding = session.encoding(),
|
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(),
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
//! Data model, state management, and configuration resolution.
|
//! Data model, state management, and configuration resolution.
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use lsp_types::{ClientCapabilities, FileEvent, NotebookDocumentCellChange, Url};
|
use lsp_types::{ClientCapabilities, FileEvent, NotebookDocumentCellChange, Url};
|
||||||
|
use settings::ResolvedClientSettings;
|
||||||
|
|
||||||
use crate::edit::{DocumentKey, DocumentVersion, NotebookDocument};
|
use crate::edit::{DocumentKey, DocumentVersion, NotebookDocument};
|
||||||
use crate::server::Workspaces;
|
use crate::server::Workspaces;
|
||||||
|
@ -147,18 +149,6 @@ impl Session {
|
||||||
Ok(())
|
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 {
|
pub(crate) fn resolved_client_capabilities(&self) -> &ResolvedClientCapabilities {
|
||||||
&self.resolved_client_capabilities
|
&self.resolved_client_capabilities
|
||||||
}
|
}
|
||||||
|
@ -166,6 +156,26 @@ impl Session {
|
||||||
pub(crate) fn encoding(&self) -> PositionEncoding {
|
pub(crate) fn encoding(&self) -> PositionEncoding {
|
||||||
self.position_encoding
|
self.position_encoding
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the paths to the configuration files in the index.
|
||||||
|
pub(crate) fn config_file_paths(&self) -> impl Iterator<Item = &Path> {
|
||||||
|
self.index.config_file_paths()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the resolved global client settings.
|
||||||
|
pub(crate) fn global_client_settings(&self) -> ResolvedClientSettings {
|
||||||
|
ResolvedClientSettings::global(&self.global_settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of open documents in the session.
|
||||||
|
pub(crate) fn open_documents_len(&self) -> usize {
|
||||||
|
self.index.open_documents_len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the workspace root folders in the session.
|
||||||
|
pub(crate) fn workspace_root_folders(&self) -> impl Iterator<Item = &Path> {
|
||||||
|
self.index.workspace_root_folders()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentSnapshot {
|
impl DocumentSnapshot {
|
||||||
|
|
|
@ -177,21 +177,6 @@ impl Index {
|
||||||
.register_workspace(&Workspace::new(url), global_settings)
|
.register_workspace(&Workspace::new(url), 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn close_workspace_folder(&mut self, workspace_url: &Url) -> crate::Result<()> {
|
pub(super) fn close_workspace_folder(&mut self, workspace_url: &Url) -> crate::Result<()> {
|
||||||
let workspace_path = workspace_url.to_file_path().map_err(|()| {
|
let workspace_path = workspace_url.to_file_path().map_err(|()| {
|
||||||
anyhow!("Failed to convert workspace URL to file path: {workspace_url}")
|
anyhow!("Failed to convert workspace URL to file path: {workspace_url}")
|
||||||
|
@ -404,6 +389,23 @@ impl Index {
|
||||||
.next_back()
|
.next_back()
|
||||||
.map(|(_, settings)| settings)
|
.map(|(_, settings)| settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the workspace root folders contained in this index.
|
||||||
|
pub(super) fn workspace_root_folders(&self) -> impl Iterator<Item = &Path> {
|
||||||
|
self.settings.keys().map(PathBuf::as_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of open documents.
|
||||||
|
pub(super) fn open_documents_len(&self) -> usize {
|
||||||
|
self.documents.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the paths to the configuration files in the index.
|
||||||
|
pub(super) fn config_file_paths(&self) -> impl Iterator<Item = &Path> {
|
||||||
|
self.settings
|
||||||
|
.values()
|
||||||
|
.flat_map(|WorkspaceSettings { ruff_settings, .. }| ruff_settings.config_file_paths())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps a workspace folder root to its settings.
|
/// Maps a workspace folder root to its settings.
|
||||||
|
|
|
@ -20,6 +20,7 @@ use ruff_workspace::{
|
||||||
|
|
||||||
use crate::session::settings::{ConfigurationPreference, ResolvedEditorSettings};
|
use crate::session::settings::{ConfigurationPreference, ResolvedEditorSettings};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct RuffSettings {
|
pub struct RuffSettings {
|
||||||
/// The path to this configuration file, used for debugging.
|
/// The path to this configuration file, used for debugging.
|
||||||
/// The default fallback configuration does not have a file path.
|
/// The default fallback configuration does not have a file path.
|
||||||
|
@ -28,6 +29,12 @@ pub struct RuffSettings {
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RuffSettings {
|
||||||
|
pub(crate) fn path(&self) -> Option<&Path> {
|
||||||
|
self.path.as_deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Deref for RuffSettings {
|
impl Deref for RuffSettings {
|
||||||
type Target = Settings;
|
type Target = Settings;
|
||||||
|
|
||||||
|
@ -298,15 +305,16 @@ impl RuffSettingsIndex {
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn list_files(&self) -> impl Iterator<Item = &Path> {
|
pub(super) fn fallback(&self) -> Arc<RuffSettings> {
|
||||||
|
self.fallback.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the paths to the configuration files in the index.
|
||||||
|
pub(crate) fn config_file_paths(&self) -> impl Iterator<Item = &Path> {
|
||||||
self.index
|
self.index
|
||||||
.values()
|
.values()
|
||||||
.filter_map(|settings| settings.path.as_deref())
|
.filter_map(|settings| settings.path.as_deref())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn fallback(&self) -> Arc<RuffSettings> {
|
|
||||||
self.fallback.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EditorConfigurationTransformer<'a>(&'a ResolvedEditorSettings, &'a Path);
|
struct EditorConfigurationTransformer<'a>(&'a ResolvedEditorSettings, &'a Path);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue