kislyuk / argcomplete

Python and tab completion, better together.
https://kislyuk.github.io/argcomplete/
Apache License 2.0
1.39k stars 129 forks source link

completion with a leading dash #477

Closed priv-kweihmann closed 3 months ago

priv-kweihmann commented 3 months ago

I have the following example code

import argcomplete, argparse

def _custom(prefix, parsed_args, **kwargs):
    if prefix.startswith('+'):
        return [f'+{x}' for x in argcomplete.FilesCompleter().__call__(prefix[1:], **kwargs)]
    elif prefix.startswith('-'):
        return [f'-{x}' for x in argcomplete.FilesCompleter().__call__(prefix[1:], **kwargs)]
    return argcomplete.FilesCompleter().__call__(prefix, **kwargs) + ['+', '-']

def create_argparser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser()
    parser.add_argument('--a', action='store_true')
    parser.add_argument('--b').completer = _custom

parser = create_argparser()
argcomplete.autocomplete(parser)
args = parser.parse_args()

print(args)

--b could be a file or a filename prefixed with - or +.

While for no prefix and + everything is working like I would expect it, for - I get instead of a potential list of files just the root level overview

test.py --b -<TAB>

--a
--b

Is there any way to make argcomplete aware that in the context of --b to run the custom completer function?

kislyuk commented 3 months ago

I don't think this is possible because - is recognized as the start of the next option. You may be able to find a solution by adjusting the behaviors in https://github.com/kislyuk/argcomplete/blob/develop/argcomplete/packages/_argparse.py but I'm not aware of a way. You can work around this by using a = after the option name: --b=....

evanunderscore commented 3 months ago

To be clear, this is not accepted by argparse either. In this case, argcomplete is completing your command line exactly how argparse sees it.

$ python example.py --b -filename
usage: ex.py [-h] [--a] [--b B]
ex.py: error: argument --b: expected one argument
$ python example.py --b=-filename
Namespace(a=False, b='-filename')