Skip to content

Commit 598dc9a

Browse files
committed
enhance BDD handling for RF 5.1
1 parent 126af22 commit 598dc9a

File tree

18 files changed

+248
-130
lines changed

18 files changed

+248
-130
lines changed

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,11 @@
163163
],
164164
"error": [
165165
"invalid.illegal.robotframework"
166+
],
167+
"config": [
168+
"comment.line.configuration.robotframework"
166169
]
170+
167171
}
168172
}
169173
],

robotcode/language_server/common/parts/diagnostics.py

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def extend_capabilities(self, capabilities: ServerCapabilities) -> None:
108108
)
109109

110110
@async_tasking_event_iterator
111-
async def collect(sender, document: TextDocument, full: bool) -> DiagnosticsResult: # NOSONAR
111+
async def collect(sender, document: TextDocument) -> DiagnosticsResult: # NOSONAR
112112
...
113113

114114
@async_tasking_event
@@ -150,39 +150,15 @@ async def ensure_workspace_loaded(self) -> None:
150150
await self.on_workspace_loaded(self)
151151

152152
async def get_document_diagnostics(self, document: TextDocument) -> RelatedFullDocumentDiagnosticReport:
153-
# if self.collect_full_diagnostics:
154-
return await document.get_cache(self.__get_full_document_diagnostics)
155-
# return await document.get_cache(self.__get_document_diagnostics)
153+
return await document.get_cache(self.__get_document_diagnostics)
156154

157155
async def __get_document_diagnostics(self, document: TextDocument) -> RelatedFullDocumentDiagnosticReport:
158156
await self.ensure_workspace_loaded()
159157

160158
diagnostics: List[Diagnostic] = []
161159

162160
async for result_any in self.collect(
163-
self,
164-
document,
165-
full=False,
166-
callback_filter=language_id_filter(document),
167-
return_exceptions=True,
168-
):
169-
result = cast(DiagnosticsResult, result_any)
170-
171-
if isinstance(result, BaseException):
172-
if not isinstance(result, asyncio.CancelledError):
173-
self._logger.exception(result, exc_info=result)
174-
else:
175-
diagnostics.extend(result.diagnostics or [])
176-
177-
return RelatedFullDocumentDiagnosticReport(items=diagnostics, result_id=str(uuid.uuid4()))
178-
179-
async def __get_full_document_diagnostics(self, document: TextDocument) -> RelatedFullDocumentDiagnosticReport:
180-
await self.ensure_workspace_loaded()
181-
182-
diagnostics: List[Diagnostic] = []
183-
184-
async for result_any in self.collect(
185-
self, document, full=True, callback_filter=language_id_filter(document), return_exceptions=True
161+
self, document, callback_filter=language_id_filter(document), return_exceptions=True
186162
):
187163
result = cast(DiagnosticsResult, result_any)
188164

@@ -289,6 +265,9 @@ async def _get_partial_diagnostics() -> WorkspaceDiagnosticReport:
289265
) as progress:
290266

291267
async def _task(doc: TextDocument) -> None:
268+
if doc.opened_in_editor:
269+
return
270+
292271
if await self.get_analysis_progress_mode(doc.uri) == AnalysisProgressMode.DETAILED:
293272
path = doc.uri.to_path()
294273
folder = self.parent.workspace.get_workspace_folder(doc.uri)

robotcode/language_server/common/parts/workspace.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
)
2525

