fix(daemon): launch LSP servers with caller env
This commit is contained in:
@@ -16,8 +16,8 @@ import { ServerNotFoundError } from "./types.ts";
|
||||
import { findRoot, pathToUri, uriToPath } from "./root.ts";
|
||||
|
||||
// Is On PATH - Returns true if `cmd` resolves to an executable via the
|
||||
// current PATH. Absolute/relative paths are checked directly.
|
||||
function isOnPath(cmd: string): boolean {
|
||||
// supplied PATH. Absolute/relative paths are checked directly.
|
||||
function isOnPath(cmd: string, env: NodeJS.ProcessEnv): boolean {
|
||||
const isExec = (p: string) => {
|
||||
try {
|
||||
fs.accessSync(p, fs.constants.X_OK);
|
||||
@@ -29,9 +29,9 @@ function isOnPath(cmd: string): boolean {
|
||||
if (cmd.includes(path.sep)) return isExec(cmd);
|
||||
const exts =
|
||||
process.platform === "win32"
|
||||
? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";")
|
||||
? (env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";")
|
||||
: [""];
|
||||
for (const dir of (process.env.PATH ?? "").split(path.delimiter)) {
|
||||
for (const dir of (env.PATH ?? "").split(path.delimiter)) {
|
||||
if (!dir) continue;
|
||||
for (const ext of exts) {
|
||||
if (isExec(path.join(dir, cmd + ext))) return true;
|
||||
@@ -69,16 +69,17 @@ export class LspClient {
|
||||
constructor(private readonly server: ServerConfig) {}
|
||||
|
||||
// Start - Spawns the server process and wires up JSON-RPC.
|
||||
async start(rootDir: string): Promise<void> {
|
||||
async start(rootDir: string, env: NodeJS.ProcessEnv): Promise<void> {
|
||||
// Verify Binary On PATH - Fail fast with a clear message instead of
|
||||
// letting spawn ENOENT surface as a generic error. It's the user's
|
||||
// responsibility to have the server installed & on PATH.
|
||||
if (!isOnPath(this.server.command)) {
|
||||
// letting spawn ENOENT surface as a generic error. Resolution uses the
|
||||
// caller/session env, not the daemon's launch-time env.
|
||||
if (!isOnPath(this.server.command, env)) {
|
||||
throw new ServerNotFoundError(this.server.command);
|
||||
}
|
||||
this.proc = spawn(this.server.command, this.server.args, {
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
cwd: rootDir,
|
||||
env,
|
||||
});
|
||||
this.proc.on("error", (err) => {
|
||||
process.stderr.write(
|
||||
@@ -277,10 +278,11 @@ export class LspClient {
|
||||
export async function startClientForFile(
|
||||
server: ServerConfig,
|
||||
filePath: string,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): Promise<{ client: LspClient; uri: string; rootDir: string }> {
|
||||
const rootDir = findRoot(filePath, server.rootMarkers);
|
||||
const client = new LspClient(server);
|
||||
await client.start(rootDir);
|
||||
await client.start(rootDir, env);
|
||||
const uri = client.openDocument(filePath);
|
||||
// Wait For Workspace Load - gopls & friends reject requests with errors
|
||||
// like "no views" until their initial load completes.
|
||||
|
||||
Reference in New Issue
Block a user