fix(lsp): 别名点号导入逐段高亮

import a.b.c as x 的路径段先于别名写入出现点,避免顺序倒置被丢弃;模块路径段即使解析不到模块也保持 namespace,便于识别缺失依赖。
This commit is contained in:
TermiNexus committed 2026-10-27 13:03:26 +08:00
1 parent b38d103c17
commit c268e5a9c0
4 files changed
+39 -5

No files matched your search

+8 -4
View File
@@ -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
+5 -1
View File
@@ -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
+2
View File
@@ -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:
+24
View File
@@ -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