Introduction
I built a VS Code extension that lets you interactively visualize function calls.
It is not just a graph renderer; I focused especially on features that help you understand code structure efficiently.
https://marketplace.visualstudio.com/items?itemName=D-grid375.call-graph-navi
D-grid375
/
call-graph-navi
Visualize and explore call graphs interactively in VS Code
Call Graph Navi
Visualize function call structures as directional graphs (incoming/outgoing) to better understand your code’s structure.
Language-agnostic — works with any language that supports Call Hierarchy. (see Requirements)
Demo
Features
Bidirectional Call Graphs
Visualize call graphs in both directions:
- Outgoing Call Graph — Shows functions called by the selected function.
- Incoming Call Graph — Shows functions that call the selected function.
Focused View
Cut out the noise and focus on the call structure you care about.
- Hide individual files or functions by clicking the × icon.
- Right-click a node → "Show Path to Root" to display only the path from that node up to the root.
Jump to Definition
Click any function to jump straight to its definition.
PlantUML Export
Click the "Export PlantUML" button in the top toolbar to export the current graph as PlantUML.
Getting Started
- Open a source file in the…
There are already several VS Code extensions that can draw call graphs, but I could not find one that covered everything I wanted to do, so I built my own. At first it was a local extension just for myself, but since I had already made it, I decided to publish it.
The main features are listed below. If you would like to try it, you can install it from the Marketplace link above.
- Bidirectional Call Graph Visualization
- Hiding Noise Functions
- PlantUML Export
- Language-Independent Support
Main Features
Bidirectional Call Graph Visualization
There are two types of call graphs, and this extension can render both:
- A graph of functions that call a specific function: Incoming Call Graph
- A graph of functions called by a specific function: Outgoing Call Graph
I use Incoming more often, and I think that is probably the more common use case in general. Still, I sometimes want to see Outgoing as well, for example when I want a comprehensive view of a function's dependency structure, so I included both.
Example of rendering Incoming on the left and Outgoing on the right for the same function.
Hiding Noise Functions
This is personally the feature I wanted most. You can freely hide functions in the graph in the following ways:
- Hide a specific function
- Hide a specific file, which hides all functions in that file
- Extract only the path between the root function and any non-root function, and hide all other functions
When working with call graphs, the biggest bottleneck is that the visualization often contains too much information, and the essence gets buried. In other words, the graph also shows structure outside the area you care about, making it hard to visually grasp the structure you actually want to see.
In that situation, hiding noisy functions lets you focus on the part you care about. This is useful not only when you are trying to understand the structure yourself, but also when you want to share that understanding with someone else.
After rendering an Outgoing graph, when you want to see the structure from the root to the function in the red frame, right-click the function node and click "Show Path to Root".
Now the graph is much clearer. Information about hidden functions and files is shown in the upper right. From there, you can hide additional items individually, or use the "Unhide All Nodes" button to show all functions again.
PlantUML Export
This is personally the second feature I wanted most. The "Export PlantUML" button outputs the structure of the currently displayed graph as PlantUML text. This makes it possible to embed the graph in Markdown, so you can go from understanding the structure to reusing it directly in a design document.
Of course, if you have applied the function-hiding feature described above, the exported PlantUML reflects the graph after that filtering.
Example of exporting the displayed graph to PlantUML, pasting it into Markdown, and rendering it. Details such as the left/right layout may change slightly, but that is simply how PlantUML works, so there is no need to worry about it. The structure itself matches exactly.
Language-Independent Support
This extension gets the call hierarchy information emitted by an LSP from VS Code and renders it as a graph. Because of that, it can be used with any language as long as an LSP is installed and can provide call hierarchy information. In other words, it should basically support all major languages.
Examples of LSPs: ms-vscode.cpptools, clangd, rust-analyzer, Pylance, gopls, etc.
Jumping to Functions
You can jump to the function definition in the source code by clicking a function in the graph.
Search
You can search for functions rendered in the graph.
Enter text in the search bar in the upper right, and matching functions are highlighted in yellow and centered.
Demo
The demo below shows the following operations:
- Render an Incoming Call Graph, with
GPIO_get_inputas the root function - Jump to a function definition
- Extract the path between the root function and another function,
tetris_receive_game_restart_input - Export PlantUML, paste it into Markdown, and render it
Design Overview
I will also briefly touch on the design.
The main language used is TypeScript. The component diagram is shown below.
When a graph-rendering command is executed in the VS Code editor, the Command Entry in the Extension Host receives it and starts processing. The Command Entry uses the Call Graph Provider to recursively traverse VS Code's Call Hierarchy API from the root function and collect the call relationships. The raw data is then cleaned up and transformed into pure graph-structure data containing only nodes, edges, and file groups: CallGraphData.
Next, the Webview Panel Manager creates a Webview for displaying the graph and passes the CallGraphData described above to it. The Call Graph UI on the Webview side receives that data, passes it to the external library dagre to calculate the graph layout, and renders the result into the DOM as SVG elements. Incidentally, operations triggered by user commands on the graph screen, such as jumping to a function or exporting PlantUML, are outside the responsibility of a simple drawing update, so they call back into the Extension Host to be handled there.
Future Improvements
Currently, the entire graph is rendered at once.
I would also like to support an approach where the graph starts from the root and can be expanded incrementally as needed.
Also, the current layout is vertical only, but I would like to add a horizontal layout as well. Layout preference likely differs from person to person, and a horizontal layout may make some graphs more compact and easier to read. Personally, I prefer the vertical layout.
I plan to continue improving the extension as I find more things while using it.
Closing
This extension originally started as something I built for myself, but now that I have published it, I naturally want to keep its quality high. If you try it and have feedback or suggestions for improvement, please feel free to contact me, either in the comments on this article or through GitHub Issues.
Thank you for reading to the end.










Top comments (0)