# 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<A>, f: A -> B): List<B>
```

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<A>): Int` | Get list length |
| `head` | `(list: List<A>): Option<A>` | First element |
| `tail` | `(list: List<A>): List<A>` | All but first |
| `map` | `(list: List<A>, f: A -> B): List<B>` | Transform elements |
| `filter` | `(list: List<A>, p: A -> Bool): List<A>` | Keep matching |
| `fold` | `(list: List<A>, init: B, f: (B, A) -> B): B` | Reduce |
| `reverse` | `(list: List<A>): List<A>` | Reverse order |
| `concat` | `(a: List<A>, b: List<A>): List<A>` | Join lists |
| `range` | `(start: Int, end: Int): List<Int>` | Create range |
| `get` | `(list: List<A>, index: Int): Option<A>` | Get at index |
| `find` | `(list: List<A>, p: A -> Bool): Option<A>` | Find first match |
| `isEmpty` | `(list: List<A>): Bool` | Check empty |
| `take` | `(list: List<A>, n: Int): List<A>` | Take n elements |
| `drop` | `(list: List<A>, n: Int): List<A>` | Drop n elements |
| `any` | `(list: List<A>, p: A -> Bool): Bool` | Any matches |
| `all` | `(list: List<A>, p: A -> Bool): Bool` | All match |

### String Module

| Method | Signature | Description |
|--------|-----------|-------------|
| `length` | `(s: String): Int` | String length |
| `split` | `(s: String, delim: String): List<String>` | Split by delimiter |
| `join` | `(list: List<String>, 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<String>` | To char list |
| `lines` | `(s: String): List<String>` | 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<String>` | List directory |
| `mkdir` | `(path: String): Bool` | Create directory |

### Http Effect

| Operation | Signature | Description |
|-----------|-----------|-------------|
| `get` | `(url: String): Result<String, String>` | HTTP GET |
| `post` | `(url: String, body: String): Result<String, String>` | HTTP POST |
| `put` | `(url: String, body: String): Result<String, String>` | HTTP PUT |
| `delete` | `(url: String): Result<String, String>` | 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<Row>` | 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.
