From 077592a12fd982de3e69572a4c738dd4468617f9 Mon Sep 17 00:00:00 2001 From: Phil Ellison Date: Mon, 28 Dec 2020 18:29:58 +0000 Subject: Initial implementation of view-hir command --- crates/hir/src/code_model.rs | 3 +- crates/ide/src/lib.rs | 5 +++ crates/ide/src/view_hir.rs | 39 ++++++++++++++++++++ crates/rust-analyzer/src/handlers.rs | 10 +++++ crates/rust-analyzer/src/lsp_ext.rs | 8 ++++ crates/rust-analyzer/src/main_loop.rs | 1 + editors/code/package.json | 9 +++++ editors/code/src/commands.ts | 69 +++++++++++++++++++++++++++++++++++ editors/code/src/lsp_ext.ts | 1 + editors/code/src/main.ts | 1 + 10 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 crates/ide/src/view_hir.rs diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index b7ded3478..9b78944c6 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs @@ -729,7 +729,8 @@ impl DefWithBody { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Function { - pub(crate) id: FunctionId, + // DO NOT MERGE: this was previously pub(crate) + pub id: FunctionId, } impl Function { diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 41eb139d1..25c2047ca 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -31,6 +31,7 @@ mod folding_ranges; mod goto_definition; mod goto_implementation; mod goto_type_definition; +mod view_hir; mod hover; mod inlay_hints; mod join_lines; @@ -271,6 +272,10 @@ impl Analysis { self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range)) } + pub fn view_hir(&self, position: FilePosition) -> Cancelable { + self.with_db(|db| view_hir::view_hir(&db, position)) + } + pub fn expand_macro(&self, position: FilePosition) -> Cancelable> { self.with_db(|db| expand_macro::expand_macro(db, position)) } diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs new file mode 100644 index 000000000..e48f2cfe0 --- /dev/null +++ b/crates/ide/src/view_hir.rs @@ -0,0 +1,39 @@ +use hir::{Function, Semantics}; +use hir::db::DefDatabase; +use ide_db::base_db::FilePosition; +use ide_db::RootDatabase; +use syntax::{AstNode, algo::find_node_at_offset, ast}; +use std::fmt::Write; + +// Feature: View hir +// +// |=== +// | Editor | Action Name +// +// | VS Code | **Rust Analyzer: View Hir** +// |=== +pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { + body_hir(db, position).unwrap_or("Not inside a function body".to_string()) +} + +fn body_hir(db: &RootDatabase, position: FilePosition) -> Option { + let sema = Semantics::new(db); + let source_file = sema.parse(position.file_id); + + let function = find_node_at_offset::( + source_file.syntax(), + position.offset, + )?; + + let function: Function = sema.to_def(&function)?; + let body = db.body(function.id.into()); + + let mut result = String::new(); + writeln!(&mut result, "== Body expressions ==").ok()?; + + for (id, expr) in body.exprs.iter() { + writeln!(&mut result, "{:?}: {:?}", id, expr).ok()?; + } + + Some(result) +} \ No newline at end of file diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 374fb5302..85f1f81ad 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -104,6 +104,16 @@ pub(crate) fn handle_syntax_tree( Ok(res) } +pub(crate) fn handle_view_hir( + snap: GlobalStateSnapshot, + params: lsp_types::TextDocumentPositionParams, +) -> Result { + let _p = profile::span("handle_view_hir"); + let position = from_proto::file_position(&snap, params)?; + let res = snap.analysis.view_hir(position)?; + Ok(res) +} + pub(crate) fn handle_expand_macro( snap: GlobalStateSnapshot, params: lsp_ext::ExpandMacroParams, diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 93ac45415..a85978737 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -53,6 +53,14 @@ pub struct SyntaxTreeParams { pub range: Option, } +pub enum ViewHir {} + +impl Request for ViewHir { + type Params = lsp_types::TextDocumentPositionParams; + type Result = String; + const METHOD: &'static str = "rust-analyzer/viewHir"; +} + 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 5d55dc96e..8eca79f7e 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -443,6 +443,7 @@ impl GlobalState { .on_sync::(|s, p| handlers::handle_memory_usage(s, p))? .on::(handlers::handle_analyzer_status) .on::(handlers::handle_syntax_tree) + .on::(handlers::handle_view_hir) .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 13749a084..4bae5d647 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -103,6 +103,11 @@ "title": "Show Syntax Tree", "category": "Rust Analyzer" }, + { + "command": "rust-analyzer.viewHir", + "title": "View Hir", + "category": "Rust Analyzer" + }, { "command": "rust-analyzer.expandMacro", "title": "Expand macro recursively", @@ -998,6 +1003,10 @@ "command": "rust-analyzer.syntaxTree", "when": "inRustProject" }, + { + "command": "rust-analyzer.viewHir", + "when": "inRustProject" + }, { "command": "rust-analyzer.expandMacro", "when": "inRustProject" diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 9d4823a34..21b0c27f3 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -340,6 +340,75 @@ export function syntaxTree(ctx: Ctx): Cmd { }; } +// Opens the virtual file that will show hir +// +// The contents of the file come from the `TextDocumentContentProvider` +export function viewHir(ctx: Ctx): Cmd { + const tdcp = new class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse('rust-analyzer://viewHir/hir.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), + position: client.code2ProtocolConverter.asPosition( + rustEditor.selection.active, + ), + }; + return client.sendRequest(ra.viewHir, params, ct); + } + + get onDidChange(): vscode.Event { + return this.eventEmitter.event; + } + }; + + void new AstInspector(ctx); + + ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); + ctx.pushCleanup(vscode.languages.setLanguageConfiguration("ra_syntax_tree", { + brackets: [["[", ")"]], + })); + + return async () => { + const editor = vscode.window.activeTextEditor; + const rangeEnabled = !!editor && !editor.selection.isEmpty; + + const uri = rangeEnabled + ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) + : tdcp.uri; + + const document = await vscode.workspace.openTextDocument(uri); + + tdcp.eventEmitter.fire(uri); + + void await vscode.window.showTextDocument(document, { + viewColumn: vscode.ViewColumn.Two, + preserveFocus: true + }); + }; +} // Opens the virtual file that will show the syntax tree // diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index 5e877ce65..d21a3db86 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -24,6 +24,7 @@ export interface SyntaxTreeParams { } export const syntaxTree = new lc.RequestType("rust-analyzer/syntaxTree"); +export const viewHir = new lc.RequestType("rust-analyzer/viewHir"); export interface ExpandMacroParams { textDocument: lc.TextDocumentIdentifier; diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 282240d84..60907dfd4 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -105,6 +105,7 @@ async function tryActivate(context: vscode.ExtensionContext) { ctx.registerCommand('joinLines', commands.joinLines); ctx.registerCommand('parentModule', commands.parentModule); ctx.registerCommand('syntaxTree', commands.syntaxTree); + ctx.registerCommand('viewHir', commands.viewHir); ctx.registerCommand('expandMacro', commands.expandMacro); ctx.registerCommand('run', commands.run); ctx.registerCommand('debug', commands.debug); -- cgit v1.2.3