瀏覽代碼

fix(lsp): preserve POSIX backslash paths

Tianyi Cui 2 月之前
父節點
當前提交
f61a4943bd
共有 2 個文件被更改,包括 8 次插入 和 3 次删除
  1. 3 2
      packages/lsp/tool-lsp/src/render.ts
  2. 5 1
      packages/lsp/tool-lsp/tests/render.spec.ts

+ 3 - 2
packages/lsp/tool-lsp/src/render.ts

@@ -149,6 +149,7 @@ export function renderUri(uri: string, workspaceUri: string): string {
   if (targetSegments === undefined || workspaceSegments === undefined) return uri
   const sameAuthority = target.hostname === workspace.hostname
   const windowsWorld = isWindowsFileWorld(workspace, workspaceSegments)
+  if (windowsWorld && [...targetSegments, ...workspaceSegments].some(segment => segment.includes('\\'))) return uri
   const inside = sameAuthority
     && targetSegments.length >= workspaceSegments.length
     && workspaceSegments.every((segment, index) => samePathSegment(segment, targetSegments[index] as string, windowsWorld))
@@ -164,11 +165,11 @@ function isWindowsFileWorld(url: URL, segments: readonly string[]): boolean {
   return url.hostname.length > 0 || /^[A-Za-z]:$/.test(segments[0] ?? '')
 }
 
-/** Decode URI path segments while rejecting encoded separators that would change path structure. */
+/** Decode URI path segments while rejecting encoded POSIX separators and NUL. */
 function decodeFileSegments(url: URL): string[] | undefined {
   try {
     const decoded = url.pathname.split('/').map(segment => decodeURIComponent(segment))
-    if (decoded.some(segment => /[/\\\0]/u.test(segment))) return undefined
+    if (decoded.some(segment => /[/\0]/u.test(segment))) return undefined
     while (decoded.at(-1) === '') decoded.pop()
     decoded.shift()
     return decoded

+ 5 - 1
packages/lsp/tool-lsp/tests/render.spec.ts

@@ -82,11 +82,15 @@ describe('renderUri', () => {
     expect(renderUri('file:///a.ts', 'file:///')).toBe('a.ts')
   })
 
+  it('preserves backslashes as ordinary POSIX filename characters', () => {
+    expect(renderUri('file:///home/u/proj/dir%5Cname/a.ts', WS_URI)).toBe('dir\\name/a.ts')
+  })
+
   it('keeps malformed or mismatched URI coordinates verbatim', () => {
     expect(renderUri('file://[', WS_URI)).toBe('file://[')
     expect(renderUri('file:///a.ts', 'https://example.com/workspace')).toBe('file:///a.ts')
     expect(renderUri('file:///a.ts', 'file:///bad%ZZ')).toBe('file:///a.ts')
-    expect(renderUri('file:///bad%5Cpath', WS_URI)).toBe('file:///bad%5Cpath')
+    expect(renderUri('file:///C:/workspace/bad%5Cpath', 'file:///C:/workspace')).toBe('file:///C:/workspace/bad%5Cpath')
     expect(renderUri('file:///short', 'file:///short/deeper')).toBe('/short')
     expect(renderUri('file:///', 'file:///C:/workspace')).toBe('/')
   })