Marco Ricci commited on 2025-01-01 00:21:55
Zeige 1 geänderte Dateien mit 51 Einfügungen und 0 Löschungen.
`click` already includes shell completion out of the box, so what
remained to be done was to tell `click` what kind of values the
arguments expect:
* The `path` argument for `derivepassphrase export vault` will be
completed with a filename or the string `VAULT_PATH`. Because this
is not (as a whole) a supported standard category of completion
items, we must generate the completion items ourselves in this case,
including the partial filtering of results.
* The `path` argument to the `--import` and `--export` options of
`derivepassphrase vault` will be completed with a filename. `click`
handles this for us.
* The `service` argument to `devirepassphrase vault` will be completed
with a service name, which we must manually extract and filter.
The shell completion has so far only been tested interactively; in
particular, it is currently excluded from coverage testing.
| ... | ... |
@@ -1343,6 +1343,23 @@ def _load_data( |
| 1343 | 1343 |
assert_never(fmt) |
| 1344 | 1344 |
|
| 1345 | 1345 |
|
| 1346 |
+def _shell_complete_vault_path( # pragma: no cover |
|
| 1347 |
+ ctx: click.Context, |
|
| 1348 |
+ param: click.Parameter, |
|
| 1349 |
+ incomplete: str, |
|
| 1350 |
+) -> list[str | click.shell_completion.CompletionItem]: |
|
| 1351 |
+ del ctx, param |
|
| 1352 |
+ if incomplete and 'VAULT_PATH'.startswith(incomplete): |
|
| 1353 |
+ ret: set[str | click.shell_completion.CompletionItem] = {'VAULT_PATH'}
|
|
| 1354 |
+ for f in os.listdir(): |
|
| 1355 |
+ if f.startswith(incomplete): |
|
| 1356 |
+ ret.add(f + os.path.sep if os.path.isdir(f) else f) |
|
| 1357 |
+ return sorted(ret) |
|
| 1358 |
+ return [ |
|
| 1359 |
+ click.shell_completion.CompletionItem('', type='file'),
|
|
| 1360 |
+ ] |
|
| 1361 |
+ |
|
| 1362 |
+ |
|
| 1346 | 1363 |
@derivepassphrase_export.command( |
| 1347 | 1364 |
'vault', |
| 1348 | 1365 |
context_settings={'help_option_names': ['-h', '--help']},
|
| ... | ... |
@@ -1401,6 +1418,7 @@ def _load_data( |
| 1401 | 1418 |
'path', |
| 1402 | 1419 |
metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_METAVAR_PATH), |
| 1403 | 1420 |
required=True, |
| 1421 |
+ shell_complete=_shell_complete_vault_path, |
|
| 1404 | 1422 |
) |
| 1405 | 1423 |
@click.pass_context |
| 1406 | 1424 |
def derivepassphrase_export_vault( |
| ... | ... |
@@ -2179,6 +2197,36 @@ def _validate_length( |
| 2179 | 2197 |
return int_value |
| 2180 | 2198 |
|
| 2181 | 2199 |
|
| 2200 |
+def _shell_complete_path( # pragma: no cover |
|
| 2201 |
+ ctx: click.Context, |
|
| 2202 |
+ parameter: click.Parameter, |
|
| 2203 |
+ incomplete: str, |
|
| 2204 |
+) -> list[str | click.shell_completion.CompletionItem]: |
|
| 2205 |
+ del ctx, parameter, incomplete |
|
| 2206 |
+ return [click.shell_completion.CompletionItem('', type='file')]
|
|
| 2207 |
+ |
|
| 2208 |
+ |
|
| 2209 |
+def _shell_complete_service( # pragma: no cover |
|
| 2210 |
+ ctx: click.Context, |
|
| 2211 |
+ parameter: click.Parameter, |
|
| 2212 |
+ incomplete: str, |
|
| 2213 |
+) -> list[str | click.shell_completion.CompletionItem]: |
|
| 2214 |
+ del ctx, parameter |
|
| 2215 |
+ try: |
|
| 2216 |
+ config = _load_config() |
|
| 2217 |
+ return [sv for sv in config['services'] if sv.startswith(incomplete)] |
|
| 2218 |
+ except FileNotFoundError: |
|
| 2219 |
+ try: |
|
| 2220 |
+ config, _exc = _migrate_and_load_old_config() |
|
| 2221 |
+ return [ |
|
| 2222 |
+ sv for sv in config['services'] if sv.startswith(incomplete) |
|
| 2223 |
+ ] |
|
| 2224 |
+ except FileNotFoundError: |
|
| 2225 |
+ return [] |
|
| 2226 |
+ except Exception: # noqa: BLE001 |
|
| 2227 |
+ return [] |
|
| 2228 |
+ |
|
| 2229 |
+ |
|
| 2182 | 2230 |
DEFAULT_NOTES_TEMPLATE = """\ |
| 2183 | 2231 |
# Enter notes below the line with the cut mark (ASCII scissors and |
| 2184 | 2232 |
# dashes). Lines above the cut mark (such as this one) will be ignored. |
| ... | ... |
@@ -2416,6 +2464,7 @@ DEFAULT_NOTES_MARKER = '# - - - - - >8 - - - - -' |
| 2416 | 2464 |
), |
| 2417 | 2465 |
), |
| 2418 | 2466 |
cls=StorageManagementOption, |
| 2467 |
+ shell_complete=_shell_complete_path, |
|
| 2419 | 2468 |
) |
| 2420 | 2469 |
@click.option( |
| 2421 | 2470 |
'-i', |
| ... | ... |
@@ -2431,6 +2480,7 @@ DEFAULT_NOTES_MARKER = '# - - - - - >8 - - - - -' |
| 2431 | 2480 |
), |
| 2432 | 2481 |
), |
| 2433 | 2482 |
cls=StorageManagementOption, |
| 2483 |
+ shell_complete=_shell_complete_path, |
|
| 2434 | 2484 |
) |
| 2435 | 2485 |
@click.option( |
| 2436 | 2486 |
'--overwrite-existing/--merge-existing', |
| ... | ... |
@@ -2478,6 +2528,7 @@ DEFAULT_NOTES_MARKER = '# - - - - - >8 - - - - -' |
| 2478 | 2528 |
metavar=_msg.TranslatedString(_msg.Label.VAULT_METAVAR_SERVICE), |
| 2479 | 2529 |
required=False, |
| 2480 | 2530 |
default=None, |
| 2531 |
+ shell_complete=_shell_complete_service, |
|
| 2481 | 2532 |
) |
| 2482 | 2533 |
@click.pass_context |
| 2483 | 2534 |
def derivepassphrase_vault( # noqa: C901,PLR0912,PLR0913,PLR0914,PLR0915 |
| 2484 | 2535 |