3 use dot
::{Id, LabelText}
;
5 base_db
::{CrateGraph, CrateId, Dependency, SourceDatabase, SourceDatabaseExt}
,
6 FxHashSet
, RootDatabase
,
9 // Feature: View Crate Graph
11 // Renders the currently loaded crate graph as an SVG graphic. Requires the `dot` tool, which
12 // is part of graphviz, to be installed.
14 // Only workspace crates are included, no crates.io dependencies or sysroot crates.
17 // | Editor | Action Name
19 // | VS Code | **Rust Analyzer: View Crate Graph**
21 pub(crate) fn view_crate_graph(db
: &RootDatabase
, full
: bool
) -> Result
<String
, String
> {
22 let crate_graph
= db
.crate_graph();
23 let crates_to_render
= crate_graph
29 // Only render workspace crates
30 let root_id
= db
.file_source_root(crate_graph
[*krate
].root_file_id
);
31 !db
.source_root(root_id
).is_library
35 let graph
= DotCrateGraph { graph: crate_graph, crates_to_render }
;
37 let mut dot
= Vec
::new();
38 dot
::render(&graph
, &mut dot
).unwrap();
39 Ok(String
::from_utf8(dot
).unwrap())
42 struct DotCrateGraph
{
43 graph
: Arc
<CrateGraph
>,
44 crates_to_render
: FxHashSet
<CrateId
>,
47 type Edge
<'a
> = (CrateId
, &'a Dependency
);
49 impl<'a
> dot
::GraphWalk
<'a
, CrateId
, Edge
<'a
>> for DotCrateGraph
{
50 fn nodes(&'a
self) -> dot
::Nodes
<'a
, CrateId
> {
51 self.crates_to_render
.iter().copied().collect()
54 fn edges(&'a
self) -> dot
::Edges
<'a
, Edge
<'a
>> {
61 .filter(|dep
| self.crates_to_render
.contains(&dep
.crate_id
))
62 .map(move |dep
| (*krate
, dep
))
67 fn source(&'a
self, edge
: &Edge
<'a
>) -> CrateId
{
71 fn target(&'a
self, edge
: &Edge
<'a
>) -> CrateId
{
76 impl<'a
> dot
::Labeller
<'a
, CrateId
, Edge
<'a
>> for DotCrateGraph
{
77 fn graph_id(&'a
self) -> Id
<'a
> {
78 Id
::new("rust_analyzer_crate_graph").unwrap()
81 fn node_id(&'a
self, n
: &CrateId
) -> Id
<'a
> {
82 Id
::new(format
!("_{}", n
.0)).unwrap()
85 fn node_shape(&'a
self, _node
: &CrateId
) -> Option
<LabelText
<'a
>> {
86 Some(LabelText
::LabelStr("box".into()))
89 fn node_label(&'a
self, n
: &CrateId
) -> LabelText
<'a
> {
90 let name
= self.graph
[*n
].display_name
.as_ref().map_or("(unnamed crate)", |name
| &*name
);
91 LabelText
::LabelStr(name
.into())