Architecture
System layout for spice-lsp: crates, data flow, and how analysis layers build on each other.
Story in four layers
Every feature belongs to one of these layers:
| Layer | Responsibility | Status |
|---|---|---|
| 1. Parse | Tree-sitter CST, syntax diagnostics | Shipped |
| 2. Index | Symbols, scopes, cross-references, include/lib graph | Shipped |
| 3. Assist | Hover (reference + file-local); completion | Hover shipped; completion planned |
| 4. Deep semantics | Formatter; net connectivity | Formatter shipped; connectivity planned |
Layer 4 and the reference corpus are documented in Dialect reference and net semantics.
High-level overview
┌─────────────────────────────────────────────────────────────────┐
│ Editor clients │
│ VS Code extension │ Neovim │ Helix │ other LSP clients │
└────────────┬────────────────────────────────────────────────────┘
│ JSON-RPC 2.0 over stdio (LSP)
▼
┌─────────────────────────────────────────────────────────────────┐
│ crates/spice-lsp (binary: spice-lsp) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ tower-lsp Backend │ │
│ │ • text sync, publishDiagnostics │ │
│ │ • symbols, definition, references │ │
│ │ • hover (reference corpus + file-local) │ │
│ │ • formatting (`format_source` → TextEdit) │ │
│ │ • (planned) completion │ │
│ └────────────────────────┬─────────────────────────────────┘ │
└───────────────────────────┼─────────────────────────────────────┘
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌────────────────┐ ┌──────────────────┐
│ spice-parser │ │ spice-reference│ │ tree-sitter-spice│
│ parse, index, │ │ dialect docs │ │ grammar, queries │
│ diagnose, format│ │ │ │ │
└─────────────────┘ └────────────────┘ └──────────────────┘
Crate responsibilities
| Crate / directory | Role |
|---|---|
crates/spice-lsp | LSP server, JSON-RPC, document store; format CLI subcommand |
crates/spice-parser | Parsing, symbol index, diagnostics, formatter (format_source) |
crates/spice-reference | Load and query dialect reference entries |
tree-sitter-spice/ | Grammar and query files |
reference/ | Curated JSON per dialect — authored over time |
editors/vscode/ | VS Code extension client |
test-data/ | Fixtures for syntax, semantics, hover snapshots |
LSP server lifecycle
- Client connects via stdio; sends
initializewith client capabilities and dialect option. - Server responds with capabilities (incremental sync, diagnostics, symbols, definition, references, hover, formatting).
- Document open/change updates an in-memory map of open buffers.
- On each change (debounced ~150 ms):
- Re-parse with Tree-sitter
- Run diagnostic passes (syntax + semantic + include resolution)
- Send
textDocument/publishDiagnosticswith the document version
- Hover resolves against the CST and
spice-reference. Navigation requests re-analyze on demand so the symbol index stays current even when diagnostics are still debouncing. - Formatting pretty-prints the buffer via
spice_parser::format_sourceand returns a full-documentTextEditwhen needed. - Shutdown exits cleanly.
Document model
#![allow(unused)]
fn main() {
struct Document {
uri: Url,
text: String,
tree: tree_sitter::Tree,
version: i32,
symbols: SymbolTable,
// planned
net_graph: Option<NetGraph>,
}
}
Parser and analysis pipeline
Syntax
- Parse buffer → CST
- Collect ERROR / MISSING nodes and hand-written checks (e.g. unclosed
.subckt) - Map to LSP
Diagnostic(Error)
Symbol index
Walk the CST to build:
- Subcircuit and model definitions
- Component instances and
.parambindings
Enables navigation, duplicate-name warnings, and undefined reference checks.
Include / library graph
Follow .include / .inc and HSPICE .lib 'file' entry (section-filtered) to merge external model and subcircuit definitions. Used by unknown-model diagnostics and go-to-definition. Details: Include and library resolution.
Assist
Use the symbol index and reference corpus for hover (subcircuit pin lists, in-file .model parameters, curated directive/element docs). Completion will reuse the same index and corpus.
Format and dialect
Dialect setting selects reference namespace and (later) grammar quirks / formatter profiles. The formatter pretty-prints line tokens (column alignment, + wrap, directive casing) and returns a full-document TextEdit — see Formatter.
Reference docs and connectivity
Reference lookup (shipped): Map cursor token → reference/<dialect>/… entry → markdown hover.
Net graph (planned): Build terminal graph per scope → warn on dangling nodes and floating nets.
Instance lines ──► NetGraph ──► dangling / floating diagnostics
Cursor token ──► ReferenceIndex ──► rich hover markdown
See Dialect reference and net semantics.
VS Code extension
Thin Node client: spawns spice-lsp, forwards LSP traffic, exposes dialect and diagnostic settings. No parsing in TypeScript.
See VS Code integration.
Performance targets
| Metric | Target |
|---|---|
| Parse + syntax diagnose (5k lines) | < 50 ms |
| Full semantic pass + net graph (50k lines) | < 100 ms |
| Reference hover lookup | < 1 ms (in-memory index) |
| Incremental edit | Re-parse changed regions only |
Buffers at or above spiceLsp.extractedByteThreshold (default 16 MiB) use extracted analysis: definitions-only indexing without per-instance symbols. See LSP features and Large-file / extracted mode.
Related reading
- Dialect reference and net semantics
- LSP features — method-by-method status
- Demo and testing — verification
- Design (internal) — full requirements