T M4.5: Tier 1 language-server configs (ts/js, lua, bash, toml, zig)
Ship single-binary LSP servers pre-wired in the default bundle so a user who installs the server gets attachment with no init.lua: - typescript-language-server (--stdio) for the typescript / typescriptreact / javascript / javascriptreact language ids - lua-language-server (settings.Lua present-not-null for the workspace/configuration pull) - bash-language-server (start subcommand) - taplo (lsp stdio; settings.taplo present-not-null) - zls (no args) Plus the pmacs.lsp.filetypes extension->language map entries (ts/mts/cts, tsx, js/mjs/cjs, jsx, sh, bash, toml, zig, zon, lua), keeping the same idempotent `or` guard so init.lua overrides win. m4_25 asserts every config table and the filetype map resolve to the documented values (binary-independent, spawns nothing). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
3f9edb2e57
commit
e0e176fe4d
|
|
@ -84,6 +84,65 @@ pmacs.lsp.config.go = pmacs.lsp.config.go or {
|
|||
settings = { gopls = {} },
|
||||
}
|
||||
|
||||
-- TypeScript / JavaScript via typescript-language-server (the
|
||||
-- tsserver wrapper). One binary serves the whole family; like
|
||||
-- `c`/`cpp` these are separate config entries purely so the
|
||||
-- `language_id` sent in `didOpen` is accurate — tsserver keys
|
||||
-- diagnostics and some code actions off it (typescript /
|
||||
-- typescriptreact / javascript / javascriptreact). `--stdio` is the
|
||||
-- LSP transport. The project model comes from `tsconfig.json` /
|
||||
-- `jsconfig.json` (no `workspace/configuration` pull). Users
|
||||
-- override from init.lua before a TS/JS file opens; swapping to
|
||||
-- `vtsls` is just `command = "vtsls"`.
|
||||
for _, lid in ipairs({ "typescript", "typescriptreact", "javascript", "javascriptreact" }) do
|
||||
pmacs.lsp.config[lid] = pmacs.lsp.config[lid] or {
|
||||
command = "typescript-language-server",
|
||||
args = { "--stdio" },
|
||||
}
|
||||
end
|
||||
|
||||
-- Lua via lua-language-server (sumneko). Speaks LSP over stdio with
|
||||
-- no transport flag. It pulls configuration via
|
||||
-- `workspace/configuration` under the `Lua` section; an empty table
|
||||
-- is "use defaults" — present, not null (same rationale as gopls).
|
||||
-- `.lua` is tree-sitter-grammar-backed, so `pmacs.parse` already
|
||||
-- resolves the `lua` language and this is the config that attaches.
|
||||
-- Users populate `settings.Lua` (runtime.version, workspace.library,
|
||||
-- diagnostics.globals = { "pmacs" }, …) from init.lua.
|
||||
pmacs.lsp.config.lua = pmacs.lsp.config.lua or {
|
||||
command = "lua-language-server",
|
||||
args = {},
|
||||
settings = { Lua = {} },
|
||||
}
|
||||
|
||||
-- Bash / shell via bash-language-server. `start` is its
|
||||
-- LSP-over-stdio subcommand. No project config; it shells out to
|
||||
-- `shellcheck` (diagnostics) and `shfmt` (formatting) when those are
|
||||
-- on PATH. Users override from init.lua before a shell file opens.
|
||||
pmacs.lsp.config.bash = pmacs.lsp.config.bash or {
|
||||
command = "bash-language-server",
|
||||
args = { "start" },
|
||||
}
|
||||
|
||||
-- TOML via taplo. `taplo lsp stdio` serves LSP over stdio. taplo
|
||||
-- pulls configuration via `workspace/configuration` under the
|
||||
-- `taplo` section (empty ⇒ defaults, present not null); a project
|
||||
-- `.taplo.toml` still wins. Users populate it from init.lua.
|
||||
pmacs.lsp.config.toml = pmacs.lsp.config.toml or {
|
||||
command = "taplo",
|
||||
args = { "lsp", "stdio" },
|
||||
settings = { taplo = {} },
|
||||
}
|
||||
|
||||
-- Zig via zls. `zls` with no args serves LSP over stdio; it reads
|
||||
-- `zls.json` / `build.zig` for the project model (no
|
||||
-- `workspace/configuration` pull). Users override from init.lua
|
||||
-- before a `.zig` / `.zon` file opens.
|
||||
pmacs.lsp.config.zig = pmacs.lsp.config.zig or {
|
||||
command = "zls",
|
||||
args = {},
|
||||
}
|
||||
|
||||
-- LSP-side extension → language map, deliberately independent of the
|
||||
-- tree-sitter detection in `pmacs.parse` (which is grammar-gated:
|
||||
-- Python has an LSP server but no bundled grammar). Consulted only
|
||||
|
|
@ -103,6 +162,28 @@ for _, ext in ipairs({ "cpp", "cc", "cxx", "hpp", "hh", "hxx", "ipp", "inl", "cp
|
|||
end
|
||||
-- Go.
|
||||
pmacs.lsp.filetypes.go = pmacs.lsp.filetypes.go or "go"
|
||||
-- Tier 1 single-binary servers. TypeScript / JavaScript distinguish
|
||||
-- the JSX variants so the server enables the JSX parser.
|
||||
for _, ext in ipairs({ "ts", "mts", "cts" }) do
|
||||
pmacs.lsp.filetypes[ext] = pmacs.lsp.filetypes[ext] or "typescript"
|
||||
end
|
||||
pmacs.lsp.filetypes.tsx = pmacs.lsp.filetypes.tsx or "typescriptreact"
|
||||
for _, ext in ipairs({ "js", "mjs", "cjs" }) do
|
||||
pmacs.lsp.filetypes[ext] = pmacs.lsp.filetypes[ext] or "javascript"
|
||||
end
|
||||
pmacs.lsp.filetypes.jsx = pmacs.lsp.filetypes.jsx or "javascriptreact"
|
||||
-- Lua (lua-language-server). pmacs bundles a Lua grammar, so
|
||||
-- `language_for_path` resolves `.lua` first; this entry is the LSP
|
||||
-- fallback and keeps the language id stable if that ever changes.
|
||||
pmacs.lsp.filetypes.lua = pmacs.lsp.filetypes.lua or "lua"
|
||||
-- Bash / shell (bash-language-server).
|
||||
pmacs.lsp.filetypes.sh = pmacs.lsp.filetypes.sh or "bash"
|
||||
pmacs.lsp.filetypes.bash = pmacs.lsp.filetypes.bash or "bash"
|
||||
-- TOML (taplo).
|
||||
pmacs.lsp.filetypes.toml = pmacs.lsp.filetypes.toml or "toml"
|
||||
-- Zig (zls). `.zon` is Zig Object Notation, handled by the same server.
|
||||
pmacs.lsp.filetypes.zig = pmacs.lsp.filetypes.zig or "zig"
|
||||
pmacs.lsp.filetypes.zon = pmacs.lsp.filetypes.zon or "zig"
|
||||
|
||||
-- Per-buffer attachment record: { language, server, uri, version }.
|
||||
-- Keyed by `tostring(BufferIdLua)` because BufferIdLua hands out fresh
|
||||
|
|
|
|||
|
|
@ -4364,6 +4364,92 @@ fn m4_24_workspace_did_change_watched_files() {
|
|||
);
|
||||
}
|
||||
|
||||
/// Tier 1 single-binary language servers ship pre-configured in the
|
||||
/// default bundle. Binary-independent: we don't spawn anything, just
|
||||
/// assert the `pmacs.lsp.config` tables and the `pmacs.lsp.filetypes`
|
||||
/// extension→language map resolve to the documented values, so a user
|
||||
/// who installs `typescript-language-server` / `lua-language-server` /
|
||||
/// `bash-language-server` / `taplo` / `zls` gets attachment with no
|
||||
/// init.lua.
|
||||
#[test]
|
||||
fn m4_25_tier1_language_server_configs_and_filetypes() {
|
||||
use pmacs::editor::EditorState;
|
||||
|
||||
let s = EditorState::new();
|
||||
let probe: mlua::Table = s
|
||||
.lua_host
|
||||
.lua()
|
||||
.load(
|
||||
r#"
|
||||
local out = {}
|
||||
local c = pmacs.lsp.config
|
||||
local ft = pmacs.lsp.filetypes
|
||||
|
||||
-- TypeScript / JavaScript family: one binary, four language
|
||||
-- ids so didOpen reports the right one. --stdio transport.
|
||||
local tsjs_ok = true
|
||||
for _, lid in ipairs({ "typescript", "typescriptreact",
|
||||
"javascript", "javascriptreact" }) do
|
||||
local e = c[lid]
|
||||
if not (e and e.command == "typescript-language-server"
|
||||
and e.args and e.args[1] == "--stdio") then
|
||||
tsjs_ok = false
|
||||
end
|
||||
end
|
||||
out.tsjs = tsjs_ok
|
||||
|
||||
-- Lua: lua-language-server, no transport flag, settings.Lua
|
||||
-- present-not-null for the workspace/configuration pull.
|
||||
out.lua = c.lua ~= nil
|
||||
and c.lua.command == "lua-language-server"
|
||||
and type(c.lua.settings) == "table"
|
||||
and type(c.lua.settings.Lua) == "table"
|
||||
|
||||
-- Bash: bash-language-server start.
|
||||
out.bash = c.bash ~= nil
|
||||
and c.bash.command == "bash-language-server"
|
||||
and c.bash.args and c.bash.args[1] == "start"
|
||||
|
||||
-- TOML: taplo lsp stdio, settings.taplo present-not-null.
|
||||
out.toml = c.toml ~= nil
|
||||
and c.toml.command == "taplo"
|
||||
and c.toml.args and c.toml.args[1] == "lsp"
|
||||
and c.toml.args[2] == "stdio"
|
||||
and type(c.toml.settings) == "table"
|
||||
and type(c.toml.settings.taplo) == "table"
|
||||
|
||||
-- Zig: zls, no args.
|
||||
out.zig = c.zig ~= nil and c.zig.command == "zls"
|
||||
|
||||
-- Extension → language map.
|
||||
out.ft = ft.ts == "typescript"
|
||||
and ft.mts == "typescript"
|
||||
and ft.cts == "typescript"
|
||||
and ft.tsx == "typescriptreact"
|
||||
and ft.js == "javascript"
|
||||
and ft.mjs == "javascript"
|
||||
and ft.cjs == "javascript"
|
||||
and ft.jsx == "javascriptreact"
|
||||
and ft.sh == "bash"
|
||||
and ft.bash == "bash"
|
||||
and ft.toml == "toml"
|
||||
and ft.zig == "zig"
|
||||
and ft.zon == "zig"
|
||||
and ft.lua == "lua"
|
||||
|
||||
return out
|
||||
"#,
|
||||
)
|
||||
.eval()
|
||||
.expect("probe tier1 config + filetypes");
|
||||
assert!(probe.get::<bool>("tsjs").unwrap(), "ts/js family config");
|
||||
assert!(probe.get::<bool>("lua").unwrap(), "lua config");
|
||||
assert!(probe.get::<bool>("bash").unwrap(), "bash config");
|
||||
assert!(probe.get::<bool>("toml").unwrap(), "toml config");
|
||||
assert!(probe.get::<bool>("zig").unwrap(), "zig config");
|
||||
assert!(probe.get::<bool>("ft").unwrap(), "filetype map");
|
||||
}
|
||||
|
||||
/// Default LSP bundle (`builtin/runtime/lsp.lua`) is wired in: the
|
||||
/// hooks are defined, the namespace tables exist, the user-facing
|
||||
/// commands are registered with the command registry, and the default
|
||||
|
|
|
|||
Loading…
Reference in New Issue