Skip to content

Outside VS Code

Joël Deffner edited this page Aug 11, 2026 · 1 revision

Outside VS Code

The language server is standard LSP over --stdio. Everything that is not a webview works from neovim, Zed, Helix or any other LSP client, and the server can be embedded in your own application.

This page is the orientation. The setup reference that ships with the server and is updated alongside it is packages/server/README.md.

What you get

Ranked completion, hover docs, go-to-definition, find references, rename, document and workspace symbols, folding, formatting, semantic tokens, inlay hints, and the structural and localization diagnostics, for all three games.

Hovers, code actions and logging adapt to the client automatically. A plain LSP client gets clean markdown (no VS Code markup, no dead command: links), real WorkspaceEdit quick fixes rather than editor-command actions it cannot run, server-side file watching via workspace/didChangeWatchedFiles dynamic registration, and a window/logMessage status mirror. Nothing has to be configured for that; do not declare the client capability flags, they are how the VS Code client announces itself.

What stays VS Code only: tiger diagnostics, the webview UIs (Project dashboard, event graph, event simulator, GUI widget tree, GUI Editor, mod report) and the DDS texture previews.

Install

Grab an artifact from the releases page:

  • px-lsp-server-<version>.tar.gz needs Node.js 18+ on your PATH.
  • px-lsp-win-x64-<version>.zip is the same payload plus an unmodified official Node build and a px-lsp.cmd launcher, so nothing has to be installed first. Point your client at px-lsp.cmd and pass no arguments.

Extract it anywhere and do not flatten it. The server finds its bundled data at ../data/<gameId>/ relative to dist/server.js, so dist/ and data/ must stay siblings. A lone server.js still starts and still answers requests, it just silently loses the bundled wiki tokens and the completion frequency tables; the startup log line tells you which of the two you have.

Wiring it up

Three things to get right, and they are the three things that go wrong:

1. Filetypes. Paradox script is plain .txt and localization is plain .yml, so your editor has to be told which files are which. The three language ids are paradox, paradox-loc and paradox-gui. If a file opens with no diagnostics, no highlighting and an empty completion popup, check its filetype first: a .txt that stayed text never reaches the server at all.

2. The mod root. Root markers should be descriptor.mod (CK3) or .metadata (Victoria 3, EU5). If they never match, the server falls back to the first workspace folder, and workspace-mod-only features (reference diagnostics, required-localization checks, the loc quick fix) stay silent because the file belongs to no known mod.

EU5 is the trap here: its content lives under a load-stage folder (in_game/, main_menu/, loading_screen/), but the mod root is still the folder holding .metadata/. Keep the root there, not on in_game/.

3. The game. The server serves one game per instance and there is no auto-detection outside VS Code: set gameId explicitly to "ck3" (the default), "vic3" or "eu5". gamePath and logsPath then describe that game, and Vic3 and EU5 write their script_docs to docs/, not logs/. See Supported Games.

Initialization options mirror the VS Code settings: gameId, gamePath, logsPath, locLanguage, parentPaths, diagnosticsIgnore, diagnosticsIgnorePatterns, scopeInlayHints.

A copy-paste neovim configuration (0.11+, with a note for 0.10) is in the server README. It was verified hands-on against neovim 0.12 on a real mod; the committed parity harness in scripts/nvim-parity/ re-checks it.

Dump your own game data

More important here than in VS Code. CK3 ships bundled wiki tables and a dump snapshot, Victoria 3 ships a dump snapshot, EU5 ships neither yet. So on EU5 the difference between a working index and a thin list of your own definitions is your own dump.

Launch with -debug_mode, run script_docs in the console, point logsPath at the dump folder, and restart the server.

Embedding the server in an application

Wiring the server into a mod manager or a custom editor is a supported, documented path, and a different job from configuring an editor:

  • docs/EMBEDDING.md covers the process contract, the initialization options an application should send, and URI and document-sync conventions.
  • docs/PROTOCOL.md is the method-by-method reference for the custom paradox/* requests beyond standard LSP: the mod overview, the event graph and event detail, GUI layout and the paradox/guiSourceEdit writer, scope inference. A plain editor client can ignore all of them.

The npm packages are @px-lsp/server (the server, with its bundled per-game data) and @px-lsp/protocol (the wire contract, payload types, settings shapes and pure helpers, with zero dependencies and no vscode import).

Clone this wiki locally