Codescape is a VS Code extension that parses Java files with Tree-sitter and renders classes as an isometric city in webviews.
- Backend parses
.javafiles intoClassInfo[]. - In-memory store tracks parse state per file.
- File watcher emits incremental frontend updates (
PARTIAL_STATE). - Frontend canvas renders buildings from class metadata.
High-level flow:
Java files -> parser/javaExtractor -> parser -> FileParseStore
|
+-> on activation scan
+-> on file change/delete
|
v
JavaFileWatcher -> PARTIAL_STATE -> webview script -> render
This section covers all current modules under src/ and media/.
-
activate(context: vscode.ExtensionContext)- Purpose: extension bootstrap/orchestration.
- Responsibilities:
- Creates
FileParseStoreandJavaFileWatcher. - Initializes parser via
initializeParser(). - Registers commands:
codescape.scancodescape.createPanelcodescape.dumpParseStorecodescape.exportParseStore
- Registers explorer webview provider:
codescape.Cityview. - Performs startup parse of workspace Java files.
- Creates
- Interactions:
- Calls
parseAndStore()for initial population. - Passes webviews to watcher for incremental updates.
- Calls
-
createPanel(context, javaWatcher)- Purpose: opens editor-tab webview panel (
Codescape). - Interactions:
- Injects HTML from
getWebviewContent(). - Adds panel webview to
JavaFileWatcher. - Posts a legacy
AST_DATApayload (placeholder/bootstrap behavior).
- Injects HTML from
- Purpose: opens editor-tab webview panel (
-
workspaceScan(store)- Purpose: manual command-triggered parse pass.
- Interactions:
- Uses
getJavaFiles()+parseAndStore().
- Uses
-
getJavaFiles()- Purpose: find all Java files, honoring
.excludeglob entries.
- Purpose: find all Java files, honoring
-
isExcluded(uri)- Purpose: check if file path matches
.excludepatterns. - Abstraction: delegates matching to
minimatch.
- Purpose: check if file path matches
-
CodescapeViewProvider implements vscode.WebviewViewProvider- Purpose: explorer/sidebar view provider (
codescape.Cityview). - Interaction: registers webview with
JavaFileWatcherfor shared updates.
- Purpose: explorer/sidebar view provider (
-
getWebviewContent(webview, extensionUri)- Purpose: returns full frontend HTML+script.
- Frontend state model inside script:
state.classes:ClassInfo[]state.layout: class -> grid positionstate.colors: class -> assigned colorstate.status:loading | ready | empty | error
-
type IncrementalChangePayload{ changed?: ClassInfo[]; related?: ClassInfo[]; removed?: string[] }.
-
class JavaFileWatcher- Purpose: watches
**/*.javaand pushes incremental updates to active webviews. - Core fields:
_watcher: vscode.FileSystemWatcher_webviews: vscode.Webview[]
- Methods:
addWebview(view): subscribes webview.removeWebview(view): unsubscribes webview.handleIncrementalChange(uri, store): parse changed file, compute related classes, broadcastPARTIAL_STATE.buildPartialStatePayload(changed, removed, store): relationship-aware payload builder.postIncrementalChange(payload, views): sendsPARTIAL_STATE.dispose(): dispose file watcher.
- Interactions:
- Uses
parseAndStore()from parser. - Uses
buildGraph()/getRelated()from relations. - Uses
isExcluded()from extension.
- Uses
- Purpose: watches
-
ensureInitialized()/initializeParser()- Purpose: idempotent parser init.
-
parseJavaFile(uri)- Purpose: read Java file and extract classes.
-
parseAndStore(uri, store)- Purpose: orchestrates parse lifecycle.
- Steps:
- mark pending
- parse with Tree-sitter
- set parsed result
- export sidecar JSON (
*.jsonnext to source) - return
{ changed, removed }
-
getData(uri, store)- Purpose: store accessor.
- Purpose: Tree-sitter Java extraction logic.
- Key interfaces:
ClassInfoMethodInfoFieldInfoConstructorInfoParameterInfo
- Key functions:
initParser()extractClasses(source)- helper extraction functions for methods, fields, constructors, types, modifiers, inheritance.
- Notable behavior:
- Handles classes and interfaces (including nested declarations).
- Type extraction normalizes many forms (primitive, array, generic base type, scoped identifiers).
-
interface StoreEntry{ status: 'pending' | 'parsed'; data?: ClassInfo[] }
-
class FileParseStore- Purpose: typed in-memory parse-state map keyed by URI string.
- Methods:
markPending,setParsed,remove,get,snapshot.
-
interface ClassGraphdependsOnanddependedOnByadjacency maps.
-
buildGraph(allClasses)- Purpose: build dependency graph from inheritance/implements/fields/ctor params.
-
getRelated(changedNames, graph)- Purpose: find classes dependent on changed/removed classes.
- Purpose: canvas isometric primitives.
- Functions:
drawIsoGridshadedrawIsoCubedrawIsoBuildingplaceIsoBuilding
- Purpose: draw UML class box on canvas.
- Function:
drawUmlBox
- Purpose: state machine + render loop + message handling.
- Handles messages:
FULL_STATE(legacy path, referencesfileData)AST_DATA(legacy/mock path)PARTIAL_STATE(active incremental path)
- Current incremental behavior:
- Calls
updateState(changed)thenupdateState(related)if present. - This currently replaces full state with subsets instead of merging.
- Calls
BuildingNode,BuildingPosition,LayoutMap.
computeLayout(nodes)- Purpose: relationship-grouped row layout algorithm.
- Status: tested, but not wired into active webview layout path.
- Purpose: local/demo harness for trying
computeLayout()with sample nodes. - Status: developer utility; not imported by runtime extension code.
- Defines
FullStateMessage,PartialStateMessage,ReadyMessage, etc. - Status: partially out of sync with runtime payload shapes.
- Purpose: earlier standalone renderer/prototype assets.
- Status: not used by the active extension webview (
getWebviewContent+src/webview/*). - Interaction: none in current runtime path.
src/test/parser.test.ts: parser coverage with fixtures.src/test/relations.test.ts: graph and related-class behavior.src/test/layout.test.ts: layout algorithm behavior.src/test/watcher.test.ts: store lifecycle test (currently contains an assertion mismatch in expected parsed data shape).src/test/extension.test.ts: placeholder sample test.
Rationale:
- Isometric rendering needs 2.5D projection, not a full 3D scene graph.
- Lower dependency and runtime complexity in VS Code webview sandbox.
- Smaller bundle and easier control over pixel-level rendering.
Rationale:
- Layout is primarily presentation logic.
- Keeps backend focused on semantic model (
ClassInfo). - Avoids backend round-trip for every visual recalculation.
Current status:
- Active layout is inline (
runAutoLayoutin webview script). src/layout/placer.tsexists as an abstraction candidate, not yet integrated.
Intended rationale:
- Full snapshot once at load.
- Incremental payloads on change/delete for performance and responsiveness.
Current code state:
- Watcher emits
PARTIAL_STATE. - Startup panel currently posts legacy
AST_DATAmock data. - Message contract has legacy branches (
FULL_STATE,AST_DATA,READY) and needs consolidation. - This split remains the correct architecture even though implementation still has legacy paths.
Rationale:
- Support both explorer view and independent editor panel.
- Shared rendering stack allows consistent experience across placements.
Current implementation:
- Explorer view provider is registered.
- Separate
codescape.createPanelcommand opens panel view. - Watcher broadcasts updates to all registered webviews.
Current approach:
- Primary state: in-memory
FileParseStore. - Artifact persistence: per-file JSON sidecars from
parseAndStore. - Export utility: workspace-level
codescape-output.jsoncommand.
Rationale:
- Fast startup and simple runtime model.
- JSON outputs provide inspectable parse artifacts without database complexity.
codescape.scanreparses store data but does not currently broadcast a full-state refresh to already-open webviews.PARTIAL_STATEfrontend handling currently applies subset updates (changed, thenrelated) instead of merging against a canonical full state model.- Relationship data is computed backend-side, but frontend color mapping is still class-stable palette assignment (not relationship-based encoding yet).
src/types/messages.tsshould be aligned with live runtime payloads.
- Parsing and dependency graphing live in backend TypeScript modules.
- Watcher transforms file events into semantic incremental payloads.
- Webviews consume payloads and own visual state + rendering.
- Two display surfaces (explorer webview and panel webview) can receive the same updates.
- The system is structurally modular, but message-contract consolidation is the next key step for reliability.