summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRyan <fauxpark@gmail.com>2024-11-21 22:57:36 +1100
committerGitHub <noreply@github.com>2024-11-21 22:57:36 +1100
commit65a8a5ff69289a5cb8fce6555b774573e4452a79 (patch)
tree24d26aceb9f86e54b6e2cc110a8672f334f7182a /lib
parentc7a04bd9305c337e9190d5ebdd368c4af49adc43 (diff)
`qmk find`: expand operator support (#24468)
Diffstat (limited to 'lib')
-rw-r--r--lib/python/qmk/search.py40
-rw-r--r--lib/python/qmk/tests/test_cli_commands.py2
2 files changed, 31 insertions, 11 deletions
diff --git a/lib/python/qmk/search.py b/lib/python/qmk/search.py
index 6517bb4951..c7bce344ad 100644
--- a/lib/python/qmk/search.py
+++ b/lib/python/qmk/search.py
@@ -239,11 +239,11 @@ def _filter_keymap_targets(target_list: List[KeyboardKeymapDesc], filters: List[
239 valid_targets = parallel_map(_load_keymap_info, target_list) 239 valid_targets = parallel_map(_load_keymap_info, target_list)
240 240
241 function_re = re.compile(r'^(?P<function>[a-zA-Z]+)\((?P<key>[a-zA-Z0-9_\.]+)(,\s*(?P<value>[^#]+))?\)$') 241 function_re = re.compile(r'^(?P<function>[a-zA-Z]+)\((?P<key>[a-zA-Z0-9_\.]+)(,\s*(?P<value>[^#]+))?\)$')
242 equals_re = re.compile(r'^(?P<key>[a-zA-Z0-9_\.]+)\s*=\s*(?P<value>[^#]+)$') 242 comparison_re = re.compile(r'^(?P<key>[a-zA-Z0-9_\.]+)\s*(?P<op>[\<\>\!=]=|\<|\>)\s*(?P<value>[^#]+)$')
243 243
244 for filter_expr in filters: 244 for filter_expr in filters:
245 function_match = function_re.match(filter_expr) 245 function_match = function_re.match(filter_expr)
246 equals_match = equals_re.match(filter_expr) 246 comparison_match = comparison_re.match(filter_expr)
247 247
248 if function_match is not None: 248 if function_match is not None:
249 func_name = function_match.group('function').lower() 249 func_name = function_match.group('function').lower()
@@ -259,23 +259,43 @@ def _filter_keymap_targets(target_list: List[KeyboardKeymapDesc], filters: List[
259 value_str = f", {{fg_cyan}}{value}{{fg_reset}}" if value is not None else "" 259 value_str = f", {{fg_cyan}}{value}{{fg_reset}}" if value is not None else ""
260 cli.log.info(f'Filtering on condition: {{fg_green}}{func_name}{{fg_reset}}({{fg_cyan}}{key}{{fg_reset}}{value_str})...') 260 cli.log.info(f'Filtering on condition: {{fg_green}}{func_name}{{fg_reset}}({{fg_cyan}}{key}{{fg_reset}}{value_str})...')
261 261
262 elif equals_match is not None: 262 elif comparison_match is not None:
263 key = equals_match.group('key') 263 key = comparison_match.group('key')
264 value = equals_match.group('value') 264 op = comparison_match.group('op')
265 cli.log.info(f'Filtering on condition: {{fg_cyan}}{key}{{fg_reset}} == {{fg_cyan}}{value}{{fg_reset}}...') 265 value = comparison_match.group('value')
266 cli.log.info(f'Filtering on condition: {{fg_cyan}}{key}{{fg_reset}} {op} {{fg_cyan}}{value}{{fg_reset}}...')
266 267
267 def _make_filter(k, v): 268 def _make_filter(k, o, v):
268 expr = fnmatch.translate(v) 269 expr = fnmatch.translate(v)
269 rule = re.compile(f'^{expr}$', re.IGNORECASE) 270 rule = re.compile(f'^{expr}$', re.IGNORECASE)
270 271
271 def f(e: KeyboardKeymapDesc): 272 def f(e: KeyboardKeymapDesc):
272 lhs = e.dotty.get(k) 273 lhs = e.dotty.get(k)
273 lhs = str(False if lhs is None else lhs) 274 rhs = v
274 return rule.search(lhs) is not None 275
276 if o in ['<', '>', '<=', '>=']:
277 lhs = int(False if lhs is None else lhs)
278 rhs = int(rhs)
279
280 if o == '<':
281 return lhs < rhs
282 elif o == '>':
283 return lhs > rhs
284 elif o == '<=':
285 return lhs <= rhs
286 elif o == '>=':
287 return lhs >= rhs
288 else:
289 lhs = str(False if lhs is None else lhs)
290
291 if o == '!=':
292 return rule.search(lhs) is None
293 elif o == '==':
294 return rule.search(lhs) is not None
275 295
276 return f 296 return f
277 297
278 valid_targets = filter(_make_filter(key, value), valid_targets) 298 valid_targets = filter(_make_filter(key, op, value), valid_targets)
279 else: 299 else:
280 cli.log.warning(f'Unrecognized filter expression: {filter_expr}') 300 cli.log.warning(f'Unrecognized filter expression: {filter_expr}')
281 continue 301 continue
diff --git a/lib/python/qmk/tests/test_cli_commands.py b/lib/python/qmk/tests/test_cli_commands.py
index f18bd12f82..b10fd8d19d 100644
--- a/lib/python/qmk/tests/test_cli_commands.py
+++ b/lib/python/qmk/tests/test_cli_commands.py
@@ -390,7 +390,7 @@ def test_find_contains():
390def test_find_multiple_conditions(): 390def test_find_multiple_conditions():
391 # this is intended to match at least 'crkbd/rev1' 391 # this is intended to match at least 'crkbd/rev1'
392 result = check_subcommand( 392 result = check_subcommand(
393 'find', '-f', 'exists(rgb_matrix.split_count)', '-f', 'contains(matrix_pins.cols, B1)', '-f', 'length(matrix_pins.cols, 6)', '-f', 'absent(eeprom.driver)', '-f', 'ws2812.pin=D3', '-p', 'rgb_matrix.split_count', '-p', 'matrix_pins.cols', '-p', 393 'find', '-f', 'exists(rgb_matrix.split_count)', '-f', 'contains(matrix_pins.cols, B1)', '-f', 'length(matrix_pins.cols, 6)', '-f', 'absent(eeprom.driver)', '-f', 'ws2812.pin == D3', '-p', 'rgb_matrix.split_count', '-p', 'matrix_pins.cols', '-p',
394 'eeprom.driver', '-p', 'ws2812.pin' 394 'eeprom.driver', '-p', 'ws2812.pin'
395 ) 395 )
396 check_returncode(result) 396 check_returncode(result)