aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/view_crate_graph.rs38
1 files changed, 30 insertions, 8 deletions
diff --git a/crates/ide/src/view_crate_graph.rs b/crates/ide/src/view_crate_graph.rs
index 45995bf58..527a5ae0d 100644
--- a/crates/ide/src/view_crate_graph.rs
+++ b/crates/ide/src/view_crate_graph.rs
@@ -7,23 +7,36 @@ use std::{
7 7
8use dot::Id; 8use dot::Id;
9use ide_db::{ 9use ide_db::{
10 base_db::{CrateGraph, CrateId, Dependency, SourceDatabase}, 10 base_db::{CrateGraph, CrateId, Dependency, SourceDatabase, SourceDatabaseExt},
11 RootDatabase, 11 RootDatabase,
12}; 12};
13use rustc_hash::FxHashSet;
13 14
14// Feature: View Crate Graph 15// Feature: View Crate Graph
15// 16//
16// Renders the currently loaded crate graph as an SVG graphic. Requires the `dot` tool, which 17// Renders the currently loaded crate graph as an SVG graphic. Requires the `dot` tool, which
17// is part of graphviz, to be installed. 18// is part of graphviz, to be installed.
18// 19//
20// Only workspace crates are included, no crates.io dependencies or sysroot crates.
21//
19// |=== 22// |===
20// | Editor | Action Name 23// | Editor | Action Name
21// 24//
22// | VS Code | **Rust Analyzer: View Crate Graph** 25// | VS Code | **Rust Analyzer: View Crate Graph**
23// |=== 26// |===
24pub(crate) fn view_crate_graph(db: &RootDatabase) -> Result<String, String> { 27pub(crate) fn view_crate_graph(db: &RootDatabase) -> Result<String, String> {
28 let crate_graph = db.crate_graph();
29 let crates_to_render = crate_graph
30 .iter()
31 .filter(|krate| {
32 // Only render workspace crates
33 let root_id = db.file_source_root(crate_graph[*krate].root_file_id);
34 !db.source_root(root_id).is_library
35 })
36 .collect();
37 let graph = DotCrateGraph { graph: crate_graph, crates_to_render };
38
25 let mut dot = Vec::new(); 39 let mut dot = Vec::new();
26 let graph = DotCrateGraph(db.crate_graph());
27 dot::render(&graph, &mut dot).unwrap(); 40 dot::render(&graph, &mut dot).unwrap();
28 41
29 render_svg(&dot).map_err(|e| e.to_string()) 42 render_svg(&dot).map_err(|e| e.to_string())
@@ -36,7 +49,7 @@ fn render_svg(dot: &[u8]) -> Result<String, Box<dyn Error>> {
36 .stdin(Stdio::piped()) 49 .stdin(Stdio::piped())
37 .stdout(Stdio::piped()) 50 .stdout(Stdio::piped())
38 .spawn() 51 .spawn()
39 .map_err(|err| format!("failed to spawn `dot -Tsvg`: {}", err))?; 52 .map_err(|err| format!("failed to spawn `dot`: {}", err))?;
40 child.stdin.unwrap().write_all(&dot)?; 53 child.stdin.unwrap().write_all(&dot)?;
41 54
42 let mut svg = String::new(); 55 let mut svg = String::new();
@@ -44,19 +57,28 @@ fn render_svg(dot: &[u8]) -> Result<String, Box<dyn Error>> {
44 Ok(svg) 57 Ok(svg)
45} 58}
46 59
47struct DotCrateGraph(Arc<CrateGraph>); 60struct DotCrateGraph {
61 graph: Arc<CrateGraph>,
62 crates_to_render: FxHashSet<CrateId>,
63}
48 64
49type Edge<'a> = (CrateId, &'a Dependency); 65type Edge<'a> = (CrateId, &'a Dependency);
50 66
51impl<'a> dot::GraphWalk<'a, CrateId, Edge<'a>> for DotCrateGraph { 67impl<'a> dot::GraphWalk<'a, CrateId, Edge<'a>> for DotCrateGraph {
52 fn nodes(&'a self) -> dot::Nodes<'a, CrateId> { 68 fn nodes(&'a self) -> dot::Nodes<'a, CrateId> {
53 self.0.iter().collect() 69 self.crates_to_render.iter().copied().collect()
54 } 70 }
55 71
56 fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { 72 fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> {
57 self.0 73 self.crates_to_render
58 .iter() 74 .iter()
59 .flat_map(|krate| self.0[krate].dependencies.iter().map(move |dep| (krate, dep))) 75 .flat_map(|krate| {
76 self.graph[*krate]
77 .dependencies
78 .iter()
79 .filter(|dep| self.crates_to_render.contains(&dep.crate_id))
80 .map(move |dep| (*krate, dep))
81 })
60 .collect() 82 .collect()
61 } 83 }
62 84
@@ -75,7 +97,7 @@ impl<'a> dot::Labeller<'a, CrateId, Edge<'a>> for DotCrateGraph {
75 } 97 }
76 98
77 fn node_id(&'a self, n: &CrateId) -> Id<'a> { 99 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); 100 let name = self.graph[*n].display_name.as_ref().map_or("_missing_name_", |name| &*name);
79 Id::new(format!("{}_{}", name, n.0)).unwrap() 101 Id::new(format!("{}_{}", name, n.0)).unwrap()
80 } 102 }
81} 103}