mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-12 21:28:51 +00:00
Allow viewing the crate graph in a webview
This commit is contained in:
parent
9fa9d166d8
commit
a85a2c4d15
11 changed files with 125 additions and 0 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -319,6 +319,12 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc4b29f4b9bb94bf267d57269fd0706d343a160937108e9619fe380645428abb"
|
checksum = "fc4b29f4b9bb94bf267d57269fd0706d343a160937108e9619fe380645428abb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dot"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a74b6c4d4a1cff5f454164363c16b72fa12463ca6b31f4b5f2035a65fa3d5906"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "drop_bomb"
|
name = "drop_bomb"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
@ -588,6 +594,7 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg",
|
"cfg",
|
||||||
"cov-mark",
|
"cov-mark",
|
||||||
|
"dot",
|
||||||
"either",
|
"either",
|
||||||
"expect-test",
|
"expect-test",
|
||||||
"hir",
|
"hir",
|
||||||
|
|
|
@ -20,6 +20,7 @@ oorandom = "11.1.2"
|
||||||
pulldown-cmark-to-cmark = "6.0.0"
|
pulldown-cmark-to-cmark = "6.0.0"
|
||||||
pulldown-cmark = { version = "0.8.0", default-features = false }
|
pulldown-cmark = { version = "0.8.0", default-features = false }
|
||||||
url = "2.1.1"
|
url = "2.1.1"
|
||||||
|
dot = "0.1.4"
|
||||||
|
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
syntax = { path = "../syntax", version = "0.0.0" }
|
syntax = { path = "../syntax", version = "0.0.0" }
|
||||||
|
|
|
@ -49,6 +49,7 @@ mod syntax_tree;
|
||||||
mod typing;
|
mod typing;
|
||||||
mod markdown_remove;
|
mod markdown_remove;
|
||||||
mod doc_links;
|
mod doc_links;
|
||||||
|
mod view_crate_graph;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -287,6 +288,10 @@ impl Analysis {
|
||||||
self.with_db(|db| view_hir::view_hir(&db, position))
|
self.with_db(|db| view_hir::view_hir(&db, position))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn view_crate_graph(&self) -> Cancelable<Result<String, String>> {
|
||||||
|
self.with_db(|db| view_crate_graph::view_crate_graph(&db))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> {
|
pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> {
|
||||||
self.with_db(|db| expand_macro::expand_macro(db, position))
|
self.with_db(|db| expand_macro::expand_macro(db, position))
|
||||||
}
|
}
|
||||||
|
|
81
crates/ide/src/view_crate_graph.rs
Normal file
81
crates/ide/src/view_crate_graph.rs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
use std::{
|
||||||
|
error::Error,
|
||||||
|
io::{Read, Write},
|
||||||
|
process::{Command, Stdio},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use dot::Id;
|
||||||
|
use ide_db::{
|
||||||
|
base_db::{CrateGraph, CrateId, Dependency, SourceDatabase},
|
||||||
|
RootDatabase,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Feature: View Crate Graph
|
||||||
|
//
|
||||||
|
// Renders the currently loaded crate graph as an SVG graphic. Requires the `dot` tool to be
|
||||||
|
// installed.
|
||||||
|
//
|
||||||
|
// |===
|
||||||
|
// | Editor | Action Name
|
||||||
|
//
|
||||||
|
// | VS Code | **Rust Analyzer: View Crate Graph**
|
||||||
|
// |===
|
||||||
|
pub(crate) fn view_crate_graph(db: &RootDatabase) -> Result<String, String> {
|
||||||
|
let mut dot = Vec::new();
|
||||||
|
let graph = DotCrateGraph(db.crate_graph());
|
||||||
|
dot::render(&graph, &mut dot).unwrap();
|
||||||
|
|
||||||
|
render_svg(&dot).map_err(|e| e.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_svg(dot: &[u8]) -> Result<String, Box<dyn Error>> {
|
||||||
|
// We shell out to `dot` to render to SVG, as there does not seem to be a pure-Rust renderer.
|
||||||
|
let child = Command::new("dot")
|
||||||
|
.arg("-Tsvg")
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.map_err(|err| format!("failed to spawn `dot -Tsvg`: {}", err))?;
|
||||||
|
child.stdin.unwrap().write_all(&dot)?;
|
||||||
|
|
||||||
|
let mut svg = String::new();
|
||||||
|
child.stdout.unwrap().read_to_string(&mut svg)?;
|
||||||
|
Ok(svg)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DotCrateGraph(Arc<CrateGraph>);
|
||||||
|
|
||||||
|
type Edge<'a> = (CrateId, &'a Dependency);
|
||||||
|
|
||||||
|
impl<'a> dot::GraphWalk<'a, CrateId, Edge<'a>> for DotCrateGraph {
|
||||||
|
fn nodes(&'a self) -> dot::Nodes<'a, CrateId> {
|
||||||
|
self.0.iter().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> {
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.flat_map(|krate| self.0[krate].dependencies.iter().map(move |dep| (krate, dep)))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source(&'a self, edge: &Edge<'a>) -> CrateId {
|
||||||
|
edge.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target(&'a self, edge: &Edge<'a>) -> CrateId {
|
||||||
|
edge.1.crate_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> dot::Labeller<'a, CrateId, Edge<'a>> for DotCrateGraph {
|
||||||
|
fn graph_id(&'a self) -> Id<'a> {
|
||||||
|
Id::new("rust_analyzer_crate_graph").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_id(&'a self, n: &CrateId) -> Id<'a> {
|
||||||
|
let name = self.0[*n].display_name.as_ref().map_or("_missing_name_", |name| &*name);
|
||||||
|
Id::new(name).unwrap()
|
||||||
|
}
|
||||||
|
}
|
|
@ -117,6 +117,12 @@ pub(crate) fn handle_view_hir(
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn handle_view_crate_graph(snap: GlobalStateSnapshot, (): ()) -> Result<String> {
|
||||||
|
let _p = profile::span("handle_view_crate_graph");
|
||||||
|
let res = snap.analysis.view_crate_graph()??;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn handle_expand_macro(
|
pub(crate) fn handle_expand_macro(
|
||||||
snap: GlobalStateSnapshot,
|
snap: GlobalStateSnapshot,
|
||||||
params: lsp_ext::ExpandMacroParams,
|
params: lsp_ext::ExpandMacroParams,
|
||||||
|
|
|
@ -61,6 +61,14 @@ impl Request for ViewHir {
|
||||||
const METHOD: &'static str = "rust-analyzer/viewHir";
|
const METHOD: &'static str = "rust-analyzer/viewHir";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ViewCrateGraph {}
|
||||||
|
|
||||||
|
impl Request for ViewCrateGraph {
|
||||||
|
type Params = ();
|
||||||
|
type Result = String;
|
||||||
|
const METHOD: &'static str = "rust-analyzer/viewCrateGraph";
|
||||||
|
}
|
||||||
|
|
||||||
pub enum ExpandMacro {}
|
pub enum ExpandMacro {}
|
||||||
|
|
||||||
impl Request for ExpandMacro {
|
impl Request for ExpandMacro {
|
||||||
|
|
|
@ -513,6 +513,7 @@ impl GlobalState {
|
||||||
.on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
|
.on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
|
||||||
.on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
|
.on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
|
||||||
.on::<lsp_ext::ViewHir>(handlers::handle_view_hir)
|
.on::<lsp_ext::ViewHir>(handlers::handle_view_hir)
|
||||||
|
.on::<lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph)
|
||||||
.on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
|
.on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
|
||||||
.on::<lsp_ext::ParentModule>(handlers::handle_parent_module)
|
.on::<lsp_ext::ParentModule>(handlers::handle_parent_module)
|
||||||
.on::<lsp_ext::Runnables>(handlers::handle_runnables)
|
.on::<lsp_ext::Runnables>(handlers::handle_runnables)
|
||||||
|
|
|
@ -109,6 +109,11 @@
|
||||||
"title": "View Hir",
|
"title": "View Hir",
|
||||||
"category": "Rust Analyzer"
|
"category": "Rust Analyzer"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "rust-analyzer.viewCrateGraph",
|
||||||
|
"title": "View Crate Graph",
|
||||||
|
"category": "Rust Analyzer"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "rust-analyzer.expandMacro",
|
"command": "rust-analyzer.expandMacro",
|
||||||
"title": "Expand macro recursively",
|
"title": "Expand macro recursively",
|
||||||
|
|
|
@ -429,6 +429,14 @@ export function viewHir(ctx: Ctx): Cmd {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function viewCrateGraph(ctx: Ctx): Cmd {
|
||||||
|
return async () => {
|
||||||
|
const panel = vscode.window.createWebviewPanel("rust-analyzer.crate-graph", "rust-analyzer crate graph", vscode.ViewColumn.Two);
|
||||||
|
const svg = await ctx.client.sendRequest(ra.viewCrateGraph);
|
||||||
|
panel.webview.html = svg;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Opens the virtual file that will show the syntax tree
|
// Opens the virtual file that will show the syntax tree
|
||||||
//
|
//
|
||||||
// The contents of the file come from the `TextDocumentContentProvider`
|
// The contents of the file come from the `TextDocumentContentProvider`
|
||||||
|
|
|
@ -27,6 +27,8 @@ export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>("ru
|
||||||
|
|
||||||
export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>("rust-analyzer/viewHir");
|
export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>("rust-analyzer/viewHir");
|
||||||
|
|
||||||
|
export const viewCrateGraph = new lc.RequestType0<string, void>("rust-analyzer/viewCrateGraph");
|
||||||
|
|
||||||
export interface ExpandMacroParams {
|
export interface ExpandMacroParams {
|
||||||
textDocument: lc.TextDocumentIdentifier;
|
textDocument: lc.TextDocumentIdentifier;
|
||||||
position: lc.Position;
|
position: lc.Position;
|
||||||
|
|
|
@ -106,6 +106,7 @@ async function tryActivate(context: vscode.ExtensionContext) {
|
||||||
ctx.registerCommand('parentModule', commands.parentModule);
|
ctx.registerCommand('parentModule', commands.parentModule);
|
||||||
ctx.registerCommand('syntaxTree', commands.syntaxTree);
|
ctx.registerCommand('syntaxTree', commands.syntaxTree);
|
||||||
ctx.registerCommand('viewHir', commands.viewHir);
|
ctx.registerCommand('viewHir', commands.viewHir);
|
||||||
|
ctx.registerCommand('viewCrateGraph', commands.viewCrateGraph);
|
||||||
ctx.registerCommand('expandMacro', commands.expandMacro);
|
ctx.registerCommand('expandMacro', commands.expandMacro);
|
||||||
ctx.registerCommand('run', commands.run);
|
ctx.registerCommand('run', commands.run);
|
||||||
ctx.registerCommand('copyRunCommandLine', commands.copyRunCommandLine);
|
ctx.registerCommand('copyRunCommandLine', commands.copyRunCommandLine);
|
||||||
|
|
Loading…
Reference in a new issue