feat(lsp): 增加 UTF-16 位置往返验证
- viper/lspPosition:line/character -> offset -> line/character - probe Gate 1:随机 10k 个有效位置往返,覆盖 CRLF/中文/emoji
This commit is contained in:
1 parent
c42ae889d1
commit
93cd0f1ea5
2 files changed
+50
No files matched your search
@@ -198,6 +198,31 @@ def _HandleDocument(pool: memhub.MemManager*, tr: LspTransport.LspTransport*,
|
||||
return LspRpc.WriteResponse(pool, tr, id_node, result)
|
||||
|
||||
|
||||
def _HandlePosition(pool: memhub.MemManager*, tr: LspTransport.LspTransport*,
|
||||
docs: LspDocuments.LspDocuments*, id_node: json.JsonValue*,
|
||||
params: json.JsonValue*) -> int:
|
||||
uri: str = None
|
||||
if params is not None:
|
||||
uri = LspRpc.GetStringField(params, "uri")
|
||||
doc: LspDocuments.LspDocument* = docs.Find(uri)
|
||||
if doc is None or doc.index is None:
|
||||
return LspRpc.WriteResponse(pool, tr, id_node, json.null(pool))
|
||||
line: int = LspRpc.GetIntField(params, "line", 0)
|
||||
character: int = LspRpc.GetIntField(params, "character", 0)
|
||||
offset: sizet = doc.index.PositionToOffset(line, character)
|
||||
out_line: int = 0
|
||||
out_char: int = 0
|
||||
if doc.index.OffsetToPosition(offset, &out_line, &out_char) != 0:
|
||||
return -1
|
||||
result: json.JsonValue* = json.object(pool)
|
||||
if result is None:
|
||||
return -1
|
||||
json.object_set(pool, result, "offset", json.int_val(pool, int64(offset)))
|
||||
json.object_set(pool, result, "line", json.int_val(pool, int64(out_line)))
|
||||
json.object_set(pool, result, "character", json.int_val(pool, int64(out_char)))
|
||||
return LspRpc.WriteResponse(pool, tr, id_node, result)
|
||||
|
||||
|
||||
def Run(pool: memhub.MemBuddy*, perm_pool: memhub.MemBuddy*) -> int:
|
||||
os._mbuddy = perm_pool
|
||||
os._win32._mbuddy = perm_pool
|
||||
@@ -262,6 +287,8 @@ def Run(pool: memhub.MemBuddy*, perm_pool: memhub.MemBuddy*) -> int:
|
||||
rc = _HandleStats(pool, tr, docs, ws, id_node)
|
||||
elif string.strcmp(method, "viper/lspDocument") == 0:
|
||||
rc = _HandleDocument(pool, tr, docs, id_node, params)
|
||||
elif string.strcmp(method, "viper/lspPosition") == 0:
|
||||
rc = _HandlePosition(pool, tr, docs, id_node, params)
|
||||
elif string.strcmp(method, LspProtocol.LSP_METHOD_SHUTDOWN) == 0:
|
||||
shutdown_requested = 1
|
||||
rc = LspRpc.WriteResponse(pool, tr, id_node, json.null(pool))
|
||||
|
||||
@@ -7,6 +7,7 @@ import argparse
|
||||
import json
|
||||
import os
|
||||
import queue
|
||||
import random
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
@@ -181,6 +182,28 @@ def documents(exe: str) -> int:
|
||||
if not isinstance(doc, dict) or doc.get("text") != text or doc.get("version") != 1:
|
||||
raise AssertionError(f"initial document text/version mismatch: {doc}")
|
||||
|
||||
lines = text.splitlines()
|
||||
choices: list[tuple[int, int]] = []
|
||||
for line_no, line_text in enumerate(lines):
|
||||
offsets = [0]
|
||||
units = 0
|
||||
for ch in line_text:
|
||||
units += 2 if ord(ch) > 0xFFFF else 1
|
||||
offsets.append(units)
|
||||
for character in offsets:
|
||||
choices.append((line_no, character))
|
||||
random.seed(1234)
|
||||
for _ in range(10000):
|
||||
line_no, character = random.choice(choices)
|
||||
result = client.request(
|
||||
"viper/lspPosition",
|
||||
{"uri": uri, "line": line_no, "character": character},
|
||||
).get("result")
|
||||
if not isinstance(result, dict) or result.get("line") != line_no or result.get("character") != character:
|
||||
raise AssertionError(
|
||||
f"UTF-16 round-trip failed for ({line_no},{character}): {result}"
|
||||
)
|
||||
|
||||
client.notify(
|
||||
"textDocument/didChange",
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user