From af8063fe373cf06a345b0d4eee14ef1ef6873bc7 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Sep 2020 22:05:18 +0200 Subject: [PATCH] Extend **Status** command to also show dep info for the file This should help with troubleshooting wrong project configuration --- crates/ide/src/lib.rs | 4 +-- crates/ide/src/status.rs | 49 +++++++++++++++++++--------- crates/rust-analyzer/src/handlers.rs | 19 +++++++++-- crates/rust-analyzer/src/lsp_ext.rs | 8 ++++- docs/dev/lsp-extensions.md | 9 ++++- docs/user/manual.adoc | 4 +-- editors/code/src/commands.ts | 19 +++++++---- editors/code/src/lsp_ext.ts | 5 ++- 8 files changed, 85 insertions(+), 32 deletions(-) diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 96dae9ee0b..6d5fd1a557 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -216,8 +216,8 @@ impl Analysis { } /// Debug info about the current state of the analysis. - pub fn status(&self) -> Cancelable { - self.with_db(|db| status::status(&*db)) + pub fn status(&self, file_id: Option) -> Cancelable { + self.with_db(|db| status::status(&*db, file_id)) } pub fn prime_caches(&self, files: Vec) -> Cancelable<()> { diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index 1427c50cf8..0af84daa0a 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs @@ -2,19 +2,19 @@ use std::{fmt, iter::FromIterator, sync::Arc}; use base_db::{ salsa::debug::{DebugQueryTable, TableEntry}, - FileTextQuery, SourceRootId, + CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId, }; use hir::MacroFile; use ide_db::{ symbol_index::{LibrarySymbolsQuery, SymbolIndex}, RootDatabase, }; +use itertools::Itertools; use profile::{memory_usage, Bytes}; use rustc_hash::FxHashMap; +use stdx::format_to; use syntax::{ast, Parse, SyntaxNode}; -use crate::FileId; - fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { base_db::ParseQuery.in_db(db).entries::() } @@ -31,19 +31,36 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { // // | VS Code | **Rust Analyzer: Status** // |=== -pub(crate) fn status(db: &RootDatabase) -> String { - let files_stats = FileTextQuery.in_db(db).entries::(); - let syntax_tree_stats = syntax_tree_stats(db); - let macro_syntax_tree_stats = macro_syntax_tree_stats(db); - let symbols_stats = LibrarySymbolsQuery.in_db(db).entries::(); - format!( - "{}\n{}\n{}\n{} (macros)\n{} total\n", - files_stats, - symbols_stats, - syntax_tree_stats, - macro_syntax_tree_stats, - memory_usage(), - ) +pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { + let mut buf = String::new(); + format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::()); + format_to!(buf, "{}\n", LibrarySymbolsQuery.in_db(db).entries::()); + format_to!(buf, "{}\n", syntax_tree_stats(db)); + format_to!(buf, "{} (macros)\n", macro_syntax_tree_stats(db)); + format_to!(buf, "{} total\n", memory_usage()); + + if let Some(file_id) = file_id { + format_to!(buf, "\nfile info:\n"); + let krate = crate::parent_module::crate_for(db, file_id).pop(); + match krate { + Some(krate) => { + let crate_graph = db.crate_graph(); + let display_crate = |krate: CrateId| match &crate_graph[krate].display_name { + Some(it) => format!("{}({:?})", it, krate), + None => format!("{:?}", krate), + }; + format_to!(buf, "crate: {}\n", display_crate(krate)); + let deps = crate_graph[krate] + .dependencies + .iter() + .map(|dep| format!("{}={:?}", dep.name, dep.crate_id)) + .format(", "); + format_to!(buf, "deps: {}\n", deps); + } + None => format_to!(buf, "does not belong to any crate"), + } + } + buf } #[derive(Default)] diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 7ac1a30f6c..afcec63ad1 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -38,10 +38,22 @@ use crate::{ to_proto, LspError, Result, }; -pub(crate) fn handle_analyzer_status(snap: GlobalStateSnapshot, _: ()) -> Result { +pub(crate) fn handle_analyzer_status( + snap: GlobalStateSnapshot, + params: lsp_ext::AnalyzerStatusParams, +) -> Result { let _p = profile::span("handle_analyzer_status"); let mut buf = String::new(); + + let mut file_id = None; + if let Some(tdi) = params.text_document { + match from_proto::file_id(&snap, &tdi.uri) { + Ok(it) => file_id = Some(it), + Err(_) => format_to!(buf, "file {} not found in vfs", tdi.uri), + } + } + if snap.workspaces.is_empty() { buf.push_str("no workspaces\n") } else { @@ -52,7 +64,10 @@ pub(crate) fn handle_analyzer_status(snap: GlobalStateSnapshot, _: ()) -> Result } buf.push_str("\nanalysis:\n"); buf.push_str( - &snap.analysis.status().unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()), + &snap + .analysis + .status(file_id) + .unwrap_or_else(|_| "Analysis retrieval was cancelled".to_owned()), ); format_to!(buf, "\n\nrequests:\n"); let requests = snap.latest_requests.read(); diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index e1a28b1b4b..43ff191dab 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -11,11 +11,17 @@ use serde::{Deserialize, Serialize}; pub enum AnalyzerStatus {} impl Request for AnalyzerStatus { - type Params = (); + type Params = AnalyzerStatusParams; type Result = String; const METHOD: &'static str = "rust-analyzer/analyzerStatus"; } +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct AnalyzerStatusParams { + pub text_document: Option, +} + pub enum MemoryUsage {} impl Request for MemoryUsage { diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 2e3133449f..f1160bb1cc 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -390,7 +390,14 @@ rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look **Method:** `rust-analyzer/analyzerStatus` -**Request:** `null` +**Request:** + +```typescript +interface AnalyzerStatusParams { + /// If specified, show dependencies of the current file. + textDocument?: TextDocumentIdentifier; +} +``` **Response:** `string` diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 7d85b36cb3..c1a7788520 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -113,8 +113,8 @@ Note that installing via `xtask install` does not work for VS Code Remote, inste Here are some useful self-diagnostic commands: -* **Rust Analyzer: Show RA Version** shows the version of `rust-analyzer` binary -* **Rust Analyzer: Status** prints some statistics about the server, like the few latest LSP requests +* **Rust Analyzer: Show RA Version** shows the version of `rust-analyzer` binary. +* **Rust Analyzer: Status** prints some statistics about the server, and dependency information for the current file. * To enable server-side logging, run with `env RA_LOG=info` and see `Output > Rust Analyzer Language Server` in VS Code's panel. * To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Rust Analyzer Language Server Trace` in the panel. * To enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open `Output > Rust Analyzer Client` in the panel. diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index e9581a9b59..1a90f1b7d9 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -21,7 +21,12 @@ export function analyzerStatus(ctx: Ctx): Cmd { provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult { if (!vscode.window.activeTextEditor) return ''; - return ctx.client.sendRequest(ra.analyzerStatus); + const params: ra.AnalyzerStatusParams = {}; + const doc = ctx.activeRustEditor?.document; + if (doc != null) { + params.textDocument = ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(doc); + } + return ctx.client.sendRequest(ra.analyzerStatus, params); } get onDidChange(): vscode.Event { @@ -94,7 +99,7 @@ export function matchingBrace(ctx: Ctx): Cmd { if (!editor || !client) return; const response = await client.sendRequest(ra.matchingBrace, { - textDocument: { uri: editor.document.uri.toString() }, + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), positions: editor.selections.map(s => client.code2ProtocolConverter.asPosition(s.active), ), @@ -118,7 +123,7 @@ export function joinLines(ctx: Ctx): Cmd { const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, { ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)), - textDocument: { uri: editor.document.uri.toString() }, + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), }); editor.edit((builder) => { client.protocol2CodeConverter.asTextEdits(items).forEach((edit: any) => { @@ -136,7 +141,7 @@ export function onEnter(ctx: Ctx): Cmd { if (!editor || !client) return false; const lcEdits = await client.sendRequest(ra.onEnter, { - textDocument: { uri: editor.document.uri.toString() }, + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), position: client.code2ProtocolConverter.asPosition( editor.selection.active, ), @@ -165,7 +170,7 @@ export function parentModule(ctx: Ctx): Cmd { if (!editor || !client) return; const response = await client.sendRequest(ra.parentModule, { - textDocument: { uri: editor.document.uri.toString() }, + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), position: client.code2ProtocolConverter.asPosition( editor.selection.active, ), @@ -191,7 +196,7 @@ export function ssr(ctx: Ctx): Cmd { const position = editor.selection.active; const selections = editor.selections; - const textDocument = { uri: editor.document.uri.toString() }; + const textDocument = ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document); const options: vscode.InputBoxOptions = { value: "() ==>> ()", @@ -339,7 +344,7 @@ export function expandMacro(ctx: Ctx): Cmd { const position = editor.selection.active; const expanded = await client.sendRequest(ra.expandMacro, { - textDocument: { uri: editor.document.uri.toString() }, + textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), position, }); diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index d167041c4c..eb422d3e75 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -4,7 +4,10 @@ import * as lc from "vscode-languageclient"; -export const analyzerStatus = new lc.RequestType0("rust-analyzer/analyzerStatus"); +export interface AnalyzerStatusParams { + textDocument?: lc.TextDocumentIdentifier; +} +export const analyzerStatus = new lc.RequestType("rust-analyzer/analyzerStatus"); export const memoryUsage = new lc.RequestType0("rust-analyzer/memoryUsage"); export type Status = "loading" | "ready" | "invalid" | "needsReload";