The Soar VS Code extension provides comprehensive IDE support for the Soar cognitive architecture language, including syntax highlighting, language server features, datamap management, and project structure visualization compatible with VisualSoar.
The main extension entry point that coordinates all components:
- Lifecycle Management: Activates/deactivates extension components
- Command Registration: Registers all VS Code commands
- View Providers: Initializes tree view providers
- LSP Client: Starts the language server
- Validation Coordinator: Manages document validation workflow
Provides LSP-based language features:
- Main LSP server implementation
- Handles client-server communication
- Coordinates language features
- Parses Soar productions into structured format
- Extracts variables, attributes, function calls
- Calculates accurate position information for diagnostics
- Key Fix: Uses
getPositionInBody()to properly track line numbers across multi-line productions
- Type definitions for parsed Soar documents
- Production, attribute, variable types
- Range and position types
- VisualSoar project schema type definitions
- Datamap vertex types (SOAR_ID, ENUMERATION, INTEGER, FLOAT, STRING)
- Layout node types (operators, files, folders, substates)
- Project context management
- Finds and loads VisualSoar project files (.vsa.json, .vsproj, .soarproj)
- Builds indices for fast datamap/layout lookups
- Saves project changes
Manages VisualSoar datamap integration:
- Displays datamap as hierarchical tree view
- Cycle Detection: Prevents infinite expansion of self-referencing attributes (e.g., ^superstate)
- Multiple Datamap Views: Switch between root datamap and substate datamaps
- Smart Labeling: Shows node names instead of IDs, removes leading ^ from attributes
- Operator Hints: Displays operator name choices without expanding
- CRUD operations for datamap attributes
- Add, edit, delete attributes
- Type changes with validation
- Automatic project file saving
- Validates Soar code against datamap structure
- Reports errors at actual attribute locations (not production header)
- Escalates validation issues to errors (breaks Soar import)
- Uses full parsed range information for accurate diagnostics
Manages project structure visualization:
- Displays VisualSoar project structure
- Path Resolution: Correctly builds file paths using parent folder accumulation
- Click-to-Open: Opens files in editor when clicked
- Supports operators, substates, folders, files
- Add/remove operators, substates, files, folders
- Rename and delete nodes
- Creates corresponding datamap vertices for substates
- Synchronizes file system with project structure
- Finds orphaned .soar files not in project
- Bulk import/sync operations
- Maintains project file consistency
- Templates for creating new Soar files
- Operator scaffolding
- Substate initialization
- Bridges extension and language server
- Configures LSP capabilities
- Handles client-side LSP features
1. User saves .soar file
↓
2. extension.ts receives save event
↓
3. Calls validateDocument()
↓
4. soarParser.parse() → SoarDocument with accurate positions
↓
5. datamapValidator.validateDocument() → ValidationErrors with ranges
↓
6. datamapValidator.createDiagnostics() → VS Code Diagnostics
↓
7. Diagnostics displayed in editor at correct locations
1. User right-clicks datamap tree item
↓
2. Selects command (add/edit/delete attribute)
↓
3. extension.ts routes to datamapOperations
↓
4. Operation modifies ProjectContext in memory
↓
5. projectLoader.saveProject() writes to .vsa.json
↓
6. datamapTreeProvider.refresh() updates UI
1. User clicks layout tree item
↓
2. layoutTreeProvider builds LayoutTreeItem with:
- parentPath accumulated from ancestors
- node.file from project
↓
3. Combines: workspaceFolder + parentPath + node.file
↓
4. Example: /workspace + BW-Hierarchical/move-block + pick-up.soar
↓
5. Opens: /workspace/BW-Hierarchical/move-block/pick-up.soar
- Provider: Implements
TreeDataProvider<T> - Items: Custom
TreeItemsubclasses with context - Refresh: Event emitter for tree updates
- Context Values: Enable/disable commands based on item type
interface ProjectContext {
projectFile: string; // Path to .vsa.json
project: VisualSoarProject; // Parsed project
datamapIndex: Map<string, DMVertex>; // Fast vertex lookup
layoutIndex: Map<string, LayoutNode>; // Fast node lookup
}Shared across all components for consistent state.
Parser calculates positions by:
- Tracking base position (where body starts)
- Counting newlines and characters within body
- Building absolute positions for diagnostics
private getPositionInBody(body: string, offset: number, basePosition: Position): Position {
let line = basePosition.line;
let character = basePosition.character;
for (let i = 0; i < offset && i < body.length; i++) {
if (body[i] === '\n') {
line++;
character = 0;
} else {
character++;
}
}
return { line, character };
}Tracks ancestor IDs to prevent infinite loops:
ancestorIds: Set<string>; // All vertex IDs from root to current node
if (ancestorIds.has(edge.toId)) {
// Mark as cycle, don't allow expansion
}Problem: Originally all attributes reported errors at production header line.
Solution:
- Calculate
bodyBasePositionwhere production body starts (aftersp {) - Use
getPositionInBody()to track line breaks within body - Store full range in
SoarAttribute.range - Use range in diagnostics for accurate highlighting
Problem: Files in nested folders couldn't be opened (path not found).
Solution:
- Pass
parentPathparameter through tree construction - Accumulate folder paths:
parent + node.folderfor children - Combine:
workspaceFolder + parentPath + node.file - Handle both root files and deeply nested files correctly
Problem: ^superstate attribute pointing to parent caused infinite expansion.
Solution:
- Add
ancestorIds: Set<string>to each tree item - Check
ancestorIds.has(targetVertexId)before allowing expansion - Label cycles as "(cycle)" and make non-expandable
Feature: View different datamaps for substates.
Implementation:
- Add
currentRootIdto track which vertex to display - Provide
setDatamapRoot(vertexId)method - Find layout node name for labeled display
- Add "View Datamap" command for nodes with
dmId
src/
├── extension.ts # Main entry point
├── client/
│ └── lspClient.ts # LSP client
├── server/
│ ├── soarLanguageServer.ts # LSP server
│ ├── soarParser.ts # Parser with position tracking
│ ├── soarTypes.ts # Type definitions
│ ├── visualSoarProject.ts # VisualSoar schema types
│ └── projectLoader.ts # Project file I/O
├── datamap/
│ ├── datamapTreeProvider.ts # Datamap tree view
│ ├── datamapOperations.ts # CRUD operations
│ └── datamapValidator.ts # Code validation
└── layout/
├── layoutTreeProvider.ts # Project structure tree
├── layoutOperations.ts # Structure CRUD
├── projectSync.ts # File sync
└── soarTemplates.ts # File templates
soar.maxNumberOfProblems: Max diagnostics per file (default: 100)soar.trace.server: LSP communication logging (off/messages/verbose)
Used for conditional menu items:
datamap-root: Root datamap nodedatamap-attribute-{type}: Datamap attribute by typelayout-{type}: Layout node by type (operator-root, high-level-operator, etc.)
Follows VisualSoar 9.6.4 project schema exactly.
.vsa.json: Primary format (JSON with explicit schema).vsproj: VisualSoar native format.soarproj: Legacy format
- Projects created in extension open in VisualSoar
- Projects created in VisualSoar open in extension
- All schema fields preserved
SOAR_ID: Identifier with attributesENUMERATION: Fixed set of choicesINTEGER: Integer rangeFLOAT: Float rangeSTRING: String value
OPERATOR_ROOT: Project rootFOLDER: DirectoryFILE: Non-Soar fileFILE_OPERATOR: Soar fileOPERATOR: Basic operatorHIGH_LEVEL_OPERATOR: Operator with substate (hasdmId)HIGH_LEVEL_FILE_OPERATOR: File operator with substateIMPASSE_OPERATOR: Impasse handlerHIGH_LEVEL_IMPASSE_OPERATOR: High-level impasse handler
- Advanced Completions: Context-aware based on variable bindings
- Refactoring: Rename attribute across project
- Datamap Graph View: Visual graph editor for datamap
- Code Generation: Generate boilerplate from datamap
- Import/Export: Import datamap from existing code
- Undo/Redo: For datamap operations
- Drag-and-Drop: Reorganize layout tree
- Semantic Search: Find all uses of an attribute
- Custom commands: Add via
registerCommand() - Tree view providers: Extend
TreeDataProvider - LSP features: Add to
soarLanguageServer.ts - Validation rules: Extend
datamapValidator.ts
test/fixtures/example.soar: Basic Soar filetest/fixtures/test-validation.soar: Validation test casestest/BW-Hierarchical/: Complete hierarchical project
test/
├── suite/
│ ├── extension.test.ts # Extension tests
│ └── index.ts # Test runner
└── fixtures/ # Test data
Press F5 to launch Extension Development Host:
- Extension loads in isolated VS Code instance
- Set breakpoints in TypeScript
- Console logs appear in Debug Console
- Test with real .soar files
- "File not found": Check path resolution in
layoutTreeProvider.ts - "Wrong line highlighted": Check position calculation in
soarParser.ts - "Datamap not loading": Verify project file format and schema version
- "Infinite expansion": Check cycle detection in
datamapTreeProvider.ts
- Indices: Use
Map<string, T>for O(1) lookups - Lazy Loading: Tree items created on-demand
- Caching: Parse results cached per document version
- Debouncing: Validation debounced on rapid edits
- Clear diagnostic collection on file close
- Release references to closed documents
- Rebuild indices only when project file changes
Last Updated: December 2, 2025 Schema Version: VisualSoar 6 Extension Version: 0.1.0