Summary
Build a minimal LSP server that pushes compiler diagnostics and lint warnings to the editor in real-time. This is the foundation that Phase 2 (navigation) and Phase 3 (completion) build on.
Architecture
VS Code extension (language-winn-vscode)
│ stdin/stdout JSON-RPC
▼
winn_lsp.erl (gen_server)
├── winn_lsp_transport.erl # JSON-RPC framing over stdio
├── winn_lsp_handler.erl # LSP method dispatch
├── winn_lsp_documents.erl # In-memory document buffer (ETS)
└── winn_lsp_diagnostic.erl # #diag → LSP Diagnostic conversion
│
▼
Existing compiler pipeline
(winn_lexer → winn_parser → winn_semantic → winn_lint)
LSP Methods to Implement
| Method |
Direction |
Description |
initialize |
request |
Return server capabilities |
initialized |
notification |
No-op acknowledgment |
shutdown / exit |
request/notif |
Clean shutdown |
textDocument/didOpen |
notification |
Store document, run diagnostics |
textDocument/didChange |
notification |
Update buffer, re-run diagnostics |
textDocument/didSave |
notification |
Re-run diagnostics |
textDocument/didClose |
notification |
Remove from buffer |
textDocument/publishDiagnostics |
server→client |
Push diagnostics |
Diagnostic Pipeline
On every didOpen/didChange/didSave:
1. Get source from document buffer
2. winn_lexer:string(Source) → lex errors OR tokens
3. winn_newline_filter:filter(Tokens)
4. winn_parser:parse(Filtered) → parse errors OR AST
5. winn_lint:check_string(Source) → lint warnings
6. Convert all #diag records → LSP Diagnostic JSON
7. Publish via textDocument/publishDiagnostics
If lexing/parsing fails, still publish those errors (don't require a valid AST for diagnostics).
#diag → LSP Diagnostic Mapping
%% Winn #diag record:
#diag{severity, title, file, line, col, span_len, message, hint}
%% LSP Diagnostic:
#{
<<"range">> => #{
<<"start">> => #{<<"line">> => Line - 1, <<"character">> => Col - 1},
<<"end">> => #{<<"line">> => Line - 1, <<"character">> => Col - 1 + SpanLen}
},
<<"severity">> => 1 (error) | 2 (warning),
<<"source">> => <<"winn">>,
<<"message">> => Message,
<<"code">> => RuleName %% for lint rules
}
New Files
| File |
Purpose |
~Lines |
apps/winn/src/winn_lsp.erl |
gen_server entry point, process lifecycle |
80 |
apps/winn/src/winn_lsp_transport.erl |
JSON-RPC read/write over stdio |
120 |
apps/winn/src/winn_lsp_handler.erl |
Method dispatch + request handlers |
150 |
apps/winn/src/winn_lsp_documents.erl |
ETS-backed document buffer |
60 |
apps/winn/src/winn_lsp_diagnostic.erl |
#diag → LSP conversion |
80 |
apps/winn/test/winn_lsp_tests.erl |
Unit tests for handler + diagnostics |
150 |
CLI Integration
winn lsp # Start LSP server on stdio (for editor use)
Add parse_args(["lsp"]) -> lsp and handler in winn_cli.erl.
VS Code Extension Changes
Update language-winn-vscode:
- Add
vscode-languageclient dependency
- Configure
LanguageClient to spawn winn lsp via stdio
- Remove existing compile-on-save shell spawning (LSP replaces it)
Acceptance Criteria
Part of v0.9.0 — Developer Tooling
Summary
Build a minimal LSP server that pushes compiler diagnostics and lint warnings to the editor in real-time. This is the foundation that Phase 2 (navigation) and Phase 3 (completion) build on.
Architecture
LSP Methods to Implement
initializeinitializedshutdown/exittextDocument/didOpentextDocument/didChangetextDocument/didSavetextDocument/didClosetextDocument/publishDiagnosticsDiagnostic Pipeline
On every
didOpen/didChange/didSave:If lexing/parsing fails, still publish those errors (don't require a valid AST for diagnostics).
#diag → LSP Diagnostic Mapping
New Files
apps/winn/src/winn_lsp.erlapps/winn/src/winn_lsp_transport.erlapps/winn/src/winn_lsp_handler.erlapps/winn/src/winn_lsp_documents.erlapps/winn/src/winn_lsp_diagnostic.erlapps/winn/test/winn_lsp_tests.erlCLI Integration
winn lsp # Start LSP server on stdio (for editor use)Add
parse_args(["lsp"]) -> lspand handler inwinn_cli.erl.VS Code Extension Changes
Update
language-winn-vscode:vscode-languageclientdependencyLanguageClientto spawnwinn lspvia stdioAcceptance Criteria
winn lspstarts and responds toinitializePart of v0.9.0 — Developer Tooling