2626
from ....jsonrpc2.protocol import rpc_method
27-
from ....utils.async_cache import AsyncSimpleLRUCache
2827
from ....utils.async_tools import (
2928
Lock,
3029
async_event,
@@ -162,7 +161,6 @@ def __init__(
162161
self._file_watchers_lock = Lock()
163162

164163
self.parent.on_shutdown.add(self._on_shutdown)
165-
self._config_cache = AsyncSimpleLRUCache(max_items=1000)
166164

167165
@property
168166
def workspace_folders(self) -> List[WorkspaceFolder]:
@@ -239,7 +237,6 @@ async def did_change_configuration(sender, settings: Dict[str, Any]) -> None: #
239237
@rpc_method(name="workspace/didChangeConfiguration", param_type=DidChangeConfigurationParams)
240238
@_logger.call
241239
async def _workspace_did_change_configuration(self, settings: Dict[str, Any], *args: Any, **kwargs: Any) -> None:
242-
await self._config_cache.clear()
243240
self.settings = settings
244241
await self.did_change_configuration(self, settings)
245242

@@ -315,10 +312,6 @@ async def _workspace_did_delete_files(self, files: List[FileDelete], *args: Any,
315312
await self.did_delete_files(self, list(f.uri for f in files))
316313

317314
async def get_configuration(self, section: Type[_TConfig], scope_uri: Union[str, Uri, None] = None) -> _TConfig:
318-
return await self._config_cache.get(self._get_configuration, section, scope_uri)
319-
320-
async def _get_configuration(self, section: Type[_TConfig], scope_uri: Union[str, Uri, None] = None) -> _TConfig:
321-
322315
config = await self.get_configuration_raw(
323316
section=cast(HasConfigSection, section).__config_section__, scope_uri=scope_uri
324317
)
@@ -328,6 +321,7 @@ async def _get_configuration(self, section: Type[_TConfig], scope_uri: Union[str
328321
async def get_configuration_raw(
329322
self, section: Optional[str], scope_uri: Union[str, Uri, None] = None
330323
) -> Optional[Any]:
324+
331325
if (
332326
self.parent.client_capabilities
333327
and self.parent.client_capabilities.workspace

robotcode/language_server/robotframework/diagnostics/analyzer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ async def _analyze_keyword_call(
306306
if not allow_variables and not is_not_variable_token(keyword_token):
307307
return None
308308

309-
keyword_token = self.strip_bdd_prefix(keyword_token)
309+
keyword_token = self.strip_bdd_prefix(self.namespace, keyword_token)
310310
kw_range = range_from_token(keyword_token)
311311

312312
if keyword is not None:

robotcode/language_server/robotframework/diagnostics/library_doc.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,6 @@ class ArgumentSpec:
245245
defaults: Any
246246
types: Any
247247

248-
__robot_arguments: Optional[Any] = field(default=None, compare=False)
249-
250248
@staticmethod
251249
def from_robot_argument_spec(spec: Any) -> ArgumentSpec:
252250
return ArgumentSpec(
@@ -274,7 +272,7 @@ def resolve(
274272
ArgumentSpec as RobotArgumentSpec,
275273
)
276274

277-
if self.__robot_arguments is None:
275+
if not hasattr(self, "__robot_arguments"):
278276
self.__robot_arguments = RobotArgumentSpec(
279277
self.name,
280278
self.type,
@@ -317,7 +315,9 @@ class KeywordDoc(SourceEntity):
317315
args_to_process: Optional[int] = field(default=None, compare=False)
318316
deprecated: bool = field(default=False, compare=False)
319317
arguments: Optional[ArgumentSpec] = field(default=None, compare=False)
320-
argument_definitions: Optional[List[ArgumentDefinition]] = field(default=None, compare=False)
318+
argument_definitions: Optional[List[ArgumentDefinition]] = field(
319+
default=None, compare=False, repr=False, hash=False
320+
)
321321

322322
def __str__(self) -> str:
323323
return f"{self.name}({', '.join(str(arg) for arg in self.args)})"
@@ -476,11 +476,9 @@ class KeywordStore:
476476
source_type: Optional[str] = None
477477
keywords: List[KeywordDoc] = field(default_factory=list)
478478

479-
__matchers: Optional[Dict[KeywordMatcher, KeywordDoc]] = None
480-
481479
@property
482480
def _matchers(self) -> Dict[KeywordMatcher, KeywordDoc]:
483-
if self.__matchers is None:
481+
if not hasattr(self, "__matchers"):
484482
self.__matchers = {KeywordMatcher(v.name): v for v in self.keywords}
485483
return self.__matchers
486484

robotcode/language_server/robotframework/diagnostics/namespace.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
Range,
4242
)
4343
from ...common.text_document import TextDocument
44+
from ..languages import Languages
4445
from ..utils.ast_utils import (
4546
Token,
4647
range_from_node,
@@ -51,6 +52,7 @@
5152
from ..utils.async_ast import AsyncVisitor
5253
from ..utils.match import eq
5354
from ..utils.variables import BUILTIN_VARIABLES
55+
from ..utils.version import get_robot_version
5456
from .entities import (
5557
ArgumentDefinition,
5658
BuiltInVariableDefinition,
@@ -547,6 +549,7 @@ def __init__(
547549
invalidated_callback: Callable[[Namespace], None],
548550
document: Optional[TextDocument] = None,
549551
document_type: Optional[DocumentType] = None,
552+
languages: Optional[Languages] = None,
550553
) -> None:
551554
super().__init__()
552555

@@ -557,6 +560,7 @@ def __init__(
557560
self.invalidated_callback = invalidated_callback
558561
self._document = weakref.ref(document) if document is not None else None
559562
self.document_type: Optional[DocumentType] = document_type
563+
self.languages = languages
560564

561565
self._libraries: OrderedDict[str, LibraryEntry] = OrderedDict()
562566
self._libraries_matchers: Optional[Dict[KeywordMatcher, LibraryEntry]] = None
@@ -1769,9 +1773,22 @@ def _create_custom_and_standard_keyword_conflict_warning_message(
17691773
)
17701774

17711775
async def _get_bdd_style_keyword(self, name: str) -> Optional[KeywordDoc]:
1772-
lower = name.lower()
1773-
for prefix in ["given ", "when ", "then ", "and ", "but "]:
1774-
if lower.startswith(prefix):
1775-
return await self._find_keyword(name[len(prefix) :]) # noqa: E203
1776+
if get_robot_version() < (5, 1):
1777+
lower = name.lower()
1778+
for prefix in ["given ", "when ", "then ", "and ", "but "]:
1779+
if lower.startswith(prefix):
1780+
return await self._find_keyword(name[len(prefix) :]) # noqa: E203
1781+
return None
17761782

1777-
return None
1783+
else:
1784+
parts = name.split(maxsplit=1)
1785+
if len(parts) < 2:
1786+
return None
1787+
prefix, keyword = parts
1788+
if prefix.title() in (
1789+
self.namespace.languages.bdd_prefixes
1790+
if self.namespace.languages is not None
1791+
else {"Given ", "When ", "Then ", "And ", "But "}
1792+
):
1793+
return await self._find_keyword(keyword)
1794+
return None
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from typing import Any, Dict, Iterator, List, Protocol, Set, runtime_checkable
2+
3+
4+
@runtime_checkable
5+
class Languages(Protocol):
6+
languages: List[Any]
7+
headers: Dict[str, str]
8+
settings: Dict[str, str]
9+
bdd_prefixes: Set[str]
10+
11+
def add_language(self, name: str) -> None:
12+
...
13+
14+
def __iter__(self) -> Iterator[Any]:
15+
...

robotcode/language_server/robotframework/parts/completion.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,7 @@ async def _complete_TestCase_or_Keyword( # noqa: N802
915915
if len(statement_node.tokens) > index:
916916
token = statement_node.tokens[index]
917917

918-
token = self.strip_bdd_prefix(token)
918+
token = self.strip_bdd_prefix(self.namespace, token)
919919

920920
r = range_from_token(token)
921921
if position.is_in_range(r):
@@ -930,7 +930,11 @@ async def _complete_TestCase_or_Keyword( # noqa: N802
930930
r.end.character += 1
931931
if position.is_in_range(r):
932932
return await create_items(
933-
in_assign, in_template, r, None if self.is_bdd_token(token) else token, position
933+
in_assign,
934+
in_template,
935+
r,
936+
None if self.is_bdd_token(self.namespace, token) else token,
937+
position,
934938
)
935939

936940
return None
@@ -1052,12 +1056,12 @@ async def _complete_SuiteSetup_or_SuiteTeardown_or_TestTemplate( # noqa: N802
10521056
if len(statement_node.tokens) > 2:
10531057
token = cast(Token, statement_node.tokens[2])
10541058

1055-
token = self.strip_bdd_prefix(token)
1059+
token = self.strip_bdd_prefix(self.namespace, token)
10561060

10571061
r = range_from_token(token)
10581062
if position.is_in_range(r):
10591063
return await self.create_keyword_completion_items(
1060-
None if self.is_bdd_token(token) else token,
1064+
None if self.is_bdd_token(self.namespace, token) else token,
10611065
position,
10621066
add_reserverd=False,
10631067
add_none=True,
@@ -1073,7 +1077,7 @@ async def _complete_SuiteSetup_or_SuiteTeardown_or_TestTemplate( # noqa: N802
10731077
r.end.character += 1
10741078
if position.is_in_range(r):
10751079
return await self.create_keyword_completion_items(
1076-
None if self.is_bdd_token(token) else token,
1080+
None if self.is_bdd_token(self.namespace, token) else token,
10771081
position,
10781082
add_reserverd=False,
10791083
add_none=True,
@@ -1183,7 +1187,7 @@ async def complete_Setup_or_Teardown_or_Template( # noqa: N802
11831187
if len(statement_node.tokens) > 3:
11841188
token = cast(Token, statement_node.tokens[3])
11851189

1186-
token = self.strip_bdd_prefix(token)
1190+
token = self.strip_bdd_prefix(self.namespace, token)
11871191

11881192
r = range_from_token(token)
11891193
if position.is_in_range(r):
@@ -1200,7 +1204,7 @@ async def complete_Setup_or_Teardown_or_Template( # noqa: N802
12001204
r.end.character += 1
12011205
if position.is_in_range(r):
12021206
return await self.create_keyword_completion_items(
1203-
None if self.is_bdd_token(token) else token,
1207+
None if self.is_bdd_token(self.namespace, token) else token,
12041208
position,
12051209
add_reserverd=False,
12061210
add_none=True,

robotcode/language_server/robotframework/parts/diagnostics.py

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,7 @@ async def namespace_invalidated(self, sender: Any, document: TextDocument) -> No
5757
@language_id("robotframework")
5858
@threaded()
5959
@_logger.call
60-
async def collect_namespace_diagnostics(self, sender: Any, document: TextDocument, full: bool) -> DiagnosticsResult:
61-
return await document.get_cache(self._collect_namespace_diagnostics, full)
62-
63-
async def _collect_namespace_diagnostics(self, document: TextDocument, full: bool) -> DiagnosticsResult:
60+
async def collect_namespace_diagnostics(self, sender: Any, document: TextDocument) -> DiagnosticsResult:
6461
try:
6562
namespace = await self.parent.documents_cache.get_namespace(document)
6663
if namespace is None:
@@ -126,10 +123,7 @@ def _create_error_from_token(self, token: Token, source: Optional[str] = None) -
126123
@language_id("robotframework")
127124
@threaded()
128125
@_logger.call
129-
async def collect_token_errors(self, sender: Any, document: TextDocument, full: bool) -> DiagnosticsResult:
130-
return await document.get_cache(self._collect_token_errors, full)
131-
132-
async def _collect_token_errors(self, document: TextDocument, full: bool) -> DiagnosticsResult:
126+
async def collect_token_errors(self, sender: Any, document: TextDocument) -> DiagnosticsResult:
133127
from robot.errors import VariableError
134128
from robot.parsing.lexer.tokens import Token
135129

@@ -195,11 +189,7 @@ async def _collect_token_errors(self, document: TextDocument, full: bool) -> Dia
195189
@language_id("robotframework")
196190
@threaded()
197191
@_logger.call
198-
async def collect_model_errors(self, sender: Any, document: TextDocument, full: bool) -> DiagnosticsResult:
199-
return await document.get_cache(self._collect_model_errors, full)
200-
201-
async def _collect_model_errors(self, document: TextDocument, full: bool) -> DiagnosticsResult:
202-
192+
async def collect_model_errors(self, sender: Any, document: TextDocument) -> DiagnosticsResult:
203193
from ..utils.ast_utils import HasError, HasErrors
204194
from ..utils.async_ast import iter_nodes
205195

@@ -247,18 +237,15 @@ async def _collect_model_errors(self, document: TextDocument, full: bool) -> Dia
247237
@language_id("robotframework")
248238
@threaded()
249239
@_logger.call
250-
async def collect_unused_references(self, sender: Any, document: TextDocument, full: bool) -> DiagnosticsResult:
240+
async def collect_unused_references(self, sender: Any, document: TextDocument) -> DiagnosticsResult:
251241
config = await self.parent.workspace.get_configuration(AnalysisConfig, document.uri)
252242

253-
if not full or not config.find_unused_references:
243+
if not config.find_unused_references:
254244
return DiagnosticsResult(self.collect_unused_references, [])
255245

256-
return await document.get_cache(self._collect_unused_references, full)
257-
258-
async def _collect_unused_references(self, document: TextDocument, full: bool) -> DiagnosticsResult:
259-
if not full:
260-
return DiagnosticsResult(self.collect_unused_references, [])
246+
return await self._collect_unused_references(document)
261247

248+
async def _collect_unused_references(self, document: TextDocument) -> DiagnosticsResult:
262249
try:
263250
namespace = await self.parent.documents_cache.get_namespace(document)
264251
if namespace is None:

robotcode/language_server/robotframework/parts/discovering.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ def generate(suite: TestSuite) -> TestItem:
294294
try:
295295
config = await self.get_config(workspace_folder)
296296
rpa_mode = config.get_rpa_mode() if config is not None else None
297-
languages = config.languages if config is not None else None
297+
languages = await self.parent.documents_cache.get_workspace_languages(workspace_folder)
298298

299299
if paths is None and config is not None:
300300
paths = config.paths

0 commit comments

Comments
 (0)