fix(lsp): 解码百分号编码盘符后去掉前导分隔符
VS Code 发送 file:///d%3A/...,DecodeUri 只在字面冒号时去前导 /,解出 /d:/... 后 FindProject 失败,项目未采纳、索引 roots 落到工作区根,跨模块成员全部失去高亮与跳转。改为解码完成后判断盘符;gate10 增加百分号编码 rootUri 的回归断言。
This commit is contained in:
1 parent
e761a85ca7
commit
4770f57567
2 files changed
+48
-2
No files matched your search
@@ -136,8 +136,6 @@ def DecodeUri(pool: memhub.MemManager*, uri: str) -> str:
|
||||
p: str = uri
|
||||
if string.strncmp(uri, "file://", 7) == 0:
|
||||
p = uri + 7
|
||||
if p[0] == '/' and len(p) >= 3 and p[2] == ':':
|
||||
p = p + 1
|
||||
n: sizet = string.strlen(p)
|
||||
out: bytes = pool.alloc(n + 1)
|
||||
if out is None:
|
||||
@@ -158,6 +156,10 @@ def DecodeUri(pool: memhub.MemManager*, uri: str) -> str:
|
||||
o += 1
|
||||
i += 1
|
||||
out[o] = 0
|
||||
# VS Code sends the drive colon percent-encoded (file:///d%3A/...), so the leading
|
||||
# separator must be dropped after decoding, not before.
|
||||
if string.strncmp(uri, "file://", 7) == 0 and o >= 3 and out[0] == '/' and out[2] == ':':
|
||||
return str(out + 1)
|
||||
return str(out)
|
||||
|
||||
|
||||
|
||||
@@ -1765,6 +1765,50 @@ def gate10(exe: str) -> int:
|
||||
code = client.close()
|
||||
if code != 0:
|
||||
raise AssertionError(f"exit code is {code}, expected 0")
|
||||
|
||||
# VS Code's URI serializer percent-encodes the drive colon (file:///d%3A/...). A decoded
|
||||
# path starting with "/" prevents project adoption and leaves the index roots empty.
|
||||
def vscode_uri(path: Path) -> str:
|
||||
p = path.resolve().as_posix()
|
||||
if len(p) >= 2 and p[1] == ":":
|
||||
p = p[0].lower() + "%3A" + p[2:]
|
||||
return "file:///" + p
|
||||
|
||||
enc_client = Client(exe)
|
||||
enc_init = enc_client.request(
|
||||
"initialize",
|
||||
{"processId": os.getpid(), "rootUri": vscode_uri(workspace), "capabilities": {}},
|
||||
)
|
||||
if not isinstance(enc_init.get("result"), dict):
|
||||
raise AssertionError(f"encoded-URI initialize failed: {enc_init}")
|
||||
enc_client.notify("initialized", {})
|
||||
enc_client.notify(
|
||||
"textDocument/didOpen",
|
||||
{"textDocument": {"uri": vscode_uri(use_path), "languageId": "viper",
|
||||
"version": 1, "text": text}},
|
||||
)
|
||||
enc_client.wait_notification("textDocument/publishDiagnostics")
|
||||
enc_stats = enc_client.request("viper/lspStats").get("result") or {}
|
||||
enc_source = str(enc_stats.get("sourceDir") or "")
|
||||
if enc_source.startswith("/"):
|
||||
raise AssertionError(f"encoded URI root was not decoded: {enc_stats}")
|
||||
if Path(enc_source).resolve() != workspace.resolve():
|
||||
raise AssertionError(f"encoded URI sourceDir mismatch: {enc_stats}")
|
||||
enc_sem = enc_client.request(
|
||||
"textDocument/semanticTokens/full", {"textDocument": {"uri": vscode_uri(use_path)}},
|
||||
timeout=120.0,
|
||||
).get("result")
|
||||
if not isinstance(enc_sem, dict):
|
||||
raise AssertionError(f"encoded URI semanticTokens failed: {enc_sem}")
|
||||
enc_tokens = _decode_tokens(enc_sem.get("data", []))
|
||||
enc_pos = _position(text, "s.value")
|
||||
enc_pos["character"] += 2
|
||||
if not _find_token(enc_tokens, enc_pos["line"], enc_pos["character"], sem_types.index("property")):
|
||||
raise AssertionError(f"encoded URI lost cross-file member token: {enc_pos}")
|
||||
enc_client.request("shutdown")
|
||||
if enc_client.close() != 0:
|
||||
raise AssertionError("encoded URI client did not exit cleanly")
|
||||
|
||||
shutil.rmtree(workspace, ignore_errors=True)
|
||||
print("member-annotations: OK")
|
||||
print("member-module-chain: OK")
|
||||
|
||||
Reference in new issue
Block a user