codesynapt 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/LICENSE +686 -0
- package/LICENSES.md +141 -0
- package/README.md +331 -0
- package/electron/main.cjs +2849 -0
- package/electron/plugin-loader.cjs +184 -0
- package/electron/preload.cjs +108 -0
- package/package.json +216 -0
- package/packages/core/bin/codesynapt-mcp.cjs +611 -0
- package/packages/core/bin/codesynapt.cjs +1933 -0
- package/packages/core/legacy.js +300 -0
- package/packages/core/lib/control-server.cjs +1539 -0
- package/packages/core/lib/embedding.cjs +89 -0
- package/packages/core/lib/logger.cjs +63 -0
- package/packages/core/lib/search-cache.cjs +140 -0
- package/packages/core/lib/search-worker.cjs +255 -0
- package/packages/core/lib/search.cjs +211 -0
- package/packages/core/lib/symbol-graph.cjs +402 -0
- package/packages/core/lib/symbol-parser-js.cjs +542 -0
- package/packages/core/lib/symbol-parser-misc.cjs +394 -0
- package/packages/core/lib/symbol-parser-py.cjs +215 -0
- package/packages/core/lib/symbol-parser-treesitter.cjs +658 -0
- package/packages/core/lib/symbol-parser-tsc.cjs +332 -0
- package/packages/core/monorepo.js +310 -0
- package/packages/core/parser.js +2234 -0
- package/packages/core/scanner.js +623 -0
- package/plugin-api/LICENSE +21 -0
- package/plugin-api/README.md +114 -0
- package/plugin-api/docs/01-getting-started.md +197 -0
- package/plugin-api/docs/02-concepts.md +269 -0
- package/plugin-api/docs/api-reference.md +463 -0
- package/plugin-api/docs/troubleshooting.md +332 -0
- package/plugin-api/docs/types/exporter.md +377 -0
- package/plugin-api/docs/types/theme.md +312 -0
- package/plugin-api/examples/hello-world-plugin/README.md +70 -0
- package/plugin-api/examples/hello-world-plugin/main.js +36 -0
- package/plugin-api/examples/hello-world-plugin/manifest.json +12 -0
- package/plugin-api/examples/mermaid-exporter/README.md +125 -0
- package/plugin-api/examples/mermaid-exporter/main.js +58 -0
- package/plugin-api/examples/mermaid-exporter/manifest.json +12 -0
- package/plugin-api/examples/rust-parser/README.md +71 -0
- package/plugin-api/examples/rust-parser/main.js +123 -0
- package/plugin-api/examples/rust-parser/manifest.json +12 -0
- package/plugin-api/examples/sunset-theme/README.md +95 -0
- package/plugin-api/examples/sunset-theme/manifest.json +12 -0
- package/plugin-api/examples/sunset-theme/theme.css +31 -0
- package/plugin-api/package.json +20 -0
- package/plugin-api/types.d.ts +395 -0
- package/public/app.js +6837 -0
- package/public/backend.js +285 -0
- package/public/index.html +647 -0
- package/public/plugin-host.js +321 -0
- package/public/style.css +4359 -0
- package/public/vendor/three.module.js +53044 -0
- package/scripts/competitor-watch.mjs +144 -0
- package/scripts/copy-vendor.js +21 -0
- package/scripts/download-bundled-node.cjs +53 -0
- package/scripts/fuses-after-pack.cjs +34 -0
- package/scripts/license-check.js +119 -0
- package/scripts/perf-test.js +200 -0
- package/server.js +132 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
# Theme plugin
|
|
2
|
+
|
|
3
|
+
A theme plugin is the simplest plugin type — just CSS. You override
|
|
4
|
+
the app's CSS variables under a `body[data-theme="your-id"]` selector,
|
|
5
|
+
and filegraph3d picks it up automatically.
|
|
6
|
+
|
|
7
|
+
- [Minimal example](#minimal-example)
|
|
8
|
+
- [Every variable you can override](#every-variable-you-can-override)
|
|
9
|
+
- [Palette construction](#palette-construction)
|
|
10
|
+
- [Decorations: corner brackets and accents](#decorations-corner-brackets-and-accents)
|
|
11
|
+
- [Dark vs light themes](#dark-vs-light-themes)
|
|
12
|
+
- [Studying built-in themes](#studying-built-in-themes)
|
|
13
|
+
- [Common mistakes](#common-mistakes)
|
|
14
|
+
|
|
15
|
+
## Minimal example
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
plugins/my-theme/
|
|
19
|
+
├── manifest.json
|
|
20
|
+
└── theme.css
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**`manifest.json`:**
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"id": "my-theme",
|
|
28
|
+
"name": "My Theme",
|
|
29
|
+
"version": "1.0.0",
|
|
30
|
+
"type": "theme",
|
|
31
|
+
"main": "theme.css",
|
|
32
|
+
"minAppVersion": "0.10.0",
|
|
33
|
+
"license": "MIT"
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**`theme.css`:**
|
|
38
|
+
|
|
39
|
+
```css
|
|
40
|
+
body[data-theme="my-theme"] {
|
|
41
|
+
--bg: #1A1A1A;
|
|
42
|
+
--fg: #F0F0F0;
|
|
43
|
+
--accent: #FF8800;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
That's a working theme. It won't look great because you've only set 3
|
|
48
|
+
of ~30 variables, but it'll load. Read on for the rest.
|
|
49
|
+
|
|
50
|
+
## Every variable you can override
|
|
51
|
+
|
|
52
|
+
filegraph3d's UI is parameterized by ~30 CSS custom properties. The
|
|
53
|
+
full list:
|
|
54
|
+
|
|
55
|
+
### Backgrounds
|
|
56
|
+
|
|
57
|
+
| Variable | Used by | Notes |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| `--bg` | Body background | The main canvas background. Pure color, no alpha. |
|
|
60
|
+
| `--bg-deep` | Very deep accents | Slightly darker than `--bg`. |
|
|
61
|
+
| `--bg-elev` | Raised elements | Tooltips, dropdowns. Use `rgba(...)` for translucency. |
|
|
62
|
+
| `--bg-glass` | All floating panels | The "frosted glass" panel background. Should be `rgba()` with ~0.85 alpha. |
|
|
63
|
+
| `--bg-solid` | Where solid is required | Settings panel sections, etc. |
|
|
64
|
+
|
|
65
|
+
### Borders
|
|
66
|
+
|
|
67
|
+
| Variable | Used by | Notes |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `--border` | Default panel borders | Should be visible but not loud. |
|
|
70
|
+
| `--border-hot` | Active / focused borders | Brighter version of `--border`. |
|
|
71
|
+
| `--border-edge` | Subtle dividers, separators | Nearly invisible (alpha ~0.05). |
|
|
72
|
+
|
|
73
|
+
### Foregrounds
|
|
74
|
+
|
|
75
|
+
| Variable | Used by | Notes |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `--fg` | Primary text | Should pass contrast against `--bg`. |
|
|
78
|
+
| `--fg-dim` | Secondary text | Labels, less important info. |
|
|
79
|
+
| `--fg-mute` | Tertiary text | Captions, kicker text. |
|
|
80
|
+
| `--fg-faint` | Quaternary text | Disabled, divider labels. |
|
|
81
|
+
|
|
82
|
+
### Accents (semantic colors)
|
|
83
|
+
|
|
84
|
+
| Variable | Semantic role | Where |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| `--accent` | Default information / focus | Buttons, highlights, brand dot, search focus border |
|
|
87
|
+
| `--accent-warm` | Active set / starred | Star buttons, pipelines panel, active markings |
|
|
88
|
+
| `--accent-pink` | Warning / danger | Delete buttons, error states |
|
|
89
|
+
| `--accent-cool` | Secondary focus | Focus ripples (less common) |
|
|
90
|
+
| `--danger` | Errors | Validation failures, destructive confirmation |
|
|
91
|
+
|
|
92
|
+
### Typography
|
|
93
|
+
|
|
94
|
+
| Variable | Used by |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `--font-mono` | Monospace text (code, data, default body) |
|
|
97
|
+
| `--font-display` | Display text (logo, headers) |
|
|
98
|
+
|
|
99
|
+
The defaults expect `'JetBrains Mono'` to be available, with fallbacks
|
|
100
|
+
to `'SF Mono'`, `ui-monospace`, `Menlo`. You can change to any font
|
|
101
|
+
stack you like; the user must have it installed.
|
|
102
|
+
|
|
103
|
+
### Layout
|
|
104
|
+
|
|
105
|
+
| Variable | Used by |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `--radius` | Border-radius for panels, buttons | `0` = brutalist, `4-6px` = friendly, `12px+` = bubbly |
|
|
108
|
+
| `--space-1` through `--space-6` | 4px grid spacing | Rarely needs override |
|
|
109
|
+
|
|
110
|
+
### Motion & decoration flags
|
|
111
|
+
|
|
112
|
+
| Variable | What it controls |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `--decoration` | `1` to show corner brackets on panels, `0` to hide |
|
|
115
|
+
| `--grain` | Opacity of background noise overlay (`0` to `0.05`) |
|
|
116
|
+
| `--motion-scale` | Multiplier for ambient animations (`0` = none, `1` = default, `1.5` = more) |
|
|
117
|
+
|
|
118
|
+
### Easing
|
|
119
|
+
|
|
120
|
+
| Variable | Used by |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `--ease-out` | Smooth ease-out for hover transitions |
|
|
123
|
+
| `--ease-snap` | Snappy ease for selection changes |
|
|
124
|
+
|
|
125
|
+
## Palette construction
|
|
126
|
+
|
|
127
|
+
A good theme needs **5 colors** at minimum:
|
|
128
|
+
|
|
129
|
+
1. **Background** (`--bg`)
|
|
130
|
+
2. **Foreground** (`--fg`)
|
|
131
|
+
3. **Three accents** (`--accent`, `--accent-warm`, `--accent-pink`)
|
|
132
|
+
|
|
133
|
+
### Step-by-step
|
|
134
|
+
|
|
135
|
+
**1. Pick a background.** This sets the mood:
|
|
136
|
+
- Near-black (`#0A0A0A`) — neutral terminal feel
|
|
137
|
+
- Tinted dark (`#1A1B26` Tokyo Night, `#2A1810` warm) — character
|
|
138
|
+
- True white (`#FAFAFA`) — light mode
|
|
139
|
+
|
|
140
|
+
**2. Pick a foreground that contrasts.**
|
|
141
|
+
- For dark bg: `#E0E0E0` to `#F5F5F5`
|
|
142
|
+
- For light bg: `#1A1A1A` to `#333333`
|
|
143
|
+
- Aim for **WCAG AA** contrast (4.5:1 minimum for normal text).
|
|
144
|
+
|
|
145
|
+
**3. Pick `--accent`.** This is the main signal color. Used everywhere
|
|
146
|
+
you want to draw the eye. Choose something that:
|
|
147
|
+
- Stands out against `--bg`
|
|
148
|
+
- Doesn't fight `--fg` (don't pick a similar hue)
|
|
149
|
+
|
|
150
|
+
**4. Pick `--accent-warm` and `--accent-pink`.** These are semantic:
|
|
151
|
+
- `--accent-warm` = active set, starred (golds, oranges work great)
|
|
152
|
+
- `--accent-pink` = danger, deletion (reds, hot pinks)
|
|
153
|
+
|
|
154
|
+
The three accents should be **distinguishable at a glance**. If they're
|
|
155
|
+
all bluish, users can't tell what each one means.
|
|
156
|
+
|
|
157
|
+
**5. Generate the supporting colors.**
|
|
158
|
+
|
|
159
|
+
Common pattern (in HSL):
|
|
160
|
+
```
|
|
161
|
+
--fg: hsl(H, S, 95%)
|
|
162
|
+
--fg-dim: hsl(H, S*0.8, 75%)
|
|
163
|
+
--fg-mute: hsl(H, S*0.5, 50%)
|
|
164
|
+
--fg-faint: hsl(H, S*0.3, 35%)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Where `H, S` are the hue/saturation of the base foreground.
|
|
168
|
+
|
|
169
|
+
For borders, use the accent color at low alpha:
|
|
170
|
+
```
|
|
171
|
+
--border: rgba(R, G, B, 0.16) /* visible */
|
|
172
|
+
--border-hot: rgba(R, G, B, 0.55) /* active */
|
|
173
|
+
--border-edge: rgba(R, G, B, 0.06) /* nearly invisible */
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Where `R, G, B` is your accent color's RGB.
|
|
177
|
+
|
|
178
|
+
## Decorations: corner brackets and accents
|
|
179
|
+
|
|
180
|
+
filegraph3d's built-in themes have **corner brackets** on panels —
|
|
181
|
+
small `┌` `┐` `└` `┘` marks that frame each panel. These are part of
|
|
182
|
+
the "Observatory" aesthetic.
|
|
183
|
+
|
|
184
|
+
You control them with `--decoration`:
|
|
185
|
+
|
|
186
|
+
```css
|
|
187
|
+
body[data-theme="my-clean-theme"] {
|
|
188
|
+
--decoration: 0; /* hide all corner brackets */
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```css
|
|
193
|
+
body[data-theme="my-bold-theme"] {
|
|
194
|
+
--decoration: 1; /* show corner brackets (default) */
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
When `--decoration: 0`:
|
|
199
|
+
- Corner brackets disappear
|
|
200
|
+
- ASCII dividers in welcome screen hide
|
|
201
|
+
- `[ ]` brackets around the brand label hide
|
|
202
|
+
|
|
203
|
+
This single switch controls roughly two dozen decorative elements.
|
|
204
|
+
|
|
205
|
+
## Dark vs light themes
|
|
206
|
+
|
|
207
|
+
Light themes need a few extra tweaks. Set everything as usual, then:
|
|
208
|
+
|
|
209
|
+
```css
|
|
210
|
+
body[data-theme="my-light-theme"] {
|
|
211
|
+
--bg: #FAFAFA;
|
|
212
|
+
--fg: #1A1A1A;
|
|
213
|
+
--accent: #0066CC;
|
|
214
|
+
--accent-warm: #B87000;
|
|
215
|
+
--accent-pink: #CC2233;
|
|
216
|
+
|
|
217
|
+
/* Soften the grain overlay (it looks bad on white) */
|
|
218
|
+
--grain: 0;
|
|
219
|
+
|
|
220
|
+
/* Borders need to be dark on light bg */
|
|
221
|
+
--border: rgba(0, 0, 0, 0.08);
|
|
222
|
+
--border-hot: rgba(0, 0, 0, 0.3);
|
|
223
|
+
--border-edge: rgba(0, 0, 0, 0.04);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/* Hide the grain overlay specifically for this theme */
|
|
227
|
+
body[data-theme="my-light-theme"]::before {
|
|
228
|
+
opacity: 0 !important;
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
The grain overlay is set on `body::before` and uses
|
|
233
|
+
`mix-blend-mode: overlay`, which looks fine on dark but adds ugly
|
|
234
|
+
specks on light. Force it off.
|
|
235
|
+
|
|
236
|
+
## Studying built-in themes
|
|
237
|
+
|
|
238
|
+
The seven built-in themes are great references. They live in the
|
|
239
|
+
app's `public/style.css`. Each is implemented as a `body[data-theme="..."]`
|
|
240
|
+
block:
|
|
241
|
+
|
|
242
|
+
- `observatory` — the default, brutalist + corner brackets
|
|
243
|
+
- `minimal` — Obsidian-style, soft and quiet
|
|
244
|
+
- `terminal` — Linear-style, monochrome
|
|
245
|
+
- `maximal` — bold gradients
|
|
246
|
+
- `carbon` — CRT phosphor green
|
|
247
|
+
- `mono` — Tokyo Night warmth
|
|
248
|
+
- `daylight` — light mode
|
|
249
|
+
|
|
250
|
+
Open `style.css` and grep for `body[data-theme=` to find each one.
|
|
251
|
+
Copy the parts you like.
|
|
252
|
+
|
|
253
|
+
## Common mistakes
|
|
254
|
+
|
|
255
|
+
### "My theme doesn't show up"
|
|
256
|
+
|
|
257
|
+
- Did you **fully quit** the app (Cmd/Ctrl+Q) and reopen? Themes are
|
|
258
|
+
injected at startup.
|
|
259
|
+
- Is `manifest.json` valid JSON? Try `jsonlint.com`.
|
|
260
|
+
- Is the folder name and `manifest.id` matching? They don't have to be
|
|
261
|
+
identical, but the `id` determines what selector you need (it's
|
|
262
|
+
`body[data-theme="<id>"]`, not the folder name).
|
|
263
|
+
|
|
264
|
+
### "Colors look right but layout is weird"
|
|
265
|
+
|
|
266
|
+
You probably forgot `--decoration` or `--radius`. Set them explicitly
|
|
267
|
+
even if you want defaults — relying on inheritance gives unpredictable
|
|
268
|
+
results when users switch from another theme.
|
|
269
|
+
|
|
270
|
+
### "It looks fine in my theme but broken in others"
|
|
271
|
+
|
|
272
|
+
Don't define your CSS variables outside the `body[data-theme="..."]`
|
|
273
|
+
selector. If you do, they leak into other themes. Bad:
|
|
274
|
+
|
|
275
|
+
```css
|
|
276
|
+
/* ❌ leaks to all themes */
|
|
277
|
+
:root {
|
|
278
|
+
--accent: #FF0000;
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Good:
|
|
283
|
+
|
|
284
|
+
```css
|
|
285
|
+
/* ✅ scoped to this theme only */
|
|
286
|
+
body[data-theme="my-theme"] {
|
|
287
|
+
--accent: #FF0000;
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### "Light mode text is unreadable"
|
|
292
|
+
|
|
293
|
+
Check your contrast ratios. On light backgrounds:
|
|
294
|
+
- `--fg` should be very dark (`#1A1A1A` to `#333`)
|
|
295
|
+
- `--fg-mute` should still be readable (`#666` minimum)
|
|
296
|
+
|
|
297
|
+
Use a contrast checker like `webaim.org/resources/contrastchecker/`.
|
|
298
|
+
|
|
299
|
+
### "My theme breaks the file tree colors"
|
|
300
|
+
|
|
301
|
+
The colored squares next to filenames come from the **app's** file-type
|
|
302
|
+
palette, not your theme. They're hardcoded by extension (`.js` = yellow,
|
|
303
|
+
`.tsx` = blue, etc). If you want a different file-type palette, that's
|
|
304
|
+
a different feature — currently not user-overridable.
|
|
305
|
+
|
|
306
|
+
## Next steps
|
|
307
|
+
|
|
308
|
+
- Try the [sunset-theme example](../../examples/sunset-theme/) — a
|
|
309
|
+
warm coral-orange theme you can copy and modify.
|
|
310
|
+
- Read the [exporter guide](./exporter.md) for your next plugin type.
|
|
311
|
+
- Or jump to the [API reference](../api-reference.md) for the full
|
|
312
|
+
surface.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# hello-world-plugin
|
|
2
|
+
|
|
3
|
+
A minimal action plugin that demonstrates:
|
|
4
|
+
|
|
5
|
+
- Registering a context-menu item
|
|
6
|
+
- Subscribing to selection events
|
|
7
|
+
- Showing toast notifications
|
|
8
|
+
- Using `ctx.log` for debugging
|
|
9
|
+
|
|
10
|
+
## What it does
|
|
11
|
+
|
|
12
|
+
When installed:
|
|
13
|
+
|
|
14
|
+
1. **Right-click any node** in the graph — a "Hello from plugin" item
|
|
15
|
+
appears in the menu. Click it to see a toast.
|
|
16
|
+
|
|
17
|
+
2. **Click any node** — a toast pops up with that node's basic stats
|
|
18
|
+
(incoming/outgoing edge counts).
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
Copy this folder into your filegraph3d plugins directory:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
macOS: ~/Library/Application Support/FileGraph 3D/plugins/
|
|
26
|
+
Windows: %APPDATA%\FileGraph 3D\plugins\
|
|
27
|
+
Linux: ~/.config/FileGraph 3D/plugins/
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Quit and reopen filegraph3d. Open any folder. Click or right-click
|
|
31
|
+
nodes.
|
|
32
|
+
|
|
33
|
+
## Files
|
|
34
|
+
|
|
35
|
+
- **`manifest.json`** — declares the plugin as type `action` with no
|
|
36
|
+
required permissions (read-graph is implicit, and the toast/log
|
|
37
|
+
helpers don't need permissions).
|
|
38
|
+
|
|
39
|
+
- **`main.js`** — the entry point. Subscribes to events, registers a
|
|
40
|
+
context-menu item, and stores its unsubscribe function so
|
|
41
|
+
`deactivate()` can clean up.
|
|
42
|
+
|
|
43
|
+
## What to look at
|
|
44
|
+
|
|
45
|
+
- The `default export` shape — every code plugin has an object with
|
|
46
|
+
at least an `activate(ctx)` function.
|
|
47
|
+
|
|
48
|
+
- `ctx.events.on(...)` returns an unsubscribe function. The plugin
|
|
49
|
+
stores it as `this._unsub` and calls it from `deactivate()`.
|
|
50
|
+
|
|
51
|
+
- `ctx.ui.registerContextMenuItem(...)` doesn't return a useful handle
|
|
52
|
+
for the plugin to track because the plugin host handles cleanup
|
|
53
|
+
automatically when the plugin unloads.
|
|
54
|
+
|
|
55
|
+
- `ctx.toast(...)` automatically prefixes messages with `[hello-world]`
|
|
56
|
+
so the user knows where they came from.
|
|
57
|
+
|
|
58
|
+
## What to try next
|
|
59
|
+
|
|
60
|
+
Modify `main.js` to:
|
|
61
|
+
|
|
62
|
+
- Show different info in the toast (e.g. file extension, size in KB)
|
|
63
|
+
- Filter the context menu to only appear on `.js` files (use the
|
|
64
|
+
`enabled` callback)
|
|
65
|
+
- Subscribe to a different event (`focus:changed`, `snapshot:applied`)
|
|
66
|
+
- Persist a counter in `ctx.storage` ("you've clicked X files")
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
MIT.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Minimal plugin example.
|
|
2
|
+
// Listens for node selections and shows a toast with stats.
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
activate(ctx) {
|
|
6
|
+
ctx.log('Hello World plugin loaded')
|
|
7
|
+
|
|
8
|
+
// Subscribe to selection events
|
|
9
|
+
const unsub = ctx.events.on('selection:changed', (id) => {
|
|
10
|
+
if (!id) return
|
|
11
|
+
const node = ctx.graph.getNode(id)
|
|
12
|
+
if (!node) return
|
|
13
|
+
|
|
14
|
+
const outCount = ctx.graph.outgoing(id).length
|
|
15
|
+
const inCount = ctx.graph.incoming(id).length
|
|
16
|
+
|
|
17
|
+
ctx.toast(`${id} — ${outCount} out, ${inCount} in`)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
// Register a context-menu item
|
|
21
|
+
ctx.ui.registerContextMenuItem({
|
|
22
|
+
label: 'Hello from plugin',
|
|
23
|
+
icon: '👋',
|
|
24
|
+
action: (nodeId) => {
|
|
25
|
+
ctx.toast(`You picked: ${nodeId}`)
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
// Cleanup function — called when plugin is disabled
|
|
30
|
+
this._unsub = unsub
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
deactivate() {
|
|
34
|
+
if (this._unsub) this._unsub()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "hello-world",
|
|
3
|
+
"name": "Hello World",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"author": "filegraph3d",
|
|
6
|
+
"description": "Minimal plugin scaffold — shows a toast on every selection",
|
|
7
|
+
"type": "action",
|
|
8
|
+
"main": "main.js",
|
|
9
|
+
"minAppVersion": "0.10.0",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"permissions": []
|
|
12
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# mermaid-exporter
|
|
2
|
+
|
|
3
|
+
Exports the current graph as a [Mermaid](https://mermaid.js.org/)
|
|
4
|
+
diagram (`.mmd`). Mermaid renders natively in GitHub Markdown, Notion,
|
|
5
|
+
Obsidian, GitLab, and many other tools.
|
|
6
|
+
|
|
7
|
+
## What it does
|
|
8
|
+
|
|
9
|
+
Adds **"Mermaid Diagram"** as a new option in the export menu.
|
|
10
|
+
|
|
11
|
+
Clicking it generates a file like:
|
|
12
|
+
|
|
13
|
+
```mermaid
|
|
14
|
+
graph LR
|
|
15
|
+
index_js["index.js"]
|
|
16
|
+
utils_js["utils.js"]
|
|
17
|
+
parser_js["parser.js"]
|
|
18
|
+
index_js --> utils_js
|
|
19
|
+
index_js --> parser_js
|
|
20
|
+
parser_js --> utils_js
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
You can paste this directly into a GitHub README inside a
|
|
24
|
+
```` ```mermaid ```` code block, and it'll render as a diagram.
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
Copy this folder into your filegraph3d plugins directory:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
macOS: ~/Library/Application Support/FileGraph 3D/plugins/
|
|
32
|
+
Windows: %APPDATA%\FileGraph 3D\plugins\
|
|
33
|
+
Linux: ~/.config/FileGraph 3D/plugins/
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Quit and reopen filegraph3d. Open a folder. Open **Settings → Export**
|
|
37
|
+
— you'll see "Mermaid Diagram" listed.
|
|
38
|
+
|
|
39
|
+
## Files
|
|
40
|
+
|
|
41
|
+
- **`manifest.json`** — declares the plugin as type `exporter` with
|
|
42
|
+
the `export` permission.
|
|
43
|
+
|
|
44
|
+
- **`main.js`** — registers the exporter. The `generate` function
|
|
45
|
+
receives the graph and returns a Mermaid-format string.
|
|
46
|
+
|
|
47
|
+
## How it handles ids
|
|
48
|
+
|
|
49
|
+
Mermaid identifiers must be alphanumeric. The plugin maps every file
|
|
50
|
+
path to a safe alias by:
|
|
51
|
+
|
|
52
|
+
1. Taking the basename: `src/foo/bar.js` → `bar.js`
|
|
53
|
+
2. Replacing non-alphanumeric chars with `_`: `bar.js` → `bar_js`
|
|
54
|
+
3. Disambiguating duplicates: if two files have the same basename,
|
|
55
|
+
the second becomes `bar_js2`, the third `bar_js3`, etc.
|
|
56
|
+
|
|
57
|
+
The original path is preserved as the **label** so it's still readable
|
|
58
|
+
in the rendered diagram.
|
|
59
|
+
|
|
60
|
+
## Limitations
|
|
61
|
+
|
|
62
|
+
Mermaid struggles with very large graphs. Performance gets sluggish
|
|
63
|
+
past ~500 nodes; rendering may fail past ~2000.
|
|
64
|
+
|
|
65
|
+
For large codebases:
|
|
66
|
+
|
|
67
|
+
1. Use filegraph3d's **active set** feature to mark just the files
|
|
68
|
+
you care about, then export.
|
|
69
|
+
|
|
70
|
+
2. Or use the [GraphViz DOT exporter pattern](../../docs/types/exporter.md#example-graphviz-dot)
|
|
71
|
+
— GraphViz handles 10k+ nodes well.
|
|
72
|
+
|
|
73
|
+
## What to change
|
|
74
|
+
|
|
75
|
+
If you want to customize the output:
|
|
76
|
+
|
|
77
|
+
### Different layout direction
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
// Top-to-bottom instead of left-to-right:
|
|
81
|
+
const lines = ['graph TB']
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Options: `TB` (top→bottom), `BT`, `LR` (left→right), `RL`.
|
|
85
|
+
|
|
86
|
+
### Group by folder
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
const lines = ['graph LR']
|
|
90
|
+
const folders = new Map()
|
|
91
|
+
for (const node of graph.nodes) {
|
|
92
|
+
const dir = node.id.split('/').slice(0, -1).join('/') || 'root'
|
|
93
|
+
if (!folders.has(dir)) folders.set(dir, [])
|
|
94
|
+
folders.get(dir).push(node)
|
|
95
|
+
}
|
|
96
|
+
for (const [dir, nodes] of folders) {
|
|
97
|
+
lines.push(` subgraph "${dir}"`)
|
|
98
|
+
for (const node of nodes) {
|
|
99
|
+
lines.push(` ${alias(node.id)}["${basename(node.id)}"]`)
|
|
100
|
+
}
|
|
101
|
+
lines.push(' end')
|
|
102
|
+
}
|
|
103
|
+
// ... edges
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Style by extension
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
// After declaring nodes:
|
|
110
|
+
lines.push(' classDef js fill:#F7DF1E,stroke:#000')
|
|
111
|
+
lines.push(' classDef ts fill:#3178C6,stroke:#000')
|
|
112
|
+
for (const node of graph.nodes) {
|
|
113
|
+
lines.push(` class ${alias(node.id)} ${node.ext}`)
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
MIT.
|
|
120
|
+
|
|
121
|
+
## More
|
|
122
|
+
|
|
123
|
+
See [../../docs/types/exporter.md](../../docs/types/exporter.md) for
|
|
124
|
+
the full exporter guide, including more output formats (GraphViz,
|
|
125
|
+
custom JSON) and patterns for handling the active set.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Exports the current graph as a Mermaid diagram.
|
|
2
|
+
// Output renders inside GitHub Markdown, Notion, Obsidian, etc.
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
activate(ctx) {
|
|
6
|
+
ctx.exporters.register({
|
|
7
|
+
name: 'Mermaid Diagram',
|
|
8
|
+
extension: 'mmd',
|
|
9
|
+
mimeType: 'text/plain',
|
|
10
|
+
generate(graph) {
|
|
11
|
+
const lines = ['graph LR']
|
|
12
|
+
|
|
13
|
+
// Build a short alias for each node so the diagram stays readable
|
|
14
|
+
// when file paths are long
|
|
15
|
+
const aliases = new Map()
|
|
16
|
+
for (const node of graph.nodes) {
|
|
17
|
+
const short = node.id.split('/').pop() || node.id
|
|
18
|
+
let alias = sanitize(short)
|
|
19
|
+
// Disambiguate if two files share a basename
|
|
20
|
+
let n = 2
|
|
21
|
+
const taken = new Set(aliases.values())
|
|
22
|
+
while (taken.has(alias)) {
|
|
23
|
+
alias = sanitize(short) + n
|
|
24
|
+
n++
|
|
25
|
+
}
|
|
26
|
+
aliases.set(node.id, alias)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Declare nodes with their display names
|
|
30
|
+
for (const node of graph.nodes) {
|
|
31
|
+
const alias = aliases.get(node.id)
|
|
32
|
+
const label = node.id.split('/').pop() || node.id
|
|
33
|
+
lines.push(` ${alias}["${escapeLabel(label)}"]`)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Then edges
|
|
37
|
+
for (const e of graph.edges) {
|
|
38
|
+
const sa = aliases.get(e.s)
|
|
39
|
+
const ta = aliases.get(e.t)
|
|
40
|
+
if (sa && ta) lines.push(` ${sa} --> ${ta}`)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return lines.join('\n')
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
ctx.log('Mermaid exporter ready — use Export → Mermaid Diagram')
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Mermaid requires alphanumeric node ids — strip everything else
|
|
52
|
+
function sanitize(s) {
|
|
53
|
+
return s.replace(/[^a-zA-Z0-9_]/g, '_').replace(/^(\d)/, '_$1')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function escapeLabel(s) {
|
|
57
|
+
return s.replace(/"/g, '\\"')
|
|
58
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mermaid-exporter",
|
|
3
|
+
"name": "Mermaid Exporter",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"author": "filegraph3d",
|
|
6
|
+
"description": "Export the graph as a Mermaid diagram (.mmd) for use in Markdown",
|
|
7
|
+
"type": "exporter",
|
|
8
|
+
"main": "main.js",
|
|
9
|
+
"minAppVersion": "0.10.0",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"permissions": []
|
|
12
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# rust-parser
|
|
2
|
+
|
|
3
|
+
A filegraph3d plugin that adds support for **Rust** (`.rs`) files.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
Without this plugin, filegraph3d ignores `.rs` files — they appear as
|
|
8
|
+
isolated nodes with no edges, because the app doesn't know how to
|
|
9
|
+
read Rust's import syntax.
|
|
10
|
+
|
|
11
|
+
With this plugin installed, filegraph3d parses:
|
|
12
|
+
|
|
13
|
+
- `use path::to::thing;` — including `pub use`
|
|
14
|
+
- `mod foo;` — local module declarations
|
|
15
|
+
- `extern crate foo;` — legacy crate imports
|
|
16
|
+
|
|
17
|
+
Comments are stripped first so commented-out imports don't produce
|
|
18
|
+
false edges.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
# Copy this folder into your filegraph3d plugins directory:
|
|
24
|
+
# macOS: ~/Library/Application Support/FileGraph 3D/plugins/
|
|
25
|
+
# Windows: %APPDATA%\FileGraph 3D\plugins\
|
|
26
|
+
# Linux: ~/.config/FileGraph 3D/plugins/
|
|
27
|
+
|
|
28
|
+
cp -r rust-parser ~/Library/Application\ Support/FileGraph\ 3D/plugins/
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then quit and reopen filegraph3d.
|
|
32
|
+
|
|
33
|
+
Open a Rust project (or any folder containing `.rs` files). You'll
|
|
34
|
+
see them connected by import edges in the graph.
|
|
35
|
+
|
|
36
|
+
## Limitations
|
|
37
|
+
|
|
38
|
+
This is a regex-based parser. It handles 95% of real-world Rust code
|
|
39
|
+
but has known blind spots:
|
|
40
|
+
|
|
41
|
+
| Case | Handling |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `use foo::bar;` | ✅ Captures `foo` (the leading path segment) |
|
|
44
|
+
| `use foo::{bar, baz};` | ✅ Captures `foo` once |
|
|
45
|
+
| `use foo as f;` | ✅ Captures `foo` |
|
|
46
|
+
| `use foo::*;` | ✅ Captures `foo` |
|
|
47
|
+
| `pub use foo::bar;` | ✅ Captures `foo` |
|
|
48
|
+
| Macro-generated `use` | ❌ Not seen (macros not expanded) |
|
|
49
|
+
| `use` inside `mod { ... }` blocks | ⚠️ Captured but path may be wrong |
|
|
50
|
+
| `#[cfg(...)] use foo;` | ✅ Captures (cfg-gated imports counted) |
|
|
51
|
+
|
|
52
|
+
If you need precise Rust parsing (workspace resolution, real path
|
|
53
|
+
resolution, cfg evaluation), this isn't the right tool — use
|
|
54
|
+
[cargo-modules](https://github.com/regexident/cargo-modules) and
|
|
55
|
+
export its graph.
|
|
56
|
+
|
|
57
|
+
## How resolution works
|
|
58
|
+
|
|
59
|
+
The parser returns import paths like `"std::collections"`. filegraph3d
|
|
60
|
+
then tries to match these against actual files in your project. The
|
|
61
|
+
matching is path-prefix based, so:
|
|
62
|
+
|
|
63
|
+
- `use crate::foo::bar` → matches `src/foo/bar.rs` or `src/foo/bar/mod.rs`
|
|
64
|
+
- `use std::collections` → no match (external crate, no source in your project)
|
|
65
|
+
|
|
66
|
+
External crates appear as imports with no resolved target — they're
|
|
67
|
+
visible in the inspector but don't create edges.
|
|
68
|
+
|
|
69
|
+
## License
|
|
70
|
+
|
|
71
|
+
MIT. Copy, modify, redistribute freely.
|