# Lux Language Server Protocol (LSP) Lux includes a built-in language server that provides IDE features for any editor that supports the Language Server Protocol. ## Quick Start ### Starting the LSP Server ```bash lux lsp ``` The server communicates via stdio (stdin/stdout), following the standard LSP protocol. ## Supported Features | Feature | Status | Description | |---------|--------|-------------| | Diagnostics | Full | Real-time parse and type errors | | Hover | Full | Type information and documentation | | Completions | Full | Context-aware code completion | | Go to Definition | Full | Jump to function/type definitions | | Formatting | CLI only | Code formatting via `lux fmt` (not exposed via LSP) | | Rename | Planned | Rename symbols | | Find References | Planned | Find all usages | ## Editor Setup ### VS Code 1. Install the Lux extension from the VS Code marketplace (coming soon) 2. Or configure manually in `settings.json`: ```json { "lux.lspPath": "/path/to/lux", "lux.enableLsp": true } ``` 3. Or use a generic LSP client extension like [vscode-languageclient](https://github.com/microsoft/vscode-languageserver-node): ```json { "languageServerExample.serverPath": "lux", "languageServerExample.serverArgs": ["lsp"] } ``` ### Neovim (with nvim-lspconfig) Add to your Neovim config (`init.lua`): ```lua local lspconfig = require('lspconfig') local configs = require('lspconfig.configs') -- Register Lux as a new LSP if not configs.lux then configs.lux = { default_config = { cmd = { 'lux', 'lsp' }, filetypes = { 'lux' }, root_dir = function(fname) return lspconfig.util.find_git_ancestor(fname) or vim.fn.getcwd() end, settings = {}, }, } end -- Enable the server lspconfig.lux.setup{} ``` Also add filetype detection in `~/.config/nvim/ftdetect/lux.vim`: ```vim au BufRead,BufNewFile *.lux set filetype=lux ``` ### Neovim (with built-in LSP) ```lua vim.api.nvim_create_autocmd('FileType', { pattern = 'lux', callback = function() vim.lsp.start({ name = 'lux', cmd = { 'lux', 'lsp' }, root_dir = vim.fs.dirname(vim.fs.find({ '.git', 'lux.toml' }, { upward = true })[1]), }) end, }) ``` ### Emacs (with lsp-mode) Add to your Emacs config: ```elisp (use-package lsp-mode :hook (lux-mode . lsp) :config (add-to-list 'lsp-language-id-configuration '(lux-mode . "lux")) (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection '("lux" "lsp")) :major-modes '(lux-mode) :server-id 'lux-lsp))) ``` ### Emacs (with eglot) ```elisp (add-to-list 'eglot-server-programs '(lux-mode . ("lux" "lsp"))) ``` ### Helix Add to `~/.config/helix/languages.toml`: ```toml [[language]] name = "lux" scope = "source.lux" injection-regex = "lux" file-types = ["lux"] roots = ["lux.toml", ".git"] comment-token = "//" indent = { tab-width = 4, unit = " " } language-server = { command = "lux", args = ["lsp"] } ``` ### Sublime Text (with LSP package) Add to `Preferences > Package Settings > LSP > Settings`: ```json { "clients": { "lux": { "enabled": true, "command": ["lux", "lsp"], "selector": "source.lux" } } } ``` ### Zed Add to your Zed settings: ```json { "lsp": { "lux": { "binary": { "path": "lux", "arguments": ["lsp"] } } } } ``` ## Feature Details ### Diagnostics The LSP server provides real-time diagnostics for: - **Parse errors**: Syntax issues, missing tokens, unexpected input - **Type errors**: Type mismatches, missing fields, unknown identifiers - **Effect errors**: Missing effect declarations, unhandled effects - **Behavioral type errors**: Violations of `is pure`, `is total`, etc. Diagnostics appear as you type, typically within 100ms of changes. Example diagnostic: ``` error[E0308]: mismatched types --> src/main.lux:10:5 | 10 | return "hello" | ^^^^^^^ expected Int, found String ``` ### Hover Information Hover over any symbol to see: - **Functions**: Signature and documentation - **Types**: Type definition - **Keywords**: Syntax explanation - **Effects**: Effect operations Example hover for `List.map`: ```markdown ```lux List.map(list: List, f: A -> B): List ``` Transform each element in a list by applying a function. ``` ### Completions The LSP provides context-aware completions: #### Module Member Completions After typing a module name and `.`, you get relevant members: ```lux List. // Shows: map, filter, fold, reverse, etc. String. // Shows: length, split, join, trim, etc. Console. // Shows: print, readLine, readInt ``` #### Keyword Completions At the start of statements: ```lux fn // Function declaration let // Variable binding type // Type declaration effect // Effect declaration match // Pattern matching ``` #### Type Completions In type position: ```lux Int, Float, Bool, String, Unit List, Option, Result ``` ### Go to Definition Jump to the definition of: - **Functions**: Goes to the `fn` declaration - **Types**: Goes to the `type` declaration - **Effects**: Goes to the `effect` declaration - **Let bindings**: Goes to the `let` statement - **Imports**: Goes to the imported module Works with: - `Ctrl+Click` / `Cmd+Click` in most editors - `gd` in Vim/Neovim - `M-.` in Emacs ## Module Completions Reference ### List Module | Method | Signature | Description | |--------|-----------|-------------| | `length` | `(list: List): Int` | Get list length | | `head` | `(list: List): Option` | First element | | `tail` | `(list: List): List` | All but first | | `map` | `(list: List, f: A -> B): List` | Transform elements | | `filter` | `(list: List, p: A -> Bool): List` | Keep matching | | `fold` | `(list: List, init: B, f: (B, A) -> B): B` | Reduce | | `reverse` | `(list: List): List` | Reverse order | | `concat` | `(a: List, b: List): List` | Join lists | | `range` | `(start: Int, end: Int): List` | Create range | | `get` | `(list: List, index: Int): Option` | Get at index | | `find` | `(list: List, p: A -> Bool): Option` | Find first match | | `isEmpty` | `(list: List): Bool` | Check empty | | `take` | `(list: List, n: Int): List` | Take n elements | | `drop` | `(list: List, n: Int): List` | Drop n elements | | `any` | `(list: List, p: A -> Bool): Bool` | Any matches | | `all` | `(list: List, p: A -> Bool): Bool` | All match | ### String Module | Method | Signature | Description | |--------|-----------|-------------| | `length` | `(s: String): Int` | String length | | `split` | `(s: String, delim: String): List` | Split by delimiter | | `join` | `(list: List, delim: String): String` | Join with delimiter | | `trim` | `(s: String): String` | Remove whitespace | | `contains` | `(s: String, sub: String): Bool` | Check contains | | `replace` | `(s: String, from: String, to: String): String` | Replace | | `chars` | `(s: String): List` | To char list | | `lines` | `(s: String): List` | Split into lines | | `toUpper` | `(s: String): String` | Uppercase | | `toLower` | `(s: String): String` | Lowercase | ### Console Effect | Operation | Signature | Description | |-----------|-----------|-------------| | `print` | `(msg: String): Unit` | Print message | | `readLine` | `(): String` | Read line | | `readInt` | `(): Int` | Read integer | ### Math Module | Function | Signature | Description | |----------|-----------|-------------| | `abs` | `(x: Int): Int` | Absolute value | | `min` | `(a: Int, b: Int): Int` | Minimum | | `max` | `(a: Int, b: Int): Int` | Maximum | | `pow` | `(base: Float, exp: Float): Float` | Exponentiation | | `sqrt` | `(x: Float): Float` | Square root | | `floor` | `(x: Float): Int` | Floor | | `ceil` | `(x: Float): Int` | Ceiling | | `round` | `(x: Float): Int` | Round | ### File Effect | Operation | Signature | Description | |-----------|-----------|-------------| | `read` | `(path: String): String` | Read file | | `write` | `(path: String, content: String): Unit` | Write file | | `exists` | `(path: String): Bool` | Check exists | | `delete` | `(path: String): Bool` | Delete file | | `listDir` | `(path: String): List` | List directory | | `mkdir` | `(path: String): Bool` | Create directory | ### Http Effect | Operation | Signature | Description | |-----------|-----------|-------------| | `get` | `(url: String): Result` | HTTP GET | | `post` | `(url: String, body: String): Result` | HTTP POST | | `put` | `(url: String, body: String): Result` | HTTP PUT | | `delete` | `(url: String): Result` | HTTP DELETE | ### Random Effect | Operation | Signature | Description | |-----------|-----------|-------------| | `int` | `(min: Int, max: Int): Int` | Random integer | | `float` | `(): Float` | Random float 0-1 | | `bool` | `(): Bool` | Random boolean | ### Time Effect | Operation | Signature | Description | |-----------|-----------|-------------| | `now` | `(): Int` | Current timestamp (ms) | | `sleep` | `(ms: Int): Unit` | Sleep for ms | ### Sql Effect | Operation | Signature | Description | |-----------|-----------|-------------| | `connect` | `(url: String): Connection` | Connect to database | | `query` | `(conn: Connection, sql: String): List` | Execute query | | `execute` | `(conn: Connection, sql: String): Int` | Execute statement | | `transaction` | `(conn: Connection, f: () -> A): A` | Run in transaction | ## Troubleshooting ### LSP Not Starting 1. Verify Lux is installed: `lux --version` 2. Check the server starts: `lux lsp` (should wait for input) 3. Check editor logs for connection errors ### No Completions 1. Ensure file has `.lux` extension 2. Check file is valid (no parse errors) 3. Verify LSP is connected (check status bar) ### Slow Diagnostics The LSP re-parses and type-checks on every change. For large files: 1. Consider splitting into modules 2. Check for complex recursive types 3. Report performance issues on GitHub ### Debug Logging Enable verbose logging: ```bash LUX_LSP_LOG=debug lux lsp ``` Logs are written to stderr. ## Protocol Details The Lux LSP server implements LSP version 3.17 with the following capabilities: ```json { "capabilities": { "textDocumentSync": "full", "hoverProvider": true, "completionProvider": { "triggerCharacters": ["."] }, "definitionProvider": true } } ``` ### Supported Methods | Method | Support | |--------|---------| | `initialize` | Full | | `shutdown` | Full | | `textDocument/didOpen` | Full | | `textDocument/didChange` | Full | | `textDocument/didClose` | Full | | `textDocument/hover` | Full | | `textDocument/completion` | Full | | `textDocument/definition` | Full | | `textDocument/publishDiagnostics` | Full (server-initiated) | ## Contributing The LSP implementation is in `src/lsp.rs`. To add new features: 1. Add capability to `ServerCapabilities` 2. Implement handler in `handle_request` 3. Add tests in `tests/lsp_tests.rs` 4. Update this documentation See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup.