fdsfjlk
This commit is contained in:
166
CLI.py
166
CLI.py
@@ -636,6 +636,7 @@ if (
|
||||
and Completion is not None
|
||||
and Completer is not None
|
||||
and Document is not None
|
||||
and Lexer is not None
|
||||
):
|
||||
CompletionType = cast(Any, Completion)
|
||||
|
||||
@@ -934,7 +935,11 @@ def _create_cmdlet_cli():
|
||||
prompt_text = "🜂🜄🜁🜃|"
|
||||
|
||||
# Prepare startup table (always attempt; fall back gracefully if import fails)
|
||||
startup_table = ResultTable("*********<IGNITIO>*********<NOUSEMPEH>*********<RUGRAPOG>*********<OMEGHAU>*********") if RESULT_TABLE_AVAILABLE else None
|
||||
startup_table = None
|
||||
if RESULT_TABLE_AVAILABLE and ResultTable is not None:
|
||||
startup_table = ResultTable(
|
||||
"*********<IGNITIO>*********<NOUSEMPEH>*********<RUGRAPOG>*********<OMEGHAU>*********"
|
||||
)
|
||||
if startup_table:
|
||||
startup_table.set_no_choice(True).set_preserve_order(True)
|
||||
|
||||
@@ -1173,7 +1178,7 @@ def _create_cmdlet_cli():
|
||||
|
||||
api_key = _get_debrid_api_key(config)
|
||||
if not api_key:
|
||||
_add_startup_check("DISABLED", display, prov, "Not configured")
|
||||
_add_startup_check("DISABLED", display, provider=prov, detail="Not configured")
|
||||
else:
|
||||
from API.alldebrid import AllDebridClient
|
||||
|
||||
@@ -1347,7 +1352,7 @@ def _create_cmdlet_cli():
|
||||
except Exception:
|
||||
pass # Silently ignore if config loading fails
|
||||
|
||||
if PROMPT_TOOLKIT_AVAILABLE and PromptSession is not None and CmdletCompleter is not None:
|
||||
if PROMPT_TOOLKIT_AVAILABLE and PromptSession is not None and CmdletCompleter is not None and Style is not None:
|
||||
completer = CmdletCompleter()
|
||||
|
||||
# Define style for syntax highlighting
|
||||
@@ -1363,7 +1368,7 @@ def _create_cmdlet_cli():
|
||||
# Toolbar state for background notifications
|
||||
class ToolbarState:
|
||||
text = ""
|
||||
last_update_time = 0
|
||||
last_update_time: float = 0.0
|
||||
clear_timer: Optional[threading.Timer] = None
|
||||
|
||||
toolbar_state = ToolbarState()
|
||||
@@ -1677,6 +1682,112 @@ def _execute_pipeline(tokens: list):
|
||||
if isinstance(config, dict):
|
||||
# Request terminal-only background updates for this pipeline session
|
||||
config['_quiet_background_output'] = True
|
||||
|
||||
def _maybe_run_class_selector(selected_items: list, *, stage_is_last: bool) -> bool:
|
||||
"""Allow providers/stores to override `@N` selection semantics."""
|
||||
if not stage_is_last:
|
||||
return False
|
||||
|
||||
# Gather potential keys from table + selected rows.
|
||||
candidates: list[str] = []
|
||||
seen: set[str] = set()
|
||||
|
||||
def _add(value) -> None:
|
||||
try:
|
||||
text = str(value or '').strip().lower()
|
||||
except Exception:
|
||||
return
|
||||
if not text or text in seen:
|
||||
return
|
||||
seen.add(text)
|
||||
candidates.append(text)
|
||||
|
||||
try:
|
||||
current_table = ctx.get_current_stage_table() or ctx.get_last_result_table()
|
||||
_add(current_table.table if current_table and hasattr(current_table, 'table') else None)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
for item in selected_items or []:
|
||||
if isinstance(item, dict):
|
||||
_add(item.get('provider'))
|
||||
_add(item.get('store'))
|
||||
_add(item.get('table'))
|
||||
else:
|
||||
_add(getattr(item, 'provider', None))
|
||||
_add(getattr(item, 'store', None))
|
||||
_add(getattr(item, 'table', None))
|
||||
|
||||
# Provider selector
|
||||
try:
|
||||
from ProviderCore.registry import get_provider as _get_provider
|
||||
except Exception:
|
||||
_get_provider = None
|
||||
|
||||
if _get_provider is not None:
|
||||
for key in candidates:
|
||||
try:
|
||||
provider = _get_provider(key, config)
|
||||
except Exception:
|
||||
continue
|
||||
try:
|
||||
handled = bool(provider.selector(selected_items, ctx=ctx, stage_is_last=True))
|
||||
except TypeError:
|
||||
# Backwards-compat: selector(selected_items)
|
||||
handled = bool(provider.selector(selected_items))
|
||||
except Exception as exc:
|
||||
print(f"{key} selector failed: {exc}\n")
|
||||
return True
|
||||
if handled:
|
||||
return True
|
||||
|
||||
# Store selector
|
||||
store_keys: list[str] = []
|
||||
for item in selected_items or []:
|
||||
if isinstance(item, dict):
|
||||
v = item.get('store')
|
||||
else:
|
||||
v = getattr(item, 'store', None)
|
||||
try:
|
||||
name = str(v or '').strip()
|
||||
except Exception:
|
||||
name = ''
|
||||
if name:
|
||||
store_keys.append(name)
|
||||
|
||||
if store_keys:
|
||||
try:
|
||||
from Store.registry import Store as _StoreRegistry
|
||||
store_registry = _StoreRegistry(config, suppress_debug=True)
|
||||
try:
|
||||
_backend_names = list(store_registry.list_backends())
|
||||
except Exception:
|
||||
_backend_names = []
|
||||
_backend_by_lower = {str(n).lower(): str(n) for n in _backend_names if str(n).strip()}
|
||||
for name in store_keys:
|
||||
resolved_name = name
|
||||
if not store_registry.is_available(resolved_name):
|
||||
try:
|
||||
resolved_name = _backend_by_lower.get(str(name).lower(), name)
|
||||
except Exception:
|
||||
resolved_name = name
|
||||
if not store_registry.is_available(resolved_name):
|
||||
continue
|
||||
backend = store_registry[resolved_name]
|
||||
selector = getattr(backend, 'selector', None)
|
||||
if selector is None:
|
||||
continue
|
||||
try:
|
||||
handled = bool(selector(selected_items, ctx=ctx, stage_is_last=True))
|
||||
except TypeError:
|
||||
handled = bool(selector(selected_items))
|
||||
if handled:
|
||||
return True
|
||||
except Exception:
|
||||
# Store init failure should not break normal selection.
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
# Check if the first stage has @ selection - if so, apply it before pipeline execution
|
||||
first_stage_tokens = stages[0] if stages else []
|
||||
@@ -1827,6 +1938,10 @@ def _execute_pipeline(tokens: list):
|
||||
try:
|
||||
filtered = [resolved_items[i] for i in first_stage_selection_indices if 0 <= i < len(resolved_items)]
|
||||
if filtered:
|
||||
# Allow providers/stores to override selection behavior (e.g., Matrix room picker).
|
||||
if _maybe_run_class_selector(filtered, stage_is_last=(not stages)):
|
||||
return
|
||||
|
||||
# Convert filtered items to PipeObjects for consistent pipeline handling
|
||||
from cmdlet._shared import coerce_to_pipe_object
|
||||
filtered_pipe_objs = [coerce_to_pipe_object(item) for item in filtered]
|
||||
@@ -2011,17 +2126,21 @@ def _execute_pipeline(tokens: list):
|
||||
# If not expanding, use as filter
|
||||
if not should_expand_to_command:
|
||||
# This is a selection stage - filter piped results
|
||||
# Prefer selecting from the active result context even when nothing is piped.
|
||||
# Some cmdlets present a selectable table and rely on @N afterwards.
|
||||
if piped_result is None:
|
||||
print(f"No piped results to select from with {cmd_name}\n")
|
||||
pipeline_status = "failed"
|
||||
pipeline_error = f"Selection {cmd_name} without upstream results"
|
||||
return
|
||||
|
||||
# Normalize piped_result to always be a list for indexing
|
||||
if isinstance(piped_result, dict) or not isinstance(piped_result, (list, tuple)):
|
||||
piped_result_list = [piped_result]
|
||||
piped_result_list = ctx.get_last_result_items()
|
||||
if not piped_result_list:
|
||||
print(f"No piped results to select from with {cmd_name}\n")
|
||||
pipeline_status = "failed"
|
||||
pipeline_error = f"Selection {cmd_name} without upstream results"
|
||||
return
|
||||
else:
|
||||
piped_result_list = piped_result
|
||||
# Normalize piped_result to always be a list for indexing
|
||||
if isinstance(piped_result, dict) or not isinstance(piped_result, (list, tuple)):
|
||||
piped_result_list = [piped_result]
|
||||
else:
|
||||
piped_result_list = piped_result
|
||||
|
||||
# Get indices to select
|
||||
if is_select_all:
|
||||
@@ -2038,12 +2157,29 @@ def _execute_pipeline(tokens: list):
|
||||
stage_table = ctx.get_display_table()
|
||||
if not stage_table:
|
||||
stage_table = ctx.get_last_result_table()
|
||||
resolved_list = _resolve_items_for_selection(stage_table, list(piped_result_list))
|
||||
_debug_selection("pipeline-stage", selection_indices, stage_table, piped_result_list, resolved_list)
|
||||
# Prefer selecting from the displayed table's items if available.
|
||||
# This matters when a cmdlet shows a selectable overlay table but does not emit
|
||||
# items downstream (e.g., add-file -provider matrix shows rooms, but the piped
|
||||
# value is still the original file).
|
||||
selection_base = list(piped_result_list)
|
||||
try:
|
||||
table_rows = len(stage_table.rows) if stage_table and hasattr(stage_table, 'rows') and stage_table.rows else None
|
||||
last_items = ctx.get_last_result_items()
|
||||
if last_items and table_rows is not None and len(last_items) == table_rows:
|
||||
selection_base = list(last_items)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
resolved_list = _resolve_items_for_selection(stage_table, selection_base)
|
||||
_debug_selection("pipeline-stage", selection_indices, stage_table, selection_base, resolved_list)
|
||||
|
||||
try:
|
||||
filtered = [resolved_list[i] for i in selection_indices if 0 <= i < len(resolved_list)]
|
||||
if filtered:
|
||||
# Allow providers/stores to override selection behavior (e.g., Matrix room picker).
|
||||
if _maybe_run_class_selector(filtered, stage_is_last=(stage_index + 1 >= len(stages))):
|
||||
return
|
||||
|
||||
# Convert filtered items to PipeObjects for consistent pipeline handling
|
||||
from cmdlet._shared import coerce_to_pipe_object
|
||||
filtered_pipe_objs = [coerce_to_pipe_object(item) for item in filtered]
|
||||
|
||||
Reference in New Issue
Block a user