# LSP — semantic tools for languages beyond TypeScript

JUJU ships a built-in TypeScript/JavaScript semantic provider (bundled
TypeScript language service in a guarded worker). For **other languages** the
same tools — `symbols`, `references`, `preview_rename`, `diagnostics
(source=lsp)` — talk to an owner-controlled language server (the LSP adapter,
ADR-015).

## 0.8.2 setup

`juju setup` prepares the default external LSP set for **Python, HTML, CSS,
JSON, YAML and Bash** in JUJU private managed state and registers only missing
entries. Existing owner registrations are preserved. `juju setup --check`
performs real LSP `initialize` / `shutdown` protocol probes for those configured
servers; finding an executable alone is not considered ready.

On Windows the trusted resolver accepts a native **`.exe` outside the
workspace**, not a repository `.cmd`/`.bat` shim. The setup-managed JavaScript
servers therefore use the trusted `node.exe` plus their exact installed JS
entrypoint. A native `gopls.exe` or `rust-analyzer.exe` can still be registered
directly by the owner. The same trusted-path, workspace/secret and output
boundaries apply on every OS.

```bash
juju setup --components lsp
juju setup --check --components lsp
juju lsp list
```

## Enable an additional language manually

```bash
# Python (pyright)
npm install -g pyright
juju lsp add python --command pyright-langserver --args --stdio --ext .py --ext .pyi

# Go (gopls)
juju lsp add go --command gopls --ext .go

# Rust (rust-analyzer)
juju lsp add rust --command rust-analyzer --ext .rs

juju lsp list
juju lsp remove python
```

Restart `juju start` / `juju stdio` afterwards. The registry lives in the
**global** config (`lsp` key), never in the repository.

## How it works

- One server process per language, started lazily on first use, reused, and
  shut down after ~10 minutes idle; restarted if it crashes.
- The executable is resolved on the **trusted PATH** (or an absolute path
  outside the workspace) — never from inside the repository.
- Every file the server is asked about is read through the same `WorkspaceFS`
  policy (no secrets, no symlink escapes). Locations the server reports
  **outside** the workspace (or inside dependency folders) are counted as
  `outOfScopeCount`, never disclosed, and make `preview_rename` refuse rather
  than apply a partial rename.
- Rename edits come back as byte-offset spans and flow through the same
  planner/journal as every other change (`apply_changes`, `rollback_changes`).
- Positions use JUJU's contract: 1-based line, 1-based UTF-16 column.

## Trust

A language server is local software running with your user's privileges.
Registering one is an owner decision (`juju lsp add`); a repository cannot
register or point to a server. `environment_info` and `project_overview`
report which languages are configured.

## Unsupported

Files whose extension is not registered return `UNSUPPORTED_LANGUAGE` with the
`juju lsp add` hint — JUJU never fakes semantics with grep.
