(
names: List[str],
core: "ParseResult",
initial_context: "ParserContext",
collection: "Collection",
parser: "Parser",
)
| 18 | |
| 19 | |
| 20 | def complete( |
| 21 | names: List[str], |
| 22 | core: "ParseResult", |
| 23 | initial_context: "ParserContext", |
| 24 | collection: "Collection", |
| 25 | parser: "Parser", |
| 26 | ) -> Exit: |
| 27 | # Strip out program name (scripts give us full command line) |
| 28 | # TODO: this may not handle path/to/script though? |
| 29 | invocation = re.sub(r"^({}) ".format("|".join(names)), "", core.remainder) |
| 30 | debug("Completing for invocation: {!r}".format(invocation)) |
| 31 | # Tokenize (shlex will have to do) |
| 32 | tokens = shlex.split(invocation) |
| 33 | # Handle flags (partial or otherwise) |
| 34 | if tokens and tokens[-1].startswith("-"): |
| 35 | tail = tokens[-1] |
| 36 | debug("Invocation's tail {!r} is flag-like".format(tail)) |
| 37 | # Gently parse invocation to obtain 'current' context. |
| 38 | # Use last seen context in case of failure (required for |
| 39 | # otherwise-invalid partial invocations being completed). |
| 40 | |
| 41 | contexts: List[ParserContext] |
| 42 | try: |
| 43 | debug("Seeking context name in tokens: {!r}".format(tokens)) |
| 44 | contexts = parser.parse_argv(tokens) |
| 45 | except ParseError as e: |
| 46 | msg = "Got parser error ({!r}), grabbing its last-seen context {!r}" # noqa |
| 47 | debug(msg.format(e, e.context)) |
| 48 | contexts = [e.context] if e.context is not None else [] |
| 49 | # Fall back to core context if no context seen. |
| 50 | debug("Parsed invocation, contexts: {!r}".format(contexts)) |
| 51 | if not contexts or not contexts[-1]: |
| 52 | context = initial_context |
| 53 | else: |
| 54 | context = contexts[-1] |
| 55 | debug("Selected context: {!r}".format(context)) |
| 56 | # Unknown flags (could be e.g. only partially typed out; could be |
| 57 | # wholly invalid; doesn't matter) complete with flags. |
| 58 | debug("Looking for {!r} in {!r}".format(tail, context.flags)) |
| 59 | if tail not in context.flags: |
| 60 | debug("Not found, completing with flag names") |
| 61 | # Long flags - partial or just the dashes - complete w/ long flags |
| 62 | if tail.startswith("--"): |
| 63 | for name in filter( |
| 64 | lambda x: x.startswith("--"), context.flag_names() |
| 65 | ): |
| 66 | print(name) |
| 67 | # Just a dash, completes with all flags |
| 68 | elif tail == "-": |
| 69 | for name in context.flag_names(): |
| 70 | print(name) |
| 71 | # Otherwise, it's something entirely invalid (a shortflag not |
| 72 | # recognized, or a java style flag like -foo) so return nothing |
| 73 | # (the shell will still try completing with files, but that doesn't |
| 74 | # hurt really.) |
| 75 | else: |
| 76 | pass |
| 77 | # Known flags complete w/ nothing or tasks, depending |
no test coverage detected
searching dependent graphs…