Files
falyx/falyx/parser/falyx_parser.py
Roland Thomas dcec792d32 refactor: make completer routing-aware for namespaces
- route completions through resolve_completion_route instead of one-level command lookup
- add CompletionRoute to model partial completion state
- suggest namespace entries and namespace-level help/TLDR flags while routing
- delegate leaf argv completion to CommandArgumentParser after command resolution
- restore LCP completion behavior with deduping and flag-safe handling
- add namespace completion name iteration and TLDR example support to Falyx
- update completer and completion route documentation
2026-04-12 14:04:06 -04:00

104 lines
2.9 KiB
Python

# Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING
from falyx.mode import FalyxMode
from falyx.parser.parse_result import RootParseResult
@dataclass(slots=True)
class RootOptions:
verbose: bool = False
debug_hooks: bool = False
never_prompt: bool = False
help: bool = False
tldr: bool = False
class FalyxParser:
"""Root parser and command router for Falyx.
Responsibilities:
- parse global/root flags
- resolve built-ins vs registered commands
- normalize CLI input into ParseResult
- delegate command-specific parsing to CommandArgumentParser
"""
ROOT_FLAG_ALIASES: dict[str, str] = {
"-n": "never_prompt",
"--never-prompt": "never_prompt",
"-v": "verbose",
"--verbose": "verbose",
"-d": "debug_hooks",
"--debug-hooks": "debug_hooks",
"?": "help",
"-h": "help",
"--help": "help",
"-T": "tldr",
"--tldr": "tldr",
}
@classmethod
def _parse_root_options(
cls,
argv: list[str],
) -> tuple[RootOptions, list[str]]:
"""Parse only root/session flags from the start of argv.
Parsing stops at the first token that is not a recognized root flag.
Remaining tokens are returned untouched for later routing.
Examples:
["--verbose", "deploy", "--env", "prod"]
-> (RootOptions(verbose=True), ["deploy", "--env", "prod"])
["deploy", "--verbose"]
-> (RootOptions(), ["deploy", "--verbose"])
"""
options = RootOptions()
remaining_start = 0
for index, token in enumerate(argv):
if token == "--":
remaining_start = index + 1
break
attr = cls.ROOT_FLAG_ALIASES.get(token)
if attr is None:
remaining_start = index
break
setattr(options, attr, True)
else:
remaining_start = len(argv)
remaining = argv[remaining_start:]
return options, remaining
@classmethod
def parse(cls, argv: list[str] | None = None) -> RootParseResult:
argv = argv or []
root, remaining = cls._parse_root_options(argv)
if root.help or root.tldr:
return RootParseResult(
mode=FalyxMode.HELP,
raw_argv=argv,
never_prompt=root.never_prompt,
verbose=root.verbose,
debug_hooks=root.debug_hooks,
tldr_requested=root.tldr,
)
return RootParseResult(
mode=FalyxMode.COMMAND,
raw_argv=argv,
verbose=root.verbose,
debug_hooks=root.debug_hooks,
never_prompt=root.never_prompt,
remaining_argv=remaining,
)