diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index f4b90db3a0..ff2a54117b 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -50,6 +50,7 @@ mod typing; mod markdown_remove; mod doc_links; mod view_crate_graph; +mod view_item_tree; use std::sync::Arc; @@ -288,6 +289,10 @@ impl Analysis { self.with_db(|db| view_hir::view_hir(&db, position)) } + pub fn view_item_tree(&self, file_id: FileId) -> Cancelable { + self.with_db(|db| view_item_tree::view_item_tree(&db, file_id)) + } + /// Renders the crate graph to GraphViz "dot" syntax. pub fn view_crate_graph(&self) -> Cancelable> { self.with_db(|db| view_crate_graph::view_crate_graph(&db)) diff --git a/crates/ide/src/view_item_tree.rs b/crates/ide/src/view_item_tree.rs new file mode 100644 index 0000000000..3dc03085d6 --- /dev/null +++ b/crates/ide/src/view_item_tree.rs @@ -0,0 +1,16 @@ +use hir::db::DefDatabase; +use ide_db::base_db::FileId; +use ide_db::RootDatabase; + +// Feature: Debug ItemTree +// +// Displays the ItemTree of the currently open file, for debugging. +// +// |=== +// | Editor | Action Name +// +// | VS Code | **Rust Analyzer: Debug ItemTree** +// |=== +pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String { + db.file_item_tree(file_id.into()).pretty_print() +} diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 51041d7a0c..aa12fd94bd 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -117,6 +117,16 @@ pub(crate) fn handle_view_hir( Ok(res) } +pub(crate) fn handle_view_item_tree( + snap: GlobalStateSnapshot, + params: lsp_ext::ViewItemTreeParams, +) -> Result { + let _p = profile::span("handle_view_item_tree"); + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let res = snap.analysis.view_item_tree(file_id)?; + Ok(res) +} + pub(crate) fn handle_view_crate_graph(snap: GlobalStateSnapshot, (): ()) -> Result { let _p = profile::span("handle_view_crate_graph"); let dot = snap.analysis.view_crate_graph()??; diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 34b53a7a80..9050487930 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -70,6 +70,20 @@ impl Request for ViewCrateGraph { const METHOD: &'static str = "rust-analyzer/viewCrateGraph"; } +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ViewItemTreeParams { + pub text_document: TextDocumentIdentifier, +} + +pub enum ViewItemTree {} + +impl Request for ViewItemTree { + type Params = ViewItemTreeParams; + type Result = String; + const METHOD: &'static str = "rust-analyzer/viewItemTree"; +} + pub enum ExpandMacro {} impl Request for ExpandMacro { diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 4e07916113..f837b89ddc 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -514,6 +514,7 @@ impl GlobalState { .on::(handlers::handle_syntax_tree) .on::(handlers::handle_view_hir) .on::(handlers::handle_view_crate_graph) + .on::(handlers::handle_view_item_tree) .on::(handlers::handle_expand_macro) .on::(handlers::handle_parent_module) .on::(handlers::handle_runnables) diff --git a/editors/code/package.json b/editors/code/package.json index 1743b374c0..17d9281ff7 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -109,6 +109,11 @@ "title": "View Hir", "category": "Rust Analyzer" }, + { + "command": "rust-analyzer.viewItemTree", + "title": "Debug ItemTree", + "category": "Rust Analyzer" + }, { "command": "rust-analyzer.viewCrateGraph", "title": "View Crate Graph", diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 8ab259af22..8f672e68db 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -429,6 +429,56 @@ export function viewHir(ctx: Ctx): Cmd { }; } +export function viewItemTree(ctx: Ctx): Cmd { + const tdcp = new class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse('rust-analyzer://viewItemTree/itemtree.txt'); + readonly eventEmitter = new vscode.EventEmitter(); + constructor() { + vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); + vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions); + } + + private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { + if (isRustDocument(event.document)) { + // We need to order this after language server updates, but there's no API for that. + // Hence, good old sleep(). + void sleep(10).then(() => this.eventEmitter.fire(this.uri)); + } + } + private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { + if (editor && isRustEditor(editor)) { + this.eventEmitter.fire(this.uri); + } + } + + provideTextDocumentContent(_uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult { + const rustEditor = ctx.activeRustEditor; + const client = ctx.client; + if (!rustEditor || !client) return ''; + + const params = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(rustEditor.document), + }; + return client.sendRequest(ra.viewItemTree, params, ct); + } + + get onDidChange(): vscode.Event { + return this.eventEmitter.event; + } + }; + + ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); + + return async () => { + const document = await vscode.workspace.openTextDocument(tdcp.uri); + tdcp.eventEmitter.fire(tdcp.uri); + void await vscode.window.showTextDocument(document, { + viewColumn: vscode.ViewColumn.Two, + preserveFocus: true + }); + }; +} + export function viewCrateGraph(ctx: Ctx): Cmd { return async () => { const panel = vscode.window.createWebviewPanel("rust-analyzer.crate-graph", "rust-analyzer crate graph", vscode.ViewColumn.Two); diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index aa745a65ce..6d5c2ea72d 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -27,6 +27,12 @@ export const syntaxTree = new lc.RequestType("ru export const viewHir = new lc.RequestType("rust-analyzer/viewHir"); +export interface ViewItemTreeParams { + textDocument: lc.TextDocumentIdentifier; +} + +export const viewItemTree = new lc.RequestType("rust-analyzer/viewItemTree"); + export const viewCrateGraph = new lc.RequestType0("rust-analyzer/viewCrateGraph"); export interface ExpandMacroParams { diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 516322d035..92c797d47f 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -106,6 +106,7 @@ async function tryActivate(context: vscode.ExtensionContext) { ctx.registerCommand('parentModule', commands.parentModule); ctx.registerCommand('syntaxTree', commands.syntaxTree); ctx.registerCommand('viewHir', commands.viewHir); + ctx.registerCommand('viewItemTree', commands.viewItemTree); ctx.registerCommand('viewCrateGraph', commands.viewCrateGraph); ctx.registerCommand('expandMacro', commands.expandMacro); ctx.registerCommand('run', commands.run);