✏️ lapis
A minimal, lightweight Language Server Protocol (LSP) framework in Lean 4.
This is just a scaffold for building language servers in Lean 4. It provides the core LSP protocol handling, a virtual file system (VFS) for managing text documents, and utilities for common LSP tasks.
🎨 Usage
Add lapis as a dependency in your lakefile.toml:
[[require]]
name = "lapis"
git = "https://github.com/SrGaabriel/lapis"
rev = "main"
💡 Example
This is a small example of a language server using lapis:
def main : IO Unit := do
let config := LspConfig.new "example-server"
|>.withVersion "0.1.0"
|>.withCapabilities {
textDocumentSync := some {
openClose := some true
change := some .full
save := some { includeText := some false }
}
hoverProvider := some true
completionProvider := some {
triggerCharacters := some #["."]
resolveProvider := some false
}
}
|>.onRequestOpt "textDocument/hover" handleHover
|>.onRequest "textDocument/completion" handleCompletion
|>.onNotification "textDocument/didOpen" handleDidOpen
|>.onNotification "textDocument/didChange" handleDidChange
runStdio config
def handleDidOpen (ctx : RequestContext TestState) (params : DidOpenTextDocumentParams) : IO Unit := do
ctx.showInfo "Document opened!"
updateDiagnostics ctx params.textDocument.uri
📝 Features
Core Protocol
- Complete JSON-RPC 2.0 implementation
- LSP 3.17 base types (Position, Range, Location, Diagnostic, etc)
- Bidirectional messaging
- Request cancellation support
- Async request handling
Transport
- stdio transport (standard LSP communication)
- Thread-safe message output channel
- Proper Content-Length framing
Server Infrastructure
- Type-safe handler registration
- Clean
ServerMmonad for server operations - Built-in document synchronization (open/change/close)
- User-defined state management
- Server and client capability negotiation
Virtual File System (VFS)
- Efficient finger tree-based text representation
- Piece table for fast incremental edits
- Line index with dirty range tracking
- UTF-8/UTF-16 position conversion for LSP compatibility
- Document snapshots with reference counting
- Thread-safe document store with IO-based operations
- O(log n) split/concatenation, O(1) amortized cons/snoc
Implemented LSP Features
-
initialize/shutdown/exitlifecycle - Text document synchronization (full and incremental)
- Hover (
textDocument/hover) - Completion (
textDocument/completion) - Go to definition (types defined, handler registration supported)
- Find references (types defined, handler registration supported)
- Publish diagnostics (
textDocument/publishDiagnostics) - Workspace configuration (
workspace/configuration) - Configuration change notifications (
workspace/didChangeConfiguration)
Developer Experience
- Automatic JSON serialization/deserialization
- Type-safe message handlers with compile-time checks
- Helper methods for common operations (logging, messages, diagnostics)
- Generic configuration support for type-safe settings
- Builder pattern for server configuration
Concurrency
- Actor-based concurrency model with message passing
- Separate VFS and LSP actors for parallelism
- Per-request cancellation tokens
- Async request processing with bounded concurrency
- Thread-safe channels (unbounded, bounded, oneshot)
- Document snapshots with reference counting for concurrent access
- Actor supervision and lifecycle management
Server Utilities
- Progress reporting API with token lifecycle management
- Workspace edit support (
workspace/applyEdit) with builder pattern - Debounced diagnostics with per-document scheduling
- Dynamic capability registration (
client/registerCapability) - File watcher registration helpers