feat(coding-agent): add Expert Elixir language server to built-in LSP defaults

Adds an `expert` server entry (binary `expert`, invoked `expert --stdio`)
to the built-in LSP defaults, auto-detected for Mix projects
(`mix.exs`/`mix.lock`). Placed after `elixirls` so elixir-ls remains the
primary navigation server when both binaries are installed; this keeps the
default getServerForFile() behavior unchanged. Absent-binary setups are
unaffected by loadConfig's PATH/root-marker gating.

Includes a docs row, changelog entry, and a regression test pinning that
`.ex` files match `expert` and that `elixirls` still sorts ahead of it.
This commit is contained in:
Tharindu Abeydeera
2026-06-11 00:37:54 +02:00
parent e6ee124d7c
commit 33fcc53e82
4 changed files with 22 additions and 0 deletions
+1
View File
@@ -211,6 +211,7 @@ The following servers ship in `defaults.json` and are eligible for auto-detectio
| `hls` | Haskell | `haskell-language-server-wrapper` |
| `ocamllsp` | OCaml | `ocamllsp` |
| `elixirls` | Elixir | `elixir-ls` |
| `expert` | Elixir | `expert` |
| `erlangls` | Erlang | `erlang_ls` |
| `gleam` | Gleam | `gleam` |
| `solargraph` | Ruby | `solargraph` |
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased]
### Added
- Added the Expert Elixir language server (`expert`, invoked as `expert --stdio`) to the built-in LSP server list, auto-detected for Mix projects (`mix.exs`/`mix.lock`). When both are installed, `elixir-ls` remains the primary navigation server (Expert is ordered after it).
## [15.11.0] - 2026-06-10
### Breaking Changes
@@ -248,6 +248,12 @@
}
}
},
"expert": {
"command": "expert",
"args": ["--stdio"],
"fileTypes": [".ex", ".exs", ".heex", ".eex"],
"rootMarkers": ["mix.exs", "mix.lock"]
},
"erlangls": {
"command": "erlang_ls",
"args": [],
@@ -38,6 +38,7 @@ import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
import { clampTimeout } from "@oh-my-pi/pi-coding-agent/tools/tool-timeouts";
import * as piUtils from "@oh-my-pi/pi-utils";
import { sanitizeText, TempDir } from "@oh-my-pi/pi-utils";
import DEFAULTS from "../../src/lsp/defaults.json" with { type: "json" };
describe("lsp regressions", () => {
afterEach(() => {
@@ -1829,3 +1830,13 @@ for await (const chunk of Bun.stdin.stream()) {
expect(output).toContain("typescript-language-server (ready)");
});
});
describe("expert elixir lsp", () => {
it("registers expert for .ex while keeping elixirls primary", () => {
const config = { servers: DEFAULTS as unknown as Record<string, ServerConfig> };
const names = getServersForFile(config, "lib/app.ex").map(([name]) => name);
expect(names).toContain("expert");
expect(names).toContain("elixirls");
expect(names.indexOf("elixirls")).toBeLessThan(names.indexOf("expert"));
});
});