diff options
author | Paul Spangler <paul.spangler@ni.com> | 2021-08-09 13:27:39 -0500 |
---|---|---|
committer | David Lord <davidism@gmail.com> | 2022-03-28 08:05:27 -0700 |
commit | f2e579ab187ca8fdfbe6ce86de08f0e9f62fe4ae (patch) | |
tree | 69c832d1b503191116c1fa42038d6790badaa151 /src | |
parent | d251cb0abc9b0dbda2402d4d831c18718cfb51bf (diff) | |
download | click-f2e579ab187ca8fdfbe6ce86de08f0e9f62fe4ae.tar.gz |
shell completion prioritizes option values over new options
Allow option values that start with an option prefix to
complete rather than treating them like new options.
Don't treat count options as needing a value to complete.
Diffstat (limited to 'src')
-rw-r--r-- | src/click/core.py | 3 | ||||
-rw-r--r-- | src/click/shell_completion.py | 17 |
2 files changed, 11 insertions, 9 deletions
diff --git a/src/click/core.py b/src/click/core.py index 263a5ff..939ad81 100644 --- a/src/click/core.py +++ b/src/click/core.py @@ -292,6 +292,8 @@ class Context: #: must be never propagated to another arguments. This is used #: to implement nested parsing. self.protected_args: t.List[str] = [] + #: the collected prefixes of the command's options. + self._opt_prefixes: t.Set[str] = set(parent._opt_prefixes) if parent else set() if obj is None and parent is not None: obj = parent.obj @@ -1385,6 +1387,7 @@ class Command(BaseCommand): ) ctx.args = args + ctx._opt_prefixes.update(parser._opt_prefixes) return args def invoke(self, ctx: Context) -> t.Any: diff --git a/src/click/shell_completion.py b/src/click/shell_completion.py index 1e9df6f..c17a8e6 100644 --- a/src/click/shell_completion.py +++ b/src/click/shell_completion.py @@ -448,17 +448,16 @@ def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: ) -def _start_of_option(value: str) -> bool: +def _start_of_option(ctx: Context, value: str) -> bool: """Check if the value looks like the start of an option.""" if not value: return False c = value[0] - # Allow "/" since that starts a path. - return not c.isalnum() and c != "/" + return c in ctx._opt_prefixes -def _is_incomplete_option(args: t.List[str], param: Parameter) -> bool: +def _is_incomplete_option(ctx: Context, args: t.List[str], param: Parameter) -> bool: """Determine if the given parameter is an option that needs a value. :param args: List of complete args before the incomplete value. @@ -467,7 +466,7 @@ def _is_incomplete_option(args: t.List[str], param: Parameter) -> bool: if not isinstance(param, Option): return False - if param.is_flag: + if param.is_flag or param.count: return False last_option = None @@ -476,7 +475,7 @@ def _is_incomplete_option(args: t.List[str], param: Parameter) -> bool: if index + 1 > param.nargs: break - if _start_of_option(arg): + if _start_of_option(ctx, arg): last_option = arg return last_option is not None and last_option in param.opts @@ -551,7 +550,7 @@ def _resolve_incomplete( # split and discard the "=" to make completion easier. if incomplete == "=": incomplete = "" - elif "=" in incomplete and _start_of_option(incomplete): + elif "=" in incomplete and _start_of_option(ctx, incomplete): name, _, incomplete = incomplete.partition("=") args.append(name) @@ -559,7 +558,7 @@ def _resolve_incomplete( # even if they start with the option character. If it hasn't been # given and the incomplete arg looks like an option, the current # command will provide option name completions. - if "--" not in args and _start_of_option(incomplete): + if "--" not in args and _start_of_option(ctx, incomplete): return ctx.command, incomplete params = ctx.command.get_params(ctx) @@ -567,7 +566,7 @@ def _resolve_incomplete( # If the last complete arg is an option name with an incomplete # value, the option will provide value completions. for param in params: - if _is_incomplete_option(args, param): + if _is_incomplete_option(ctx, args, param): return param, incomplete # It's not an option name or value. The first argument without a |