Skip to content

Commit 9993ba5

Browse files
Merge pull request #32 from RohanAdwankar/codemaps
Codemaps
2 parents d75817e + ba4e2d6 commit 9993ba5

22 files changed

+2854
-78
lines changed

Cargo.lock

Lines changed: 799 additions & 40 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ clap = { version = "4.5", features = ["derive"] }
3232
axum = { version = "0.7", features = ["json"], optional = true }
3333
dialoguer = "0.11"
3434
serde = { version = "1", features = ["derive"] }
35-
serde_json = "1"
35+
serde_json = "1.0"
36+
thiserror = "1.0"
37+
walkdir = "2.4"
38+
directories = "5.0"
39+
3640
tokio = { version = "1", features = [
3741
"macros",
3842
"rt-multi-thread",
@@ -45,19 +49,15 @@ tower = { version = "0.5", optional = true }
4549
resvg = { version = "0.43", features = ["text"] }
4650
tiny-skia = { version = "0.11", features = ["png"], default-features = false }
4751
base64 = "0.22"
52+
reqwest = { version = "0.11", features = ["json"] }
53+
regex = "1.12.2"
4854

49-
[features]
50-
default = ["server"]
51-
server = ["axum", "tokio", "tower-http", "tower"]
55+
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
56+
assert_cmd = "2.1.1"
5257

5358
[dev-dependencies]
5459
wasm-bindgen-test = "0.3"
5560

56-
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
57-
assert_cmd = { version = "2", default-features = false }
58-
predicates = "3"
59-
tempfile = "3"
60-
61-
[profile.release]
62-
codegen-units = 1
63-
lto = true
61+
[features]
62+
default = ["server"]
63+
server = ["axum", "tokio", "tower-http", "tower"]

README.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ https://github.com/user-attachments/assets/de5222bb-9b65-43cf-a35b-5613d06343e8
44
## Overview
55

66
The goal of `oxdraw` is to make it easy to create and maintain high-quality diagrams using a declarative and reproducible syntax.
7-
Charts are written in [Mermaid](https://mermaid.js.org/) syntax, while a web interface allows users to fine-tune positions connector paths, colors, and other styling components. Whenever a diagram is tweaked visually, the structural changes are persisted back to the source file as declarative code so that everything remains deterministic and versionable.
7+
Charts are written in [Mermaid](https://mermaid.js.org/) syntax, while a web interface allows users to fine-tune positions, connector paths, colors, and other styling components. Whenever a diagram is tweaked visually, the structural changes are persisted back to the source file as declarative code so that everything remains deterministic and versionable.
8+
Aside from the normal diagrams, oxdraw can also embed images directly into the diagrams and view codemaps of codebase where nodes are linked to codesegments.
89
The changes are saved as comments in the mermaid file so it remains compatible with other Mermaid tools.
9-
The repo is composed of the Rust CLI to compile `.mmd` files into images and the React based web interface to editing the files.
10+
The repo is composed of the Rust CLI to compile `.mmd` files into images, a React based web interface to editing the files, and some AI and static analysis algorithm options for automatic generation of code maps.
1011

1112
## Vision
1213

@@ -32,6 +33,17 @@ oxdraw --input flow.mmd
3233
oxdraw --input flow.mmd --edit
3334
```
3435

36+
### Have AI generate a codemap for the repo you're in
37+
This will also launch the interactive viewer mapping the nodes to files in the repo. You can refer to [ai.md](docs/ai.md) for free resources on setting up AI access
38+
39+
https://github.com/user-attachments/assets/49891bec-7bcd-4af4-a357-d59708bb1812
40+
41+
```bash
42+
oxdraw --code-map ./ --gemini YOUR_API_KEY
43+
# or if you don't have AI access set up, you can use this simple static analysis based code map generator to get an idea of the feature:
44+
oxdraw --code-map ./src/diagram.rs --no-ai --output test.png
45+
```
46+
3547
## Features
3648

3749
### CLI Flags
@@ -48,6 +60,12 @@ oxdraw --input flow.mmd --edit
4860
| `-b, --background-color <COLOR>` | Background fill passed to the renderer (currently SVG only). Applies to both one-off renders and the editor preview. |
4961
| `-q, --quiet` | Suppress informational stdout such as the success message after rendering to disk. |
5062
| `-n, --new` | Create new mermaid file and serves for editing. |
63+
| `--code-map <PATH>` | Generate a code map from the given codebase path. |
64+
| `--api-key <KEY>` | API Key for the LLM (optional, defaults to environment variable if not set). |
65+
| `--model <MODEL>` | Model to use for code map generation. |
66+
| `--api-url <URL>` | API URL for the LLM. |
67+
| `--regen` | Force regeneration of the code map even if a cache exists. |
68+
| `--prompt <PROMPT>` | Custom prompt to append to the LLM instructions. |
5169

5270
### Frontend Features
5371

@@ -70,7 +88,7 @@ oxdraw --input flow.mmd --edit
7088
- The source panel mirrors the Mermaid file, auto-saves after short idle periods, and surfaces pending/saving/error states alongside the current selection.
7189
- Status text in the top toolbar signals loading, saving, and the currently edited file path.
7290

73-
## The Diagram Algorithm
91+
### The Diagram Algorithm
7492

7593
https://github.com/user-attachments/assets/4430147a-83d8-4d83-aca6-7beec197c0e3
7694

build.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use std::env;
2-
use std::path::Path;
3-
41
fn main() {
52
#[cfg(feature = "server")]
63
{
4+
use std::env;
5+
use std::path::Path;
6+
77
println!("cargo:rerun-if-changed=frontend/out");
88

99
let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR missing");

docs/ai.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
One example of a way to get LLM Access for free is Google AI Studio.
2+
Here is the steps to set it up:
3+
1. Go to [Google AI Studio](https://aistudio.google.com/api-keys) and sign in with your Google account.
4+
2. Click on "Create API Key" and "Create Project" and copy the generated API key (the names don't matter).
5+
3. Paste the API key into the `oxdraw --code-map ./ --gemini YOUR_API_KEY` flag when running the code map generation command.
6+
7+
This process is fairly straightforward and doesn't require any billing information.
8+
9+
The other default option (which [I used](https://github.com/RohanAdwankar/cgpu?tab=readme-ov-file#serve-gemini-for-free-as-openai-compatible-api) during development) is to serve local inference on this url http://localhost:8080/v1/responses
10+
11+
The response format should be compatible with OpenAI's responses API.
12+
13+
For an explanation of how the AI codemap generation works check out the [codemap!](docs/ai_codemap_generation.mmd)

docs/codemap_generation.mmd

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
graph TD
2+
Start[generate_code_map] --> CheckCache{Cached?}
3+
CheckCache -- Yes --> ReturnCached[Return Cached Map]
4+
CheckCache -- No --> Scan[Scan Codebase]
5+
Scan --> BuildPrompt[Build Initial Prompt]
6+
BuildPrompt --> LoopStart((Loop Start))
7+
LoopStart --> CheckAttempts{Max Attempts?}
8+
CheckAttempts -- Yes --> Error[Return Error]
9+
CheckAttempts -- No --> CallLLM[Call LLM API]
10+
CallLLM --> Parse{Parse JSON?}
11+
Parse -- Success --> Validate{Validate Map?}
12+
Parse -- Failure --> UpdatePrompt1[Append Parse Error]
13+
UpdatePrompt1 --> LoopStart
14+
Validate -- Valid --> SaveCache[Save to Cache]
15+
Validate -- Invalid --> UpdatePrompt2[Append Validation Error]
16+
UpdatePrompt2 --> LoopStart
17+
SaveCache --> ReturnNew[Return New Map]
18+
19+
%% OXDRAW CODE Start src/codemap.rs def:generate_code_map
20+
%% OXDRAW CODE CheckCache src/codemap.rs line:69-80
21+
%% OXDRAW CODE Scan src/codemap.rs def:scan_codebase
22+
%% OXDRAW CODE BuildPrompt src/codemap.rs line:106-144
23+
%% OXDRAW CODE LoopStart src/codemap.rs line:172-173
24+
%% OXDRAW CODE Error src/codemap.rs line:175-175
25+
%% OXDRAW CODE CheckAttempts src/codemap.rs line:169-171
26+
%% OXDRAW CODE CallLLM src/codemap.rs line:177-199
27+
%% OXDRAW CODE Parse src/codemap.rs line:206-259
28+
%% OXDRAW CODE Validate src/codemap.rs def:validate_response
29+
%% OXDRAW CODE SaveCache src/codemap.rs line:279-287
30+
%% OXDRAW CODE UpdatePrompt1 src/codemap.rs line:256-257
31+
%% OXDRAW CODE UpdatePrompt2 src/codemap.rs line:294-297
32+
%% OXDRAW CODE ReturnCached src/codemap.rs line:77-77
33+
%% OXDRAW CODE ReturnNew src/codemap.rs line:291-291
34+
%% OXDRAW META path: commit:93e6d002b6aaec11cd30e7bd362e12047534db2c diff_hash:13646096770106105413

frontend/app/globals.css

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ body > div:first-of-type {
3333
.app {
3434
display: flex;
3535
flex-direction: column;
36-
min-height: 100vh;
36+
height: 100vh;
3737
background: linear-gradient(180deg, #edf2f7 0%, #e2e8f0 100%);
38+
overflow: hidden;
3839
}
3940

4041
.toolbar {
@@ -89,6 +90,7 @@ body > div:first-of-type {
8990
background: linear-gradient(180deg, #edf2f7 0%, #e2e8f0 100%);
9091
border-top: 1px solid rgba(15, 23, 42, 0.08);
9192
gap: 0;
93+
overflow: hidden;
9294
}
9395

9496
.diagram-wrapper {
@@ -553,6 +555,12 @@ body > div:first-of-type {
553555
outline: none;
554556
}
555557

558+
.context-menu-separator {
559+
height: 1px;
560+
background: rgba(248, 250, 252, 0.15);
561+
margin: 0.25rem 0;
562+
}
563+
556564
.alignment-guide {
557565
stroke: rgba(56, 178, 172, 0.85);
558566
stroke-width: 1.5;
@@ -563,3 +571,101 @@ body > div:first-of-type {
563571
.alignment-guide-center {
564572
stroke: rgba(244, 114, 182, 0.85);
565573
}
574+
575+
.code-panel {
576+
width: 500px;
577+
max-width: 50%;
578+
display: flex;
579+
flex-direction: column;
580+
background: rgba(255, 255, 255, 0.95);
581+
backdrop-filter: blur(6px);
582+
border-left: 1px solid rgba(15, 23, 42, 0.08);
583+
box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.04);
584+
height: 100%;
585+
overflow: hidden;
586+
}
587+
588+
.code-panel.empty {
589+
align-items: center;
590+
justify-content: center;
591+
}
592+
593+
.code-panel .panel-header {
594+
padding: 0.9rem 1.1rem 0.4rem;
595+
display: flex;
596+
align-items: center;
597+
justify-content: space-between;
598+
gap: 0.35rem;
599+
border-bottom: 1px solid rgba(15, 23, 42, 0.06);
600+
}
601+
602+
.code-panel .panel-title {
603+
font-size: 0.85rem;
604+
text-transform: uppercase;
605+
letter-spacing: 0.08em;
606+
color: #64748b;
607+
font-weight: 700;
608+
}
609+
610+
.code-panel .panel-path {
611+
font-size: 0.9rem;
612+
color: #1f2937;
613+
font-weight: 600;
614+
word-break: break-all;
615+
flex: 1;
616+
margin-left: 1rem;
617+
}
618+
619+
.code-panel .close-button {
620+
background: none;
621+
border: none;
622+
font-size: 1.5rem;
623+
line-height: 1;
624+
cursor: pointer;
625+
color: #64748b;
626+
padding: 0;
627+
}
628+
629+
.code-panel .close-button:hover {
630+
color: #1f2937;
631+
}
632+
633+
.code-content {
634+
flex: 1;
635+
overflow: auto;
636+
padding: 1rem;
637+
background: #f8fafc;
638+
color: #1f2937;
639+
}
640+
641+
.code-content pre {
642+
margin: 0;
643+
}
644+
645+
.code-content code {
646+
font-family: "JetBrains Mono", "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
647+
font-size: 0.85rem;
648+
line-height: 1.5;
649+
display: block;
650+
}
651+
652+
.code-line {
653+
display: flex;
654+
gap: 1rem;
655+
}
656+
657+
.code-line.highlighted {
658+
background-color: rgba(253, 230, 138, 0.5);
659+
}
660+
661+
.line-number {
662+
color: #94a3b8;
663+
user-select: none;
664+
text-align: right;
665+
min-width: 2rem;
666+
}
667+
668+
.line-text {
669+
white-space: pre-wrap;
670+
word-break: break-all;
671+
}

0 commit comments

Comments
 (0)