1
+ import re
1
2
from itertools import chain
2
3
from typing import TYPE_CHECKING , Dict , Iterable , Iterator , List , NamedTuple , Optional , Sequence , Tuple
3
4
@@ -51,10 +52,11 @@ def __init__(self, namespace: "Namespace", library_doc: LibraryDoc) -> None:
51
52
Optional [List [KeywordDoc ]],
52
53
],
53
54
] = {}
54
- self . handle_bdd_style = True
55
+
55
56
self ._all_keywords : Optional [List [LibraryEntry ]] = None
56
57
self ._resource_keywords : Optional [List [ResourceEntry ]] = None
57
58
self ._library_keywords : Optional [List [LibraryEntry ]] = None
59
+ self ._bdd_prefix_regexp : Optional ["re.Pattern[str]" ] = None
58
60
59
61
def reset_diagnostics (self ) -> None :
60
62
self .diagnostics = []
@@ -70,17 +72,15 @@ def find_keyword(
70
72
try :
71
73
self .reset_diagnostics ()
72
74
73
- self .handle_bdd_style = handle_bdd_style
74
-
75
- cached = self ._cache .get ((name , self .handle_bdd_style ), None )
75
+ cached = self ._cache .get ((name , handle_bdd_style ), None )
76
76
77
77
if cached is not None :
78
78
self .diagnostics = cached [1 ]
79
79
self .multiple_keywords_result = cached [2 ]
80
80
return cached [0 ]
81
81
82
82
try :
83
- result = self ._find_keyword (name )
83
+ result = self ._find_keyword (name , handle_bdd_style )
84
84
if result is None :
85
85
self .diagnostics .append (
86
86
DiagnosticsEntry (
@@ -99,7 +99,7 @@ def find_keyword(
99
99
result = None
100
100
self .diagnostics .append (DiagnosticsEntry (str (e ), DiagnosticSeverity .ERROR , Error .KEYWORD_ERROR ))
101
101
102
- self ._cache [(name , self . handle_bdd_style )] = (
102
+ self ._cache [(name , handle_bdd_style )] = (
103
103
result ,
104
104
self .diagnostics ,
105
105
self .multiple_keywords_result ,
@@ -109,7 +109,11 @@ def find_keyword(
109
109
except CancelSearchError :
110
110
return None
111
111
112
- def _find_keyword (self , name : Optional [str ]) -> Optional [KeywordDoc ]:
112
+ def _find_keyword (
113
+ self ,
114
+ name : Optional [str ],
115
+ handle_bdd_style : bool = True ,
116
+ ) -> Optional [KeywordDoc ]:
113
117
if not name :
114
118
self .diagnostics .append (
115
119
DiagnosticsEntry (
@@ -129,14 +133,21 @@ def _find_keyword(self, name: Optional[str]) -> Optional[KeywordDoc]:
129
133
)
130
134
raise CancelSearchError
131
135
132
- result = self ._get_keyword_from_self (name )
136
+ result : Optional [KeywordDoc ] = None
137
+
138
+ if get_robot_version () >= (7 , 0 ) and handle_bdd_style :
139
+ result = self ._get_bdd_style_keyword (name )
140
+
141
+ if not result :
142
+ result = self ._get_keyword_from_self (name )
143
+
133
144
if not result and "." in name :
134
145
result = self ._get_explicit_keyword (name )
135
146
136
147
if not result :
137
148
result = self ._get_implicit_keyword (name )
138
149
139
- if not result and self . handle_bdd_style :
150
+ if get_robot_version () < ( 7 , 0 ) and not result and handle_bdd_style :
140
151
return self ._get_bdd_style_keyword (name )
141
152
142
153
return result
@@ -264,6 +275,9 @@ def _prioritize_same_file_or_public(
264
275
def _select_best_matches (
265
276
self , entries : List [Tuple [Optional [LibraryEntry ], KeywordDoc ]]
266
277
) -> List [Tuple [Optional [LibraryEntry ], KeywordDoc ]]:
278
+ if len (entries ) < 2 :
279
+ return entries
280
+
267
281
normal = [hand for hand in entries if not hand [1 ].is_embedded ]
268
282
if normal :
269
283
return normal
@@ -438,21 +452,25 @@ def _create_custom_and_standard_keyword_conflict_warning_message(
438
452
f"or '{ '' if standard [0 ] is None else standard [0 ].alias or standard [0 ].name } .{ standard [1 ].name } '."
439
453
)
440
454
441
- def _get_bdd_style_keyword (self , name : str ) -> Optional [KeywordDoc ]:
442
- if get_robot_version () < (6 , 0 ):
443
- lower = name .lower ()
444
- for prefix in ["given " , "when " , "then " , "and " , "but " ]:
445
- if lower .startswith (prefix ):
446
- return self ._find_keyword (name [len (prefix ) :])
447
- return None
455
+ @property
456
+ def bdd_prefix_regexp (self ) -> "re.Pattern[str]" :
457
+ if not self ._bdd_prefix_regexp :
458
+ prefixes = (
459
+ "|" .join (
460
+ self .namespace .languages .bdd_prefixes
461
+ if self .namespace .languages is not None
462
+ else ["given" , "when" , "then" , "and" , "but" ]
463
+ )
464
+ .replace (" " , r"\s" )
465
+ .lower ()
466
+ )
467
+ self ._bdd_prefix_regexp = re .compile (rf"({ prefixes } )\s" , re .IGNORECASE )
468
+ return self ._bdd_prefix_regexp
448
469
449
- parts = name .split ()
450
- if len (parts ) < 2 :
451
- return None
452
- for index in range (1 , len (parts )):
453
- prefix = " " .join (parts [:index ]).title ()
454
- if prefix .title () in (
455
- self .namespace .languages .bdd_prefixes if self .namespace .languages is not None else DEFAULT_BDD_PREFIXES
456
- ):
457
- return self ._find_keyword (" " .join (parts [index :]))
470
+ def _get_bdd_style_keyword (self , name : str ) -> Optional [KeywordDoc ]:
471
+ match = self .bdd_prefix_regexp .match (name )
472
+ if match :
473
+ return self ._find_keyword (
474
+ name [match .end () :], handle_bdd_style = False if get_robot_version () >= (7 , 0 ) else True
475
+ )
458
476
return None
0 commit comments