diff --git a/docs/21-language-service.md b/docs/21-language-service.md index 89178b8..3d19f78 100644 --- a/docs/21-language-service.md +++ b/docs/21-language-service.md @@ -164,7 +164,8 @@ name used in an expression is one only once P7 bound it. No query raises on a snapshot that stopped at any stage (`test_service_queries.py`). **Shared semantic indices.** A snapshot owns lazy declaration enumeration and -file grouping, shared by outline, workspace symbols and hover subjects. ID lookup +file grouping, shared by outline, workspace symbols, hover subjects and +effective-type code lenses. ID lookup populates separately on first hierarchy preparation/rebinding; the reverse map populates separately on first subtype request. It records direct `inherits` and `alias` edges, deduplicates repeated parents, and preserves child declaration order. diff --git a/fastraml/service/lenses.py b/fastraml/service/lenses.py index 509a072..4d15cb5 100644 --- a/fastraml/service/lenses.py +++ b/fastraml/service/lenses.py @@ -5,13 +5,13 @@ from dataclasses import dataclass from typing import TYPE_CHECKING -from fastraml.parser.fragments import every_declaration from fastraml.types.base import BaseShape from fastraml.views.render import render if TYPE_CHECKING: from fastraml.positions import Position from fastraml.registry import Raml + from fastraml.service.index import SemanticIndex from fastraml.service.workspace import Snapshot @@ -26,12 +26,13 @@ class EffectiveViews: __slots__ = ('by_site', 'by_uri') - def __init__(self, raml: Raml) -> None: + def __init__(self, raml: Raml, semantic: SemanticIndex) -> None: self.by_uri: dict[str, list[Lens]] = {} self.by_site: dict[tuple[str, int, int, str], BaseShape] = {} if not raml.unwrapped: return - for _, name, base in every_declaration(raml): + # The snapshot's one enumeration, shared with outline, hover and symbols. + for _, name, base in semantic.declarations: if not isinstance(base, BaseShape) or base.id in raml.broken: continue span = base.key_pos if base.key_pos.is_known else base.value_pos diff --git a/fastraml/service/workspace.py b/fastraml/service/workspace.py index 87a5f74..3097d76 100644 --- a/fastraml/service/workspace.py +++ b/fastraml/service/workspace.py @@ -130,8 +130,9 @@ def data(self) -> DataHover | None: @property def effective_views(self) -> EffectiveViews | None: - if self._effective_views is None and self.raml is not None: - self._effective_views = EffectiveViews(self.raml) + semantic = self.semantic + if self._effective_views is None and self.raml is not None and semantic is not None: + self._effective_views = EffectiveViews(self.raml, semantic) return self._effective_views @property diff --git a/tests/unit/test_service_indices.py b/tests/unit/test_service_indices.py index 1ca8495..d25623c 100644 --- a/tests/unit/test_service_indices.py +++ b/tests/unit/test_service_indices.py @@ -4,7 +4,7 @@ from fastraml.positions import Position from fastraml.service import index as index_module -from fastraml.service import inlays, outline, queries +from fastraml.service import inlays, lenses, outline, queries from fastraml.service.datahover import DataHover from fastraml.service.hover import Hover from tests.unit.test_service_data_hover import DOCUMENT @@ -36,6 +36,7 @@ def declarations(raml): assert first assert outline.document_symbols(snapshot, uri) is first queries.workspace_symbols([snapshot], 'Book') + assert lenses.code_lenses(snapshot, uri) assert snapshot.hover is not None assert enumerations == 1 assert snapshot.semantic is not None @@ -43,6 +44,16 @@ def declarations(raml): assert snapshot.semantic._children is None +def test_code_lenses_read_the_snapshots_shared_declaration_enumeration(memory_workspace): + workspace, folder = _buffered(memory_workspace, {'api.raml': API, 'lib.raml': LIBRARY, 'cover.raml': COVER}) + uri = f'{folder}/api.raml' + snapshot = workspace.snapshot(uri) + assert snapshot._semantic is None + assert [lens.name for lens in lenses.code_lenses(snapshot, uri)] == ['Entity', 'Book'] + assert snapshot._semantic is not None + assert snapshot._semantic._declarations is not None + + def test_typed_definition_before_hover_shares_one_data_population_without_presentation(memory_workspace, monkeypatch): workspace, folder = _buffered(memory_workspace, {'api.raml': DOCUMENT}) uri = f'{folder}/api.raml'