fix(lsp): 别名点号导入逐段高亮
import a.b.c as x 的路径段先于别名写入出现点,避免顺序倒置被丢弃;模块路径段即使解析不到模块也保持 namespace,便于识别缺失依赖。
This commit is contained in:
1 parent
b38d103c17
commit
c268e5a9c0
4 files changed
+39
-5
No files matched your search
@@ -287,10 +287,14 @@ def _TokenForOcc(ctx: LspSemCtx*, pool: memhub.MemManager*,
|
||||
typ = _TypeForTarget(tw)
|
||||
mods = _ModsForTarget(tw)
|
||||
if typ < 0:
|
||||
# Builtin type names have no declaration; color them like class types.
|
||||
if o.builtin_type == 0:
|
||||
return None
|
||||
typ = ST_CLASS
|
||||
if o.module_path != 0:
|
||||
# Dotted import segments stay namespaced even when the module cannot be found.
|
||||
typ = ST_NAMESPACE
|
||||
else:
|
||||
# Builtin type names have no declaration; color them like class types.
|
||||
if o.builtin_type == 0:
|
||||
return None
|
||||
typ = ST_CLASS
|
||||
tok: LspSemToken* = _NewTok(pool, o.line, o.sc, o.line, o.ec, typ)
|
||||
if tok is not None:
|
||||
tok.mods = mods
|
||||
|
||||
@@ -93,6 +93,8 @@ class LspOccurrence:
|
||||
force_module: int
|
||||
# 1 when the name is an unresolved builtin type (int/str/list/...), 0 otherwise.
|
||||
builtin_type: int
|
||||
# 1 for a segment of a dotted module path (always a namespace, even when the module is absent).
|
||||
module_path: int
|
||||
|
||||
def __new__(self, pool: memhub.MemManager*) -> rawptr:
|
||||
p: LspOccurrence* = (LspOccurrence*)(pool.alloc(LspOccurrence.__sizeof__()))
|
||||
@@ -954,6 +956,7 @@ def _AddModulePathOccs(pool: memhub.MemManager*, a: LspAnalysis*, scope: LspScop
|
||||
o: LspOccurrence* = _AddOcc(pool, a, scope, name, lineno, col + start,
|
||||
int(string.strlen(name)), ast.ASTCtx.Load, 0)
|
||||
if o is not None:
|
||||
o.module_path = 1
|
||||
if start == 0:
|
||||
o.sym = head
|
||||
o.head = head
|
||||
@@ -1260,11 +1263,12 @@ def _WalkStmt(pool: memhub.MemManager*, a: LspAnalysis*, scope: LspScope*,
|
||||
if sym is not None:
|
||||
sym.import_kind = LSP_IMPORT_MODULE
|
||||
sym.import_mod = bound_mod
|
||||
_DeclImportOcc(pool, a, scope, al, bound, sym)
|
||||
if al.asname is not None:
|
||||
_AddModulePathOccs(pool, a, scope, al.lineno, al.col_offset,
|
||||
al.name, 0, 0, None)
|
||||
_DeclImportOcc(pool, a, scope, al, bound, sym)
|
||||
else:
|
||||
_DeclImportOcc(pool, a, scope, al, bound, sym)
|
||||
_AddModulePathOccs(pool, a, scope, al.lineno, al.col_offset,
|
||||
al.name, 0, 1, sym)
|
||||
i += 1
|
||||
|
||||
@@ -5,6 +5,8 @@ from .gate10_stub import StubThing
|
||||
from .gate10_extra import *
|
||||
import gate10_types
|
||||
import gate10_pkg.sub.mod
|
||||
import gate10_pkg.sub as pkgsub
|
||||
import ghost_lib.path
|
||||
|
||||
|
||||
def star_use(e: Extra) -> int:
|
||||
|
||||
@@ -1545,6 +1545,30 @@ def gate10(exe: str) -> int:
|
||||
if not got.endswith(suffix):
|
||||
raise AssertionError(f"dotted import definition target is wrong: {pos} -> {got}")
|
||||
|
||||
alias_line = _position(text, "import gate10_pkg.sub as pkgsub")
|
||||
for delta, segment in ((7, "gate10_pkg"), (18, "sub"), (25, "pkgsub")):
|
||||
pos = {"line": alias_line["line"], "character": alias_line["character"] + delta}
|
||||
if not _find_token(sem_tokens, pos["line"], pos["character"],
|
||||
sem_types.index("namespace")):
|
||||
raise AssertionError(f"aliased dotted import is not highlighted: {segment} {pos}")
|
||||
alias_sub = {"line": alias_line["line"], "character": alias_line["character"] + 18}
|
||||
alias_def = client.request(
|
||||
"textDocument/definition",
|
||||
{"textDocument": {"uri": uri}, "position": alias_sub},
|
||||
timeout=120.0,
|
||||
).get("result")
|
||||
if not isinstance(alias_def, list) or not alias_def:
|
||||
raise AssertionError(f"aliased dotted import definition failed: {alias_def}")
|
||||
if not alias_def[0]["uri"].replace("\\", "/").endswith("gate10_pkg/sub/__init__.vp"):
|
||||
raise AssertionError(f"aliased dotted import target is wrong: {alias_def}")
|
||||
|
||||
ghost_line = _position(text, "import ghost_lib.path")
|
||||
for delta, segment in ((7, "ghost_lib"), (17, "path")):
|
||||
pos = {"line": ghost_line["line"], "character": ghost_line["character"] + delta}
|
||||
if not _find_token(sem_tokens, pos["line"], pos["character"],
|
||||
sem_types.index("namespace")):
|
||||
raise AssertionError(f"unresolved module path is not highlighted: {segment} {pos}")
|
||||
|
||||
def at(needle: str, delta: int = 0, occurrence: int = 0) -> dict[str, int]:
|
||||
pos = _position(text, needle, occurrence)
|
||||
pos["character"] += delta
|
||||
|
||||
Reference in new issue
Block a user