fix: LSP tools Windows compatibility - use pathToFileURL for proper URI generation (#689)

This commit is contained in:
yimingll 2026-01-11 18:01:54 +08:00 committed by GitHub
parent 42e5b5bf44
commit 8ed3f7e03b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 14 additions and 11 deletions

View File

@ -1,6 +1,7 @@
import { spawn, type Subprocess } from "bun" import { spawn, type Subprocess } from "bun"
import { readFileSync } from "fs" import { readFileSync } from "fs"
import { extname, resolve } from "path" import { extname, resolve } from "path"
import { pathToFileURL } from "node:url"
import { getLanguageId } from "./config" import { getLanguageId } from "./config"
import type { Diagnostic, ResolvedServer } from "./types" import type { Diagnostic, ResolvedServer } from "./types"
@ -427,7 +428,7 @@ export class LSPClient {
} }
async initialize(): Promise<void> { async initialize(): Promise<void> {
const rootUri = `file://${this.root}` const rootUri = pathToFileURL(this.root).href
await this.send("initialize", { await this.send("initialize", {
processId: process.pid, processId: process.pid,
rootUri, rootUri,
@ -497,7 +498,7 @@ export class LSPClient {
this.notify("textDocument/didOpen", { this.notify("textDocument/didOpen", {
textDocument: { textDocument: {
uri: `file://${absPath}`, uri: pathToFileURL(absPath).href,
languageId, languageId,
version: 1, version: 1,
text, text,
@ -512,7 +513,7 @@ export class LSPClient {
const absPath = resolve(filePath) const absPath = resolve(filePath)
await this.openFile(absPath) await this.openFile(absPath)
return this.send("textDocument/hover", { return this.send("textDocument/hover", {
textDocument: { uri: `file://${absPath}` }, textDocument: { uri: pathToFileURL(absPath).href },
position: { line: line - 1, character }, position: { line: line - 1, character },
}) })
} }
@ -521,7 +522,7 @@ export class LSPClient {
const absPath = resolve(filePath) const absPath = resolve(filePath)
await this.openFile(absPath) await this.openFile(absPath)
return this.send("textDocument/definition", { return this.send("textDocument/definition", {
textDocument: { uri: `file://${absPath}` }, textDocument: { uri: pathToFileURL(absPath).href },
position: { line: line - 1, character }, position: { line: line - 1, character },
}) })
} }
@ -530,7 +531,7 @@ export class LSPClient {
const absPath = resolve(filePath) const absPath = resolve(filePath)
await this.openFile(absPath) await this.openFile(absPath)
return this.send("textDocument/references", { return this.send("textDocument/references", {
textDocument: { uri: `file://${absPath}` }, textDocument: { uri: pathToFileURL(absPath).href },
position: { line: line - 1, character }, position: { line: line - 1, character },
context: { includeDeclaration }, context: { includeDeclaration },
}) })
@ -540,7 +541,7 @@ export class LSPClient {
const absPath = resolve(filePath) const absPath = resolve(filePath)
await this.openFile(absPath) await this.openFile(absPath)
return this.send("textDocument/documentSymbol", { return this.send("textDocument/documentSymbol", {
textDocument: { uri: `file://${absPath}` }, textDocument: { uri: pathToFileURL(absPath).href },
}) })
} }
@ -550,7 +551,7 @@ export class LSPClient {
async diagnostics(filePath: string): Promise<{ items: Diagnostic[] }> { async diagnostics(filePath: string): Promise<{ items: Diagnostic[] }> {
const absPath = resolve(filePath) const absPath = resolve(filePath)
const uri = `file://${absPath}` const uri = pathToFileURL(absPath).href
await this.openFile(absPath) await this.openFile(absPath)
await new Promise((r) => setTimeout(r, 500)) await new Promise((r) => setTimeout(r, 500))
@ -571,7 +572,7 @@ export class LSPClient {
const absPath = resolve(filePath) const absPath = resolve(filePath)
await this.openFile(absPath) await this.openFile(absPath)
return this.send("textDocument/prepareRename", { return this.send("textDocument/prepareRename", {
textDocument: { uri: `file://${absPath}` }, textDocument: { uri: pathToFileURL(absPath).href },
position: { line: line - 1, character }, position: { line: line - 1, character },
}) })
} }
@ -580,7 +581,7 @@ export class LSPClient {
const absPath = resolve(filePath) const absPath = resolve(filePath)
await this.openFile(absPath) await this.openFile(absPath)
return this.send("textDocument/rename", { return this.send("textDocument/rename", {
textDocument: { uri: `file://${absPath}` }, textDocument: { uri: pathToFileURL(absPath).href },
position: { line: line - 1, character }, position: { line: line - 1, character },
newName, newName,
}) })
@ -597,7 +598,7 @@ export class LSPClient {
const absPath = resolve(filePath) const absPath = resolve(filePath)
await this.openFile(absPath) await this.openFile(absPath)
return this.send("textDocument/codeAction", { return this.send("textDocument/codeAction", {
textDocument: { uri: `file://${absPath}` }, textDocument: { uri: pathToFileURL(absPath).href },
range: { range: {
start: { line: startLine - 1, character: startChar }, start: { line: startLine - 1, character: startChar },
end: { line: endLine - 1, character: endChar }, end: { line: endLine - 1, character: endChar },

View File

@ -30,12 +30,14 @@ export function findWorkspaceRoot(filePath: string): string {
const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"] const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"]
while (dir !== "/") { let prevDir = ""
while (dir !== prevDir) {
for (const marker of markers) { for (const marker of markers) {
if (existsSync(require("path").join(dir, marker))) { if (existsSync(require("path").join(dir, marker))) {
return dir return dir
} }
} }
prevDir = dir
dir = require("path").dirname(dir) dir = require("path").dirname(dir)
} }