Add clone support across Action types and Command so commands can be safely registered or runner-bound without mutating the original instances. - clone BaseAction implementations across simple, composite, IO, prompt, file, HTTP, process, and signal actions - bind cloned commands in Falyx.add_command_from_command() and CommandRunner - preserve local never_prompt settings when cloning actions - rename shared runtime state from options to options_manager for consistency - seed root and execution option namespaces consistently - apply scoped root and namespace option overrides during routing and dispatch - improve namespace completion by delegating option suggestions to FalyxParser - enrich missing-value errors and error hints
122 lines
3.1 KiB
Python
122 lines
3.1 KiB
Python
from prompt_toolkit.document import Document
|
|
|
|
from falyx import Falyx
|
|
from falyx.completer import FalyxCompleter
|
|
from falyx.parser import CommandArgumentParser
|
|
|
|
|
|
def completion_texts(completions) -> list[str]:
|
|
return [c.text for c in completions]
|
|
|
|
|
|
def make_completion_app() -> tuple[Falyx, FalyxCompleter]:
|
|
flx = Falyx(program="falyx")
|
|
|
|
flx.add_option(
|
|
"--profile",
|
|
suggestions=["dev", "prod", "staging"],
|
|
help="Runtime profile",
|
|
)
|
|
|
|
flx.add_option(
|
|
"--region",
|
|
choices=["us-east", "us-west"],
|
|
help="Deployment region",
|
|
)
|
|
|
|
parser = CommandArgumentParser()
|
|
parser.add_argument("--name")
|
|
parser.add_argument("--env", choices=["dev", "prod"])
|
|
|
|
flx.add_command(
|
|
key="D",
|
|
description="Deploy",
|
|
action=lambda name, env: f"deploy {name} to {env}",
|
|
aliases=["deploy"],
|
|
arg_parser=parser,
|
|
)
|
|
|
|
return flx, FalyxCompleter(flx)
|
|
|
|
|
|
def test_completion_suggests_namespace_flags():
|
|
_, completer = make_completion_app()
|
|
|
|
completions = list(
|
|
completer.get_completions(Document(text="--pr", cursor_position=4), None)
|
|
)
|
|
|
|
texts = completion_texts(completions)
|
|
assert "--profile" in texts
|
|
|
|
|
|
def test_completion_suggests_namespace_option_values():
|
|
_, completer = make_completion_app()
|
|
|
|
completions = list(
|
|
completer.get_completions(
|
|
Document(text="--profile pr", cursor_position=len("--profile pr")),
|
|
None,
|
|
)
|
|
)
|
|
|
|
texts = completion_texts(completions)
|
|
assert "prod" in texts
|
|
assert "dev" not in texts
|
|
|
|
|
|
def test_completion_after_committed_namespace_option_returns_namespace_entries():
|
|
_, completer = make_completion_app()
|
|
|
|
completions = list(
|
|
completer.get_completions(
|
|
Document(text="--profile prod de", cursor_position=len("--profile prod de")),
|
|
None,
|
|
)
|
|
)
|
|
|
|
texts = completion_texts(completions)
|
|
assert "deploy" in texts
|
|
|
|
|
|
def test_completion_preview_mode_prefixes_namespace_entry_suggestions():
|
|
_, completer = make_completion_app()
|
|
|
|
completions = list(
|
|
completer.get_completions(Document(text="?de", cursor_position=3), None)
|
|
)
|
|
|
|
texts = completion_texts(completions)
|
|
assert "?deploy" in texts
|
|
|
|
|
|
def test_resolve_completion_route_unresolved_entry_with_trailing_input_stops_namespace_entry_mode():
|
|
flx, _ = make_completion_app()
|
|
|
|
route = flx.resolve_completion_route(
|
|
["wat"],
|
|
stub="--na",
|
|
cursor_at_end_of_token=False,
|
|
invocation_context=flx.get_current_invocation_context(),
|
|
is_preview=False,
|
|
)
|
|
|
|
assert route.command is None
|
|
assert route.expecting_entry is False
|
|
assert route.remaining_argv == ["wat", "--na"]
|
|
assert route.stub == ""
|
|
|
|
|
|
def test_completion_delegates_to_command_parser_after_leaf_command_is_resolved():
|
|
_, completer = make_completion_app()
|
|
|
|
completions = list(
|
|
completer.get_completions(
|
|
Document(text="D --na", cursor_position=len("D --na")),
|
|
None,
|
|
)
|
|
)
|
|
|
|
texts = completion_texts(completions)
|
|
assert "--name" in texts
|