aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock7
-rw-r--r--crates/ide/Cargo.toml1
-rw-r--r--crates/ide/src/lib.rs5
-rw-r--r--crates/ide/src/view_crate_graph.rs81
-rw-r--r--crates/rust-analyzer/src/handlers.rs6
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs8
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1
-rw-r--r--editors/code/package.json5
-rw-r--r--editors/code/src/commands.ts8
-rw-r--r--editors/code/src/lsp_ext.ts2
-rw-r--r--editors/code/src/main.ts1
11 files changed, 125 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0e1234b72..f9c34547e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -320,6 +320,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
320checksum = "fc4b29f4b9bb94bf267d57269fd0706d343a160937108e9619fe380645428abb" 320checksum = "fc4b29f4b9bb94bf267d57269fd0706d343a160937108e9619fe380645428abb"
321 321
322[[package]] 322[[package]]
323name = "dot"
324version = "0.1.4"
325source = "registry+https://github.com/rust-lang/crates.io-index"
326checksum = "a74b6c4d4a1cff5f454164363c16b72fa12463ca6b31f4b5f2035a65fa3d5906"
327
328[[package]]
323name = "drop_bomb" 329name = "drop_bomb"
324version = "0.1.5" 330version = "0.1.5"
325source = "registry+https://github.com/rust-lang/crates.io-index" 331source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -588,6 +594,7 @@ version = "0.0.0"
588dependencies = [ 594dependencies = [
589 "cfg", 595 "cfg",
590 "cov-mark", 596 "cov-mark",
597 "dot",
591 "either", 598 "either",
592 "expect-test", 599 "expect-test",
593 "hir", 600 "hir",
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index f04bcf531..88f3d09d3 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -20,6 +20,7 @@ oorandom = "11.1.2"
20pulldown-cmark-to-cmark = "6.0.0" 20pulldown-cmark-to-cmark = "6.0.0"
21pulldown-cmark = { version = "0.8.0", default-features = false } 21pulldown-cmark = { version = "0.8.0", default-features = false }
22url = "2.1.1" 22url = "2.1.1"
23dot = "0.1.4"
23 24
24stdx = { path = "../stdx", version = "0.0.0" } 25stdx = { path = "../stdx", version = "0.0.0" }
25syntax = { path = "../syntax", version = "0.0.0" } 26syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 8e5b72044..34360501a 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -49,6 +49,7 @@ mod syntax_tree;
49mod typing; 49mod typing;
50mod markdown_remove; 50mod markdown_remove;
51mod doc_links; 51mod doc_links;
52mod view_crate_graph;
52 53
53use std::sync::Arc; 54use std::sync::Arc;
54 55
@@ -287,6 +288,10 @@ impl Analysis {
287 self.with_db(|db| view_hir::view_hir(&db, position)) 288 self.with_db(|db| view_hir::view_hir(&db, position))
288 } 289 }
289 290
291 pub fn view_crate_graph(&self) -> Cancelable<Result<String, String>> {
292 self.with_db(|db| view_crate_graph::view_crate_graph(&db))
293 }
294
290 pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> { 295 pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> {
291 self.with_db(|db| expand_macro::expand_macro(db, position)) 296 self.with_db(|db| expand_macro::expand_macro(db, position))
292 } 297 }
diff --git a/crates/ide/src/view_crate_graph.rs b/crates/ide/src/view_crate_graph.rs
new file mode 100644
index 000000000..4da4ce2b3
--- /dev/null
+++ b/crates/ide/src/view_crate_graph.rs
@@ -0,0 +1,81 @@
1use std::{
2 error::Error,
3 io::{Read, Write},
4 process::{Command, Stdio},
5 sync::Arc,
6};
7
8use dot::Id;
9use ide_db::{
10 base_db::{CrateGraph, CrateId, Dependency, SourceDatabase},
11 RootDatabase,
12};
13
14// Feature: View Crate Graph
15//
16// Renders the currently loaded crate graph as an SVG graphic. Requires the `dot` tool to be
17// installed.
18//
19// |===
20// | Editor | Action Name
21//
22// | VS Code | **Rust Analyzer: View Crate Graph**
23// |===
24pub(crate) fn view_crate_graph(db: &RootDatabase) -> Result<String, String> {
25 let mut dot = Vec::new();
26 let graph = DotCrateGraph(db.crate_graph());
27 dot::render(&graph, &mut dot).unwrap();
28
29 render_svg(&dot).map_err(|e| e.to_string())
30}
31
32fn render_svg(dot: &[u8]) -> Result<String, Box<dyn Error>> {
33 // We shell out to `dot` to render to SVG, as there does not seem to be a pure-Rust renderer.
34 let child = Command::new("dot")
35 .arg("-Tsvg")
36 .stdin(Stdio::piped())
37 .stdout(Stdio::piped())
38 .spawn()
39 .map_err(|err| format!("failed to spawn `dot -Tsvg`: {}", err))?;
40 child.stdin.unwrap().write_all(&dot)?;
41
42 let mut svg = String::new();
43 child.stdout.unwrap().read_to_string(&mut svg)?;
44 Ok(svg)
45}
46
47struct DotCrateGraph(Arc<CrateGraph>);
48
49type Edge<'a> = (CrateId, &'a Dependency);
50
51impl<'a> dot::GraphWalk<'a, CrateId, Edge<'a>> for DotCrateGraph {
52 fn nodes(&'a self) -> dot::Nodes<'a, CrateId> {
53 self.0.iter().collect()
54 }
55
56 fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> {
57 self.0
58 .iter()
59 .flat_map(|krate| self.0[krate].dependencies.iter().map(move |dep| (krate, dep)))
60 .collect()
61 }
62
63 fn source(&'a self, edge: &Edge<'a>) -> CrateId {
64 edge.0
65 }
66
67 fn target(&'a self, edge: &Edge<'a>) -> CrateId {
68 edge.1.crate_id
69 }
70}
71
72impl<'a> dot::Labeller<'a, CrateId, Edge<'a>> for DotCrateGraph {
73 fn graph_id(&'a self) -> Id<'a> {
74 Id::new("rust_analyzer_crate_graph").unwrap()
75 }
76
77 fn node_id(&'a self, n: &CrateId) -> Id<'a> {
78 let name = self.0[*n].display_name.as_ref().map_or("_missing_name_", |name| &*name);
79 Id::new(name).unwrap()
80 }
81}
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index f6e40f872..dafbab6d0 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -117,6 +117,12 @@ pub(crate) fn handle_view_hir(
117 Ok(res) 117 Ok(res)
118} 118}
119 119
120pub(crate) fn handle_view_crate_graph(snap: GlobalStateSnapshot, (): ()) -> Result<String> {
121 let _p = profile::span("handle_view_crate_graph");
122 let res = snap.analysis.view_crate_graph()??;
123 Ok(res)
124}
125
120pub(crate) fn handle_expand_macro( 126pub(crate) fn handle_expand_macro(
121 snap: GlobalStateSnapshot, 127 snap: GlobalStateSnapshot,
122 params: lsp_ext::ExpandMacroParams, 128 params: lsp_ext::ExpandMacroParams,
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index b8835a534..3bd098058 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -61,6 +61,14 @@ impl Request for ViewHir {
61 const METHOD: &'static str = "rust-analyzer/viewHir"; 61 const METHOD: &'static str = "rust-analyzer/viewHir";
62} 62}
63 63
64pub enum ViewCrateGraph {}
65
66impl Request for ViewCrateGraph {
67 type Params = ();
68 type Result = String;
69 const METHOD: &'static str = "rust-analyzer/viewCrateGraph";
70}
71
64pub enum ExpandMacro {} 72pub enum ExpandMacro {}
65 73
66impl Request for ExpandMacro { 74impl Request for ExpandMacro {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index ce7ece559..c7bd7eee1 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -513,6 +513,7 @@ impl GlobalState {
513 .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status) 513 .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
514 .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree) 514 .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
515 .on::<lsp_ext::ViewHir>(handlers::handle_view_hir) 515 .on::<lsp_ext::ViewHir>(handlers::handle_view_hir)
516 .on::<lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph)
516 .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro) 517 .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
517 .on::<lsp_ext::ParentModule>(handlers::handle_parent_module) 518 .on::<lsp_ext::ParentModule>(handlers::handle_parent_module)
518 .on::<lsp_ext::Runnables>(handlers::handle_runnables) 519 .on::<lsp_ext::Runnables>(handlers::handle_runnables)
diff --git a/editors/code/package.json b/editors/code/package.json
index f35d30898..0f38a1673 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -110,6 +110,11 @@
110 "category": "Rust Analyzer" 110 "category": "Rust Analyzer"
111 }, 111 },
112 { 112 {
113 "command": "rust-analyzer.viewCrateGraph",
114 "title": "View Crate Graph",
115 "category": "Rust Analyzer"
116 },
117 {
113 "command": "rust-analyzer.expandMacro", 118 "command": "rust-analyzer.expandMacro",
114 "title": "Expand macro recursively", 119 "title": "Expand macro recursively",
115 "category": "Rust Analyzer" 120 "category": "Rust Analyzer"
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 4092435db..8ab259af2 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -429,6 +429,14 @@ export function viewHir(ctx: Ctx): Cmd {
429 }; 429 };
430} 430}
431 431
432export function viewCrateGraph(ctx: Ctx): Cmd {
433 return async () => {
434 const panel = vscode.window.createWebviewPanel("rust-analyzer.crate-graph", "rust-analyzer crate graph", vscode.ViewColumn.Two);
435 const svg = await ctx.client.sendRequest(ra.viewCrateGraph);
436 panel.webview.html = svg;
437 };
438}
439
432// Opens the virtual file that will show the syntax tree 440// Opens the virtual file that will show the syntax tree
433// 441//
434// The contents of the file come from the `TextDocumentContentProvider` 442// The contents of the file come from the `TextDocumentContentProvider`
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index f78de894b..aa745a65c 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -27,6 +27,8 @@ export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>("ru
27 27
28export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>("rust-analyzer/viewHir"); 28export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>("rust-analyzer/viewHir");
29 29
30export const viewCrateGraph = new lc.RequestType0<string, void>("rust-analyzer/viewCrateGraph");
31
30export interface ExpandMacroParams { 32export interface ExpandMacroParams {
31 textDocument: lc.TextDocumentIdentifier; 33 textDocument: lc.TextDocumentIdentifier;
32 position: lc.Position; 34 position: lc.Position;
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 643fb643f..516322d03 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -106,6 +106,7 @@ async function tryActivate(context: vscode.ExtensionContext) {
106 ctx.registerCommand('parentModule', commands.parentModule); 106 ctx.registerCommand('parentModule', commands.parentModule);
107 ctx.registerCommand('syntaxTree', commands.syntaxTree); 107 ctx.registerCommand('syntaxTree', commands.syntaxTree);
108 ctx.registerCommand('viewHir', commands.viewHir); 108 ctx.registerCommand('viewHir', commands.viewHir);
109 ctx.registerCommand('viewCrateGraph', commands.viewCrateGraph);
109 ctx.registerCommand('expandMacro', commands.expandMacro); 110 ctx.registerCommand('expandMacro', commands.expandMacro);
110 ctx.registerCommand('run', commands.run); 111 ctx.registerCommand('run', commands.run);
111 ctx.registerCommand('copyRunCommandLine', commands.copyRunCommandLine); 112 ctx.registerCommand('copyRunCommandLine', commands.copyRunCommandLine);