j
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from importlib import import_module
|
||||
from types import ModuleType
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
try:
|
||||
@@ -21,22 +22,36 @@ def _should_hide_db_args(config: Optional[Dict[str, Any]]) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
try:
|
||||
from cmdlet import REGISTRY
|
||||
except Exception:
|
||||
REGISTRY = {} # type: ignore
|
||||
_cmdlet_pkg: ModuleType | None = None
|
||||
|
||||
try:
|
||||
from cmdnat import register_native_commands as _register_native_commands
|
||||
except Exception:
|
||||
_register_native_commands = None
|
||||
|
||||
def _get_cmdlet_package() -> Optional[ModuleType]:
|
||||
global _cmdlet_pkg
|
||||
if _cmdlet_pkg is not None:
|
||||
return _cmdlet_pkg
|
||||
try:
|
||||
_cmdlet_pkg = import_module("cmdlet")
|
||||
except Exception:
|
||||
_cmdlet_pkg = None
|
||||
return _cmdlet_pkg
|
||||
|
||||
|
||||
def _get_registry() -> Dict[str, Any]:
|
||||
pkg = _get_cmdlet_package()
|
||||
if pkg is None:
|
||||
return {}
|
||||
return getattr(pkg, "REGISTRY", {}) or {}
|
||||
|
||||
|
||||
def ensure_registry_loaded() -> None:
|
||||
"""Ensure native commands are registered into REGISTRY (idempotent)."""
|
||||
if _register_native_commands and REGISTRY is not None:
|
||||
pkg = _get_cmdlet_package()
|
||||
if pkg is None:
|
||||
return
|
||||
ensure_fn = getattr(pkg, "ensure_cmdlet_modules_loaded", None)
|
||||
if callable(ensure_fn):
|
||||
try:
|
||||
_register_native_commands(REGISTRY)
|
||||
ensure_fn()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -105,7 +120,8 @@ def get_cmdlet_metadata(
|
||||
|
||||
if data is None:
|
||||
try:
|
||||
reg_fn = (REGISTRY or {}).get(cmd_name.replace("_", "-").lower())
|
||||
registry = _get_registry()
|
||||
reg_fn = registry.get(cmd_name.replace("_", "-").lower())
|
||||
if reg_fn:
|
||||
owner_mod = getattr(reg_fn, "__module__", "")
|
||||
if owner_mod:
|
||||
@@ -150,7 +166,8 @@ def list_cmdlet_metadata(config: Optional[Dict[str, Any]] = None) -> Dict[str, D
|
||||
"""Collect metadata for all registered cmdlet keyed by canonical name."""
|
||||
ensure_registry_loaded()
|
||||
entries: Dict[str, Dict[str, Any]] = {}
|
||||
for reg_name in (REGISTRY or {}).keys():
|
||||
registry = _get_registry()
|
||||
for reg_name in registry.keys():
|
||||
meta = get_cmdlet_metadata(reg_name, config=config)
|
||||
canonical = str(reg_name).replace("_", "-").lower()
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ class PipeObject:
|
||||
return
|
||||
|
||||
# Prefer a stable, human-friendly title:
|
||||
# "1 - download-media", "2 - download-media", ...
|
||||
# "1 - download-file", "2 - download-file", ...
|
||||
# The index is preserved when possible via `pipe_index` in the PipeObject's extra.
|
||||
idx = None
|
||||
try:
|
||||
@@ -875,7 +875,7 @@ class PipelineLiveProgress:
|
||||
|
||||
# IMPORTANT: use the shared stderr Console instance so that any
|
||||
# `stderr_console().print(...)` calls from inside cmdlets (e.g. preflight
|
||||
# tables/prompts in download-media) cooperate with Rich Live rendering.
|
||||
# tables/prompts in download-file) cooperate with Rich Live rendering.
|
||||
# If we create a separate Console(file=sys.stderr), output will fight for
|
||||
# terminal cursor control and appear "blocked"/truncated.
|
||||
from SYS.rich_display import stderr_console
|
||||
|
||||
@@ -361,6 +361,8 @@ class ResultRow:
|
||||
"""Arguments to use for this row when selected via @N syntax (e.g., ['-item', '3'])"""
|
||||
source_index: Optional[int] = None
|
||||
"""Original insertion order index (used to map sorted views back to source items)."""
|
||||
payload: Optional[Any] = None
|
||||
"""Original object that contributed to this row."""
|
||||
|
||||
def add_column(self, name: str, value: Any) -> None:
|
||||
"""Add a column to this row."""
|
||||
@@ -498,6 +500,9 @@ class ResultTable:
|
||||
self.table: Optional[str] = None
|
||||
"""Table type (e.g., 'youtube', 'soulseek') for context-aware selection logic."""
|
||||
|
||||
self.table_metadata: Dict[str, Any] = {}
|
||||
"""Optional provider/table metadata (e.g., provider name, view)."""
|
||||
|
||||
self.value_case: str = "lower"
|
||||
"""Display-only value casing: 'lower' (default), 'upper', or 'preserve'."""
|
||||
|
||||
@@ -525,6 +530,18 @@ class ResultTable:
|
||||
self.table = table
|
||||
return self
|
||||
|
||||
def set_table_metadata(self, metadata: Optional[Dict[str, Any]]) -> "ResultTable":
|
||||
"""Attach provider/table metadata for downstream selection logic."""
|
||||
self.table_metadata = dict(metadata or {})
|
||||
return self
|
||||
|
||||
def get_table_metadata(self) -> Dict[str, Any]:
|
||||
"""Return attached provider/table metadata (copy to avoid mutation)."""
|
||||
try:
|
||||
return dict(self.table_metadata)
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
def set_no_choice(self, no_choice: bool = True) -> "ResultTable":
|
||||
"""Mark the table as non-interactive (no row numbers, no selection parsing)."""
|
||||
self.no_choice = bool(no_choice)
|
||||
@@ -612,6 +629,9 @@ class ResultTable:
|
||||
new_table.input_options = dict(self.input_options) if self.input_options else {}
|
||||
new_table.no_choice = self.no_choice
|
||||
new_table.table = self.table
|
||||
new_table.table_metadata = (
|
||||
dict(self.table_metadata) if getattr(self, "table_metadata", None) else {}
|
||||
)
|
||||
new_table.header_lines = list(self.header_lines) if self.header_lines else []
|
||||
return new_table
|
||||
|
||||
@@ -712,6 +732,7 @@ class ResultTable:
|
||||
Self for chaining
|
||||
"""
|
||||
row = self.add_row()
|
||||
row.payload = result
|
||||
|
||||
# Handle TagItem from get_tag.py (tag display with index)
|
||||
if hasattr(result, "__class__") and result.__class__.__name__ == "TagItem":
|
||||
@@ -738,6 +759,21 @@ class ResultTable:
|
||||
|
||||
return self
|
||||
|
||||
def get_row_payload(self, row_index: int) -> Optional[Any]:
|
||||
"""Return the original payload for the row at ``row_index`` if available."""
|
||||
if 0 <= row_index < len(self.rows):
|
||||
return getattr(self.rows[row_index], "payload", None)
|
||||
return None
|
||||
|
||||
def get_payloads(self) -> List[Any]:
|
||||
"""Return the payloads for every row, preserving table order."""
|
||||
payloads: List[Any] = []
|
||||
for row in self.rows:
|
||||
payload = getattr(row, "payload", None)
|
||||
if payload is not None:
|
||||
payloads.append(payload)
|
||||
return payloads
|
||||
|
||||
def _add_search_result(self, row: ResultRow, result: Any) -> None:
|
||||
"""Extract and add SearchResult fields to row."""
|
||||
# If provider supplied explicit columns, render those and skip legacy defaults
|
||||
|
||||
@@ -11,9 +11,11 @@ from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import sys
|
||||
from typing import Any, Iterator, TextIO
|
||||
from typing import Any, Iterator, Sequence, TextIO
|
||||
|
||||
from rich.console import Console
|
||||
from rich.panel import Panel
|
||||
from rich.text import Text
|
||||
|
||||
# Configure Rich pretty-printing to avoid truncating long strings (hashes/paths).
|
||||
# This is version-safe: older Rich versions may not support the max_* arguments.
|
||||
@@ -70,3 +72,33 @@ def capture_rich_output(*, stdout: TextIO, stderr: TextIO) -> Iterator[None]:
|
||||
finally:
|
||||
_STDOUT_CONSOLE = previous_stdout
|
||||
_STDERR_CONSOLE = previous_stderr
|
||||
|
||||
|
||||
def show_provider_config_panel(
|
||||
provider_name: str,
|
||||
keys: Sequence[str] | None = None,
|
||||
*,
|
||||
config_hint: str = "config.conf"
|
||||
) -> None:
|
||||
"""Show a Rich panel explaining how to configure a provider."""
|
||||
|
||||
normalized = str(provider_name or "").strip() or "provider"
|
||||
pre = Text("Add this to your config", style="bold")
|
||||
footer = Text(
|
||||
f"Place this block in {config_hint} or config.d/*.conf",
|
||||
style="dim"
|
||||
)
|
||||
body = Text()
|
||||
body.append(f"[provider={normalized}]\n", style="bold cyan")
|
||||
for key in keys or []:
|
||||
body.append(f'{key}=""\n', style="yellow")
|
||||
|
||||
stderr_console().print(pre)
|
||||
stderr_console().print(
|
||||
Panel(
|
||||
body,
|
||||
title=f"{normalized} configuration",
|
||||
expand=False
|
||||
)
|
||||
)
|
||||
stderr_console().print(footer)
|
||||
|
||||
Reference in New Issue
Block a user