Skip to content

Commit 6bcaa22

Browse files
committed
perf(robotlangserver): Speedup keyword completion
Recalcution of useable keywords is only called if imports changed, this should speedup showing the completion window for keywords
1 parent 1c1cb9a commit 6bcaa22

File tree

3 files changed

+32
-13
lines changed

3 files changed

+32
-13
lines changed

robotcode/language_server/robotframework/diagnostics/library_doc.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ class KeywordStore:
518518
@property
519519
def _matchers(self) -> Dict[KeywordMatcher, KeywordDoc]:
520520
if not hasattr(self, "__matchers"):
521-
self.__matchers = {KeywordMatcher(v.name): v for v in self.keywords}
521+
self.__matchers = {v.matcher: v for v in self.keywords}
522522
return self.__matchers
523523

524524
def __getitem__(self, key: str) -> "KeywordDoc":
@@ -563,6 +563,9 @@ def keys(self) -> AbstractSet[str]:
563563
def values(self) -> AbstractSet[KeywordDoc]:
564564
return {v for v in self.keywords}
565565

566+
def __iter__(self) -> Iterator[KeywordDoc]:
567+
return self.keywords.__iter__()
568+
566569
def get(self, key: str, default: Optional[KeywordDoc] = None) -> Optional[KeywordDoc]:
567570
try:
568571
return self.__getitem__(key)

robotcode/language_server/robotframework/diagnostics/namespace.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -589,8 +589,9 @@ def __init__(
589589
self._keyword_references: Dict[KeywordDoc, Set[Location]] = {}
590590
self._variable_references: Dict[VariableDefinition, Set[Location]] = {}
591591

592+
self._imported_keywords: Optional[List[KeywordDoc]] = None
593+
self._imported_keywords_lock = Lock()
592594
self._keywords: Optional[List[KeywordDoc]] = None
593-
594595
self._keywords_lock = Lock()
595596

596597
# TODO: how to get the search order from model
@@ -673,6 +674,7 @@ async def _invalidate(self) -> None:
673674
self._imports = None
674675
self._import_entries = OrderedDict()
675676
self._own_variables = None
677+
self._imported_keywords = None
676678
self._keywords = None
677679
self._library_doc = None
678680
self._analyzed = False
@@ -766,6 +768,7 @@ class DataEntry(NamedTuple):
766768
variables: OrderedDict[str, VariablesEntry] = OrderedDict()
767769
diagnostics: List[Diagnostic] = []
768770
import_entries: OrderedDict[Import, LibraryEntry] = OrderedDict()
771+
imported_keywords: Optional[List[KeywordDoc]] = None
769772

770773
@_logger.call(condition=lambda self: not self._initialized)
771774
async def ensure_initialized(self) -> bool:
@@ -812,8 +815,10 @@ async def ensure_initialized(self) -> bool:
812815
self._variables = data_entry.variables.copy()
813816
self._diagnostics = data_entry.diagnostics.copy()
814817
self._import_entries = data_entry.import_entries.copy()
818+
self._imported_keywords = (
819+
data_entry.imported_keywords.copy() if data_entry.imported_keywords else None
820+
)
815821
else:
816-
817822
variables = await self.get_resolvable_variables()
818823

819824
await self._import_default_libraries(variables)
@@ -830,6 +835,7 @@ async def ensure_initialized(self) -> bool:
830835
self._variables.copy(),
831836
self._diagnostics.copy(),
832837
self._import_entries.copy(),
838+
self._imported_keywords.copy() if self._imported_keywords else None,
833839
),
834840
)
835841

@@ -1475,16 +1481,27 @@ async def get_imported_variables_libdoc(self, name: str, args: Tuple[str, ...] =
14751481
None,
14761482
)
14771483

1484+
async def get_imported_keywords(self) -> List[KeywordDoc]:
1485+
async with self._imported_keywords_lock:
1486+
if self._imported_keywords is None:
1487+
self._imported_keywords = list(
1488+
itertools.chain(
1489+
*(e.library_doc.keywords for e in self._libraries.values()),
1490+
*(e.library_doc.keywords for e in self._resources.values()),
1491+
)
1492+
)
1493+
1494+
return self._imported_keywords
1495+
14781496
@_logger.call
14791497
async def iter_all_keywords(self) -> AsyncGenerator[KeywordDoc, None]:
14801498
import itertools
14811499

14821500
libdoc = await self.get_library_doc()
14831501

14841502
for doc in itertools.chain(
1485-
*(e.library_doc.keywords.values() for e in self._libraries.values()),
1486-
*(e.library_doc.keywords.values() for e in self._resources.values()),
1487-
libdoc.keywords.values() if libdoc is not None else [],
1503+
await self.get_imported_keywords(),
1504+
libdoc.keywords if libdoc is not None else [],
14881505
):
14891506
yield doc
14901507

@@ -1504,10 +1521,13 @@ async def get_keywords(self) -> List[KeywordDoc]:
15041521

15051522
async for doc in self.iter_all_keywords():
15061523
i += 1
1507-
result[KeywordMatcher(doc.name)] = doc
1524+
result[doc.matcher] = doc
15081525

15091526
self._keywords = list(result.values())
1510-
finally:
1527+
except BaseException:
1528+
self._logger.debug("Canceled collecting keywords ")
1529+
raise
1530+
else:
15111531
self._logger.debug(
15121532
lambda: f"end collecting {len(self._keywords) if self._keywords else 0}"
15131533
f" keywords in {time.monotonic()-current_time}s analyze {i} keywords"

robotcode/language_server/robotframework/parts/semantic_tokens.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -403,11 +403,7 @@ async def generate_sem_sub_tokens(
403403

404404
if builtin_library_doc is not None and kw in builtin_library_doc.keywords:
405405
doc = await namespace.find_keyword(token.value)
406-
if (
407-
doc is not None
408-
and doc.libname == cls.BUILTIN_MATCHER
409-
and KeywordMatcher(doc.name) == KeywordMatcher(kw)
410-
):
406+
if doc is not None and doc.libname == cls.BUILTIN_MATCHER and doc.matcher == kw:
411407
if not sem_mod:
412408
sem_mod = set()
413409
sem_mod.add(RobotSemTokenModifiers.BUILTIN)

0 commit comments

Comments
 (0)