slang-server 0.3.1: .slang/server.json is read from the LSP rootUri, and custom commands go through workspace/executeCommand
Symptom: an editor using slang-server (hudson-trading slang LSP) ignores the project's .slang/server.json {"build": "design.f"}, so the design isn't elaborated and hierarchy queries return nothing.
Cause: slang-server loads .slang/server.json only from the workspace root it receives in initialize (rootUri / workspaceFolders), not from the file's folder or the process cwd. If the client roots the session at the open file's parent dir (e.g. proj/rtl/), it never sees proj/.slang/server.json. Its log prints 'Server initialized at <root>', which tells you which root it used.
Debugging tip: speak LSP to it directly with a small Python stdio client: initialize with rootUri, initialized, didOpen, then workspace/executeCommand with command 'slang.getScope' and arguments [""]. That returns the elaborated top instances. Calling 'slang.getScope' as a bare JSON-RPC method returns 'not found'; the custom commands (getScope, getInstancesOfModule, setTopLevel, setBuildFile, getFilesContainingModule, ...) are only reachable through executeCommand. slang.getInstancesOfModule ["cpu"] returns instPath values like top.dut.
Build-file gotchas: +define+X=\"path\" needs the backslash-escaped quotes kept in the .f; shells and heredocs strip them, and you get confusing parse errors such as 'expected endclass'. Vendor system tasks ($fsdbDumpvars) need -Wno-unknown-sys-name.
Waveform-mapping gotcha: when you map design paths to dump paths by signal-name overlap, a testbench top that has its own clk/rst overlaps a small DUT's names. Keep descending below a scope that meets the overlap threshold but lacks the path, or the DUT is never found.
Confirmed on Linux with the slang-server v0.3.1 release binary, driven by a small Python stdio client. Project: proj/.slang/server.json {"build": "design.f"}, with rtl/cpu.sv and rtl/top.sv (top instantiates cpu as dut). With rootUri=proj, workspace/executeCommand slang.getScope [""] returned the top instance, and slang.getInstancesOfModule ["cpu"] returned instPath "top.dut". With rootUri=proj/rtl, the same didOpen of top.sv gave [] for both. stderr printed 'Server initialized at /tmp/r5/sl/proj' (stderr, not window/logMessage). One precision on the bare method: calling
slang.getScopedirectly got no JSON-RPC response at all within 15 s. The server only logged 'WARN: <-/- slang.getScope (not found)' to stderr and never sent an error reply (LSP expects -32601), so a client awaiting that id just hangs. Use a request timeout in debugging clients, and read the server's stderr.