diff options
Diffstat (limited to 'crates/ide')
-rw-r--r-- | crates/ide/src/view_crate_graph.rs | 38 |
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 | ||
8 | use dot::Id; | 8 | use dot::Id; |
9 | use ide_db::{ | 9 | use ide_db::{ |
10 | base_db::{CrateGraph, CrateId, Dependency, SourceDatabase}, | 10 | base_db::{CrateGraph, CrateId, Dependency, SourceDatabase, SourceDatabaseExt}, |
11 | RootDatabase, | 11 | RootDatabase, |
12 | }; | 12 | }; |
13 | use 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 | // |=== |
24 | pub(crate) fn view_crate_graph(db: &RootDatabase) -> Result<String, String> { | 27 | pub(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 | ||
47 | struct DotCrateGraph(Arc<CrateGraph>); | 60 | struct DotCrateGraph { |
61 | graph: Arc<CrateGraph>, | ||
62 | crates_to_render: FxHashSet<CrateId>, | ||
63 | } | ||
48 | 64 | ||
49 | type Edge<'a> = (CrateId, &'a Dependency); | 65 | type Edge<'a> = (CrateId, &'a Dependency); |
50 | 66 | ||
51 | impl<'a> dot::GraphWalk<'a, CrateId, Edge<'a>> for DotCrateGraph { | 67 | impl<'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 | } |