dfdf
This commit is contained in:
345
CLI.py
345
CLI.py
@@ -28,6 +28,26 @@ from prompt_toolkit.document import Document
|
||||
from prompt_toolkit.lexers import Lexer
|
||||
from prompt_toolkit.styles import Style
|
||||
|
||||
from rich_display import stderr_console, stdout_console
|
||||
|
||||
|
||||
def _install_rich_traceback(*, show_locals: bool = False) -> None:
|
||||
"""Install Rich traceback handler as the default excepthook.
|
||||
|
||||
This keeps uncaught exceptions readable in the terminal.
|
||||
"""
|
||||
try:
|
||||
from rich.traceback import install as rich_traceback_install
|
||||
|
||||
rich_traceback_install(show_locals=bool(show_locals))
|
||||
except Exception:
|
||||
# Fall back to the standard Python traceback if Rich isn't available.
|
||||
return
|
||||
|
||||
|
||||
# Default to Rich tracebacks for the whole process.
|
||||
_install_rich_traceback(show_locals=False)
|
||||
|
||||
from SYS.background_notifier import ensure_background_notifier
|
||||
from SYS.logger import debug, set_debug
|
||||
from SYS.worker_manager import WorkerManager
|
||||
@@ -530,6 +550,32 @@ class CmdletCompleter(Completer):
|
||||
self._config_loader = config_loader
|
||||
self.cmdlet_names = CmdletIntrospection.cmdlet_names()
|
||||
|
||||
@staticmethod
|
||||
def _used_arg_logicals(cmd_name: str, stage_tokens: List[str]) -> Set[str]:
|
||||
"""Return logical argument names already used in this cmdlet stage.
|
||||
|
||||
Example: if the user has typed `download-media -url ...`, then `url`
|
||||
is considered used and should not be suggested again (even as `--url`).
|
||||
"""
|
||||
arg_flags = CmdletIntrospection.cmdlet_args(cmd_name)
|
||||
allowed = {a.lstrip("-").strip().lower() for a in arg_flags if a}
|
||||
if not allowed:
|
||||
return set()
|
||||
|
||||
used: Set[str] = set()
|
||||
for tok in stage_tokens[1:]:
|
||||
if not tok or not tok.startswith("-"):
|
||||
continue
|
||||
if tok in {"-", "--"}:
|
||||
continue
|
||||
# Handle common `-arg=value` form.
|
||||
raw = tok.split("=", 1)[0]
|
||||
logical = raw.lstrip("-").strip().lower()
|
||||
if logical and logical in allowed:
|
||||
used.add(logical)
|
||||
|
||||
return used
|
||||
|
||||
def get_completions(self, document: Document, complete_event): # type: ignore[override]
|
||||
text = document.text_before_cursor
|
||||
tokens = text.split()
|
||||
@@ -600,6 +646,7 @@ class CmdletCompleter(Completer):
|
||||
return
|
||||
|
||||
arg_names = CmdletIntrospection.cmdlet_args(cmd_name)
|
||||
used_logicals = self._used_arg_logicals(cmd_name, stage_tokens)
|
||||
logical_seen: Set[str] = set()
|
||||
for arg in arg_names:
|
||||
arg_low = arg.lower()
|
||||
@@ -607,6 +654,8 @@ class CmdletCompleter(Completer):
|
||||
if prefer_single_dash and arg_low.startswith("--"):
|
||||
continue
|
||||
logical = arg.lstrip("-").lower()
|
||||
if logical in used_logicals:
|
||||
continue
|
||||
if prefer_single_dash and logical in logical_seen:
|
||||
continue
|
||||
if arg_low.startswith(current_token):
|
||||
@@ -751,26 +800,32 @@ class CmdletHelp:
|
||||
def show_cmdlet_list() -> None:
|
||||
try:
|
||||
metadata = list_cmdlet_metadata() or {}
|
||||
print("\nAvailable cmdlet:")
|
||||
from rich.box import SIMPLE
|
||||
from rich.panel import Panel
|
||||
from rich.table import Table as RichTable
|
||||
|
||||
table = RichTable(show_header=True, header_style="bold", box=SIMPLE, expand=True)
|
||||
table.add_column("Cmdlet", no_wrap=True)
|
||||
table.add_column("Aliases")
|
||||
table.add_column("Args")
|
||||
table.add_column("Summary")
|
||||
|
||||
for cmd_name in sorted(metadata.keys()):
|
||||
info = metadata[cmd_name]
|
||||
aliases = info.get("aliases", [])
|
||||
args = info.get("args", [])
|
||||
summary = info.get("summary") or ""
|
||||
alias_str = ", ".join([str(a) for a in (aliases or []) if str(a).strip()])
|
||||
arg_names = [a.get("name") for a in (args or []) if isinstance(a, dict) and a.get("name")]
|
||||
args_str = ", ".join([str(a) for a in arg_names if str(a).strip()])
|
||||
table.add_row(str(cmd_name), alias_str, args_str, str(summary))
|
||||
|
||||
display = f" cmd:{cmd_name}"
|
||||
if aliases:
|
||||
display += f" alias:{', '.join(aliases)}"
|
||||
if args:
|
||||
arg_names = [a.get("name") for a in args if a.get("name")]
|
||||
if arg_names:
|
||||
display += f" args:{', '.join(arg_names)}"
|
||||
summary = info.get("summary")
|
||||
if summary:
|
||||
display += f" - {summary}"
|
||||
print(display)
|
||||
print()
|
||||
stdout_console().print(Panel(table, title="Cmdlets", expand=False))
|
||||
except Exception as exc:
|
||||
print(f"Error: {exc}\n")
|
||||
from rich.panel import Panel
|
||||
from rich.text import Text
|
||||
|
||||
stderr_console().print(Panel(Text(f"Error: {exc}"), title="Error", expand=False))
|
||||
|
||||
@staticmethod
|
||||
def show_cmdlet_help(cmd_name: str) -> None:
|
||||
@@ -787,7 +842,10 @@ class CmdletHelp:
|
||||
def _print_metadata(cmd_name: str, data: Any) -> None:
|
||||
d = data.to_dict() if hasattr(data, "to_dict") else data
|
||||
if not isinstance(d, dict):
|
||||
print(f"Invalid metadata for {cmd_name}\n")
|
||||
from rich.panel import Panel
|
||||
from rich.text import Text
|
||||
|
||||
stderr_console().print(Panel(Text(f"Invalid metadata for {cmd_name}"), title="Error", expand=False))
|
||||
return
|
||||
|
||||
name = d.get("name", cmd_name)
|
||||
@@ -797,45 +855,48 @@ class CmdletHelp:
|
||||
args = d.get("args", [])
|
||||
details = d.get("details", [])
|
||||
|
||||
print("\nNAME")
|
||||
print(f" {name}")
|
||||
from rich.box import SIMPLE
|
||||
from rich.console import Group
|
||||
from rich.panel import Panel
|
||||
from rich.table import Table as RichTable
|
||||
from rich.text import Text
|
||||
|
||||
print("\nSYNOPSIS")
|
||||
print(f" {usage or name}")
|
||||
header = Text.assemble((str(name), "bold"))
|
||||
synopsis = Text(str(usage or name))
|
||||
stdout_console().print(Panel(Group(header, synopsis), title="Help", expand=False))
|
||||
|
||||
if summary or description:
|
||||
print("\nDESCRIPTION")
|
||||
desc_bits: List[Text] = []
|
||||
if summary:
|
||||
print(f" {summary}")
|
||||
desc_bits.append(Text(str(summary)))
|
||||
if description:
|
||||
print(f" {description}")
|
||||
desc_bits.append(Text(str(description)))
|
||||
stdout_console().print(Panel(Group(*desc_bits), title="Description", expand=False))
|
||||
|
||||
if args and isinstance(args, list):
|
||||
print("\nPARAMETERS")
|
||||
param_table = RichTable(show_header=True, header_style="bold", box=SIMPLE, expand=True)
|
||||
param_table.add_column("Arg", no_wrap=True)
|
||||
param_table.add_column("Type", no_wrap=True)
|
||||
param_table.add_column("Required", no_wrap=True)
|
||||
param_table.add_column("Description")
|
||||
for arg in args:
|
||||
if isinstance(arg, dict):
|
||||
name_str = arg.get("name", "?")
|
||||
typ = arg.get("type", "string")
|
||||
required = arg.get("required", False)
|
||||
required = bool(arg.get("required", False))
|
||||
desc = arg.get("description", "")
|
||||
else:
|
||||
name_str = getattr(arg, "name", "?")
|
||||
typ = getattr(arg, "type", "string")
|
||||
required = getattr(arg, "required", False)
|
||||
required = bool(getattr(arg, "required", False))
|
||||
desc = getattr(arg, "description", "")
|
||||
|
||||
req_marker = "[required]" if required else "[optional]"
|
||||
print(f" -{name_str} <{typ}>")
|
||||
if desc:
|
||||
print(f" {desc}")
|
||||
print(f" {req_marker}")
|
||||
print()
|
||||
param_table.add_row(f"-{name_str}", str(typ), "yes" if required else "no", str(desc or ""))
|
||||
|
||||
stdout_console().print(Panel(param_table, title="Parameters", expand=False))
|
||||
|
||||
if details:
|
||||
print("REMARKS")
|
||||
for detail in details:
|
||||
print(f" {detail}")
|
||||
print()
|
||||
stdout_console().print(Panel(Group(*[Text(str(x)) for x in details]), title="Remarks", expand=False))
|
||||
|
||||
|
||||
class CmdletExecutor:
|
||||
@@ -1044,6 +1105,26 @@ class CmdletExecutor:
|
||||
|
||||
ctx.set_last_selection(selected_indices)
|
||||
try:
|
||||
try:
|
||||
if hasattr(ctx, "set_current_cmdlet_name"):
|
||||
ctx.set_current_cmdlet_name(cmd_name)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
if hasattr(ctx, "set_current_stage_text"):
|
||||
raw_stage = ""
|
||||
try:
|
||||
raw_stage = ctx.get_current_command_text("") if hasattr(ctx, "get_current_command_text") else ""
|
||||
except Exception:
|
||||
raw_stage = ""
|
||||
if raw_stage:
|
||||
ctx.set_current_stage_text(raw_stage)
|
||||
else:
|
||||
ctx.set_current_stage_text(" ".join([cmd_name, *filtered_args]).strip() or cmd_name)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
ret_code = cmd_fn(result, filtered_args, config)
|
||||
|
||||
if getattr(pipeline_ctx, "emits", None):
|
||||
@@ -1113,8 +1194,8 @@ class CmdletExecutor:
|
||||
else:
|
||||
ctx.set_last_result_items_only(emits)
|
||||
|
||||
print()
|
||||
print(table.format_plain())
|
||||
stdout_console().print()
|
||||
stdout_console().print(table)
|
||||
|
||||
if ret_code != 0:
|
||||
stage_status = "failed"
|
||||
@@ -1125,6 +1206,16 @@ class CmdletExecutor:
|
||||
stage_error = f"{type(exc).__name__}: {exc}"
|
||||
print(f"[error] {type(exc).__name__}: {exc}\n")
|
||||
finally:
|
||||
try:
|
||||
if hasattr(ctx, "clear_current_cmdlet_name"):
|
||||
ctx.clear_current_cmdlet_name()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
if hasattr(ctx, "clear_current_stage_text"):
|
||||
ctx.clear_current_stage_text()
|
||||
except Exception:
|
||||
pass
|
||||
ctx.clear_last_selection()
|
||||
if stage_session:
|
||||
stage_session.close(status=stage_status, error_msg=stage_error)
|
||||
@@ -1322,6 +1413,13 @@ class PipelineExecutor:
|
||||
pipeline_text = " | ".join(" ".join(stage) for stage in stages)
|
||||
pipeline_session = WorkerStages.begin_pipeline(worker_manager, pipeline_text=pipeline_text, config=config)
|
||||
|
||||
raw_stage_texts: List[str] = []
|
||||
try:
|
||||
if hasattr(ctx, "get_current_command_stages"):
|
||||
raw_stage_texts = ctx.get_current_command_stages() or []
|
||||
except Exception:
|
||||
raw_stage_texts = []
|
||||
|
||||
if pipeline_session and worker_manager and isinstance(config, dict):
|
||||
session_worker_ids = config.get("_session_worker_ids")
|
||||
if session_worker_ids:
|
||||
@@ -1452,6 +1550,9 @@ class PipelineExecutor:
|
||||
if table_type == "youtube":
|
||||
print("Auto-running YouTube selection via download-media")
|
||||
stages.append(["download-media"])
|
||||
elif table_type == "bandcamp":
|
||||
print("Auto-running Bandcamp selection via download-media")
|
||||
stages.append(["download-media"])
|
||||
elif table_type in {"soulseek", "openlibrary", "libgen"}:
|
||||
print("Auto-piping selection to download-file")
|
||||
stages.append(["download-file"])
|
||||
@@ -1473,6 +1574,14 @@ class PipelineExecutor:
|
||||
):
|
||||
print("Auto-inserting download-media after YouTube selection")
|
||||
stages.insert(0, ["download-media"])
|
||||
if table_type == "bandcamp" and first_cmd not in (
|
||||
"download-media",
|
||||
"download_media",
|
||||
"download-file",
|
||||
".pipe",
|
||||
):
|
||||
print("Auto-inserting download-media after Bandcamp selection")
|
||||
stages.insert(0, ["download-media"])
|
||||
if table_type == "libgen" and first_cmd not in (
|
||||
"download-file",
|
||||
"download-media",
|
||||
@@ -1645,6 +1754,32 @@ class PipelineExecutor:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
if hasattr(ctx, "set_current_cmdlet_name"):
|
||||
ctx.set_current_cmdlet_name(cmd_name)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
if hasattr(ctx, "set_current_stage_text"):
|
||||
stage_text = ""
|
||||
if raw_stage_texts and stage_index < len(raw_stage_texts):
|
||||
candidate = str(raw_stage_texts[stage_index] or "").strip()
|
||||
if candidate:
|
||||
try:
|
||||
cand_tokens = shlex.split(candidate)
|
||||
except Exception:
|
||||
cand_tokens = candidate.split()
|
||||
if cand_tokens:
|
||||
first = str(cand_tokens[0]).replace("_", "-").lower()
|
||||
if first == cmd_name:
|
||||
stage_text = candidate
|
||||
if not stage_text:
|
||||
stage_text = " ".join(stage_tokens).strip()
|
||||
ctx.set_current_stage_text(stage_text)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
ret_code = cmd_fn(piped_result, list(stage_args), config)
|
||||
|
||||
stage_is_last = stage_index + 1 >= len(stages)
|
||||
@@ -1676,7 +1811,6 @@ class PipelineExecutor:
|
||||
and (not emits)
|
||||
and cmd_name in {"download-media", "download_media"}
|
||||
and stage_table is not None
|
||||
and hasattr(stage_table, "format_plain")
|
||||
and stage_table_type in {"ytdlp.formatlist", "download-media", "download_media"}
|
||||
):
|
||||
try:
|
||||
@@ -1691,8 +1825,8 @@ class PipelineExecutor:
|
||||
already_rendered = False
|
||||
|
||||
if not already_rendered:
|
||||
print()
|
||||
print(stage_table.format_plain())
|
||||
stdout_console().print()
|
||||
stdout_console().print(stage_table)
|
||||
|
||||
try:
|
||||
remaining = stages[stage_index + 1 :]
|
||||
@@ -1719,15 +1853,15 @@ class PipelineExecutor:
|
||||
if final_table is None:
|
||||
final_table = stage_table
|
||||
|
||||
if final_table is not None and hasattr(final_table, "format_plain"):
|
||||
if final_table is not None:
|
||||
try:
|
||||
already_rendered = bool(getattr(final_table, "_rendered_by_cmdlet", False))
|
||||
except Exception:
|
||||
already_rendered = False
|
||||
|
||||
if not already_rendered:
|
||||
print()
|
||||
print(final_table.format_plain())
|
||||
stdout_console().print()
|
||||
stdout_console().print(final_table)
|
||||
|
||||
# Fallback: if a cmdlet emitted results but did not provide a table,
|
||||
# render a standard ResultTable so last-stage pipelines still show output.
|
||||
@@ -1739,8 +1873,8 @@ class PipelineExecutor:
|
||||
table = ResultTable(table_title)
|
||||
for item in emits:
|
||||
table.add_result(item)
|
||||
print()
|
||||
print(table.format_plain())
|
||||
stdout_console().print()
|
||||
stdout_console().print(table)
|
||||
|
||||
if isinstance(ret_code, int) and ret_code != 0:
|
||||
stage_status = "failed"
|
||||
@@ -1757,6 +1891,16 @@ class PipelineExecutor:
|
||||
pipeline_error = f"{stage_label} error: {exc}"
|
||||
return
|
||||
finally:
|
||||
try:
|
||||
if hasattr(ctx, "clear_current_cmdlet_name"):
|
||||
ctx.clear_current_cmdlet_name()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
if hasattr(ctx, "clear_current_stage_text"):
|
||||
ctx.clear_current_stage_text()
|
||||
except Exception:
|
||||
pass
|
||||
if stage_session:
|
||||
stage_session.close(status=stage_status, error_msg=stage_error)
|
||||
elif pipeline_session and worker_manager:
|
||||
@@ -1774,8 +1918,8 @@ class PipelineExecutor:
|
||||
for item in items:
|
||||
table.add_result(item)
|
||||
ctx.set_last_result_items_only(items)
|
||||
print()
|
||||
print(table.format_plain())
|
||||
stdout_console().print()
|
||||
stdout_console().print(table)
|
||||
except Exception as exc:
|
||||
pipeline_status = "failed"
|
||||
pipeline_error = str(exc)
|
||||
@@ -1786,7 +1930,20 @@ class PipelineExecutor:
|
||||
except Exception as exc:
|
||||
print(f"[error] Failed to execute pipeline: {exc}\n")
|
||||
|
||||
Welcome = """
|
||||
# MEDIOS-MACINA
|
||||
|
||||
Rich can do a pretty *decent* job of rendering markdown.
|
||||
|
||||
1. This is a list item
|
||||
2. This is another list item
|
||||
"""
|
||||
from rich.markdown import Markdown
|
||||
from rich.console import Console
|
||||
|
||||
console = Console()
|
||||
md = Markdown(Welcome)
|
||||
console.print(md)
|
||||
class MedeiaCLI:
|
||||
"""Main CLI application object."""
|
||||
|
||||
@@ -1892,25 +2049,20 @@ class MedeiaCLI:
|
||||
return app
|
||||
|
||||
def run(self) -> None:
|
||||
# Ensure Rich tracebacks are active even when invoking subcommands.
|
||||
try:
|
||||
config = self._config_loader.load()
|
||||
debug_enabled = bool(config.get("debug", False)) if isinstance(config, dict) else False
|
||||
except Exception:
|
||||
debug_enabled = False
|
||||
|
||||
set_debug(debug_enabled)
|
||||
_install_rich_traceback(show_locals=debug_enabled)
|
||||
|
||||
self.build_app()()
|
||||
|
||||
def run_repl(self) -> None:
|
||||
banner = r"""
|
||||
Medeia-Macina
|
||||
=====================
|
||||
|123456789|ABCDEFGHI|
|
||||
|246813579|JKLMNOPQR|
|
||||
|369369369|STUVWXYZ0|
|
||||
|483726159|ABCDEFGHI|
|
||||
|=========+=========|
|
||||
|516273849|JKLMNOPQR|
|
||||
|639639639|STUVWXYZ0|
|
||||
|753186429|ABCDEFGHI|
|
||||
|876543219|JKLMNOPQR|
|
||||
|999999999|STUVWXYZ0|
|
||||
=====================
|
||||
"""
|
||||
print(banner)
|
||||
# (Startup banner is optional; keep the REPL quiet by default.)
|
||||
|
||||
prompt_text = "🜂🜄🜁🜃|"
|
||||
|
||||
@@ -1918,6 +2070,11 @@ class MedeiaCLI:
|
||||
"*********<IGNITIO>*********<NOUSEMPEH>*********<RUGRAPOG>*********<OMEGHAU>*********"
|
||||
)
|
||||
startup_table.set_no_choice(True).set_preserve_order(True)
|
||||
startup_table.set_value_case("upper")
|
||||
|
||||
def _upper(value: Any) -> str:
|
||||
text = "" if value is None else str(value)
|
||||
return text.upper()
|
||||
|
||||
def _add_startup_check(
|
||||
status: str,
|
||||
@@ -1929,12 +2086,12 @@ class MedeiaCLI:
|
||||
detail: str = "",
|
||||
) -> None:
|
||||
row = startup_table.add_row()
|
||||
row.add_column("Status", status)
|
||||
row.add_column("Name", name)
|
||||
row.add_column("Provider", provider or "")
|
||||
row.add_column("Store", store or "")
|
||||
row.add_column("Files", "" if files is None else str(files))
|
||||
row.add_column("Detail", detail or "")
|
||||
row.add_column("STATUS", _upper(status))
|
||||
row.add_column("NAME", _upper(name))
|
||||
row.add_column("PROVIDER", _upper(provider or ""))
|
||||
row.add_column("STORE", _upper(store or ""))
|
||||
row.add_column("FILES", "" if files is None else str(files))
|
||||
row.add_column("DETAIL", _upper(detail or ""))
|
||||
|
||||
def _has_store_subtype(cfg: dict, subtype: str) -> bool:
|
||||
store_cfg = cfg.get("store")
|
||||
@@ -1967,8 +2124,8 @@ class MedeiaCLI:
|
||||
config = self._config_loader.load()
|
||||
debug_enabled = bool(config.get("debug", False))
|
||||
set_debug(debug_enabled)
|
||||
if debug_enabled:
|
||||
debug("✓ Debug logging enabled")
|
||||
_install_rich_traceback(show_locals=debug_enabled)
|
||||
_add_startup_check("ENABLED" if debug_enabled else "DISABLED", "DEBUGGING")
|
||||
|
||||
try:
|
||||
try:
|
||||
@@ -2226,8 +2383,8 @@ class MedeiaCLI:
|
||||
_add_startup_check("ERROR", "Cookies", detail=str(exc))
|
||||
|
||||
if startup_table.rows:
|
||||
print()
|
||||
print(startup_table.format_plain())
|
||||
stdout_console().print()
|
||||
stdout_console().print(startup_table)
|
||||
except Exception as exc:
|
||||
if debug_enabled:
|
||||
debug(f"⚠ Could not check service availability: {exc}")
|
||||
@@ -2349,9 +2506,9 @@ class MedeiaCLI:
|
||||
if last_table is None:
|
||||
last_table = ctx.get_last_result_table()
|
||||
if last_table:
|
||||
print()
|
||||
stdout_console().print()
|
||||
ctx.set_current_stage_table(last_table)
|
||||
print(last_table.format_plain())
|
||||
stdout_console().print(last_table)
|
||||
else:
|
||||
items = ctx.get_last_result_items()
|
||||
if items:
|
||||
@@ -2370,10 +2527,44 @@ class MedeiaCLI:
|
||||
last_table = ctx.get_display_table() if hasattr(ctx, "get_display_table") else None
|
||||
if last_table is None:
|
||||
last_table = ctx.get_last_result_table()
|
||||
|
||||
# Auto-refresh search-store tables when navigating back,
|
||||
# so row payloads (titles/tags) reflect latest store state.
|
||||
try:
|
||||
src_cmd = getattr(last_table, "source_command", None) if last_table else None
|
||||
if isinstance(src_cmd, str) and src_cmd.lower().replace("_", "-") == "search-store":
|
||||
src_args = getattr(last_table, "source_args", None) if last_table else None
|
||||
base_args = list(src_args) if isinstance(src_args, list) else []
|
||||
cleaned_args = [
|
||||
str(a)
|
||||
for a in base_args
|
||||
if str(a).strip().lower() not in {"--refresh", "-refresh"}
|
||||
]
|
||||
if hasattr(ctx, "set_current_command_text"):
|
||||
try:
|
||||
title_text = getattr(last_table, "title", None) if last_table else None
|
||||
if isinstance(title_text, str) and title_text.strip():
|
||||
ctx.set_current_command_text(title_text.strip())
|
||||
else:
|
||||
ctx.set_current_command_text(" ".join(["search-store", *cleaned_args]).strip())
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
self._cmdlet_executor.execute("search-store", cleaned_args + ["--refresh"])
|
||||
finally:
|
||||
if hasattr(ctx, "clear_current_command_text"):
|
||||
try:
|
||||
ctx.clear_current_command_text()
|
||||
except Exception:
|
||||
pass
|
||||
continue
|
||||
except Exception as exc:
|
||||
print(f"Error refreshing search-store table: {exc}", file=sys.stderr)
|
||||
|
||||
if last_table:
|
||||
print()
|
||||
stdout_console().print()
|
||||
ctx.set_current_stage_table(last_table)
|
||||
print(last_table.format_plain())
|
||||
stdout_console().print(last_table)
|
||||
else:
|
||||
items = ctx.get_last_result_items()
|
||||
if items:
|
||||
|
||||
Reference in New Issue
Block a user