""" Pipeline state management for cmdlet. """ from __future__ import annotations import sys import time import re from contextlib import contextmanager from dataclasses import dataclass, field from contextvars import ContextVar from typing import Any, Dict, List, Optional, Sequence, Callable from SYS.models import PipelineStageContext from SYS.logger import log, debug, debug_panel, is_debug_enabled import logging logger = logging.getLogger(__name__) # SYS.worker deferred: ffmpeg+attr+rich (~260ms) loaded lazily on first pipeline run. _worker_mod: Any = None # SYS.cli_parsing deferred: prompt_toolkit (~300ms) loaded lazily on first selection. _cli_parsing_mod: Any = None # SYS.result_table deferred: textual (~140ms) loaded lazily on first Table use. _result_table_mod: Any = None def _worker() -> Any: global _worker_mod if _worker_mod is None: import SYS.worker as _m _worker_mod = _m return _worker_mod def _cli_parsing() -> Any: global _cli_parsing_mod if _cli_parsing_mod is None: import SYS.cli_parsing as _m _cli_parsing_mod = _m return _cli_parsing_mod def _result_table() -> Any: global _result_table_mod if _result_table_mod is None: from SYS.result_table import Table as _T _result_table_mod = _T return _result_table_mod HELP_EXAMPLE_SOURCE_COMMANDS = { ".help-example", "help-example", } # --------------------------------------------------------------------------- # Helper functions # --------------------------------------------------------------------------- def _emit_selection_debug_panel( *, selection_token: Any, selection_indices: Sequence[int], item_count: int, filtered_count: int, stage_table_present: bool, display_table_present: bool, stage_is_last: bool, row_action: Optional[Sequence[Any]] = None, downstream_stages: Optional[Sequence[Sequence[Any]]] = None, mode: Optional[str] = None, ) -> None: if not is_debug_enabled(): return try: rows: List[tuple[str, Any]] = [ ("selection", str(selection_token or "")), ("indices", [int(idx) + 1 for idx in (selection_indices or [])]), ("items", int(item_count)), ("filtered", int(filtered_count)), ("stage_table", bool(stage_table_present)), ("display_table", bool(display_table_present)), ("stage_is_last", bool(stage_is_last)), ("downstream_stages", len(list(downstream_stages or []))), ] if mode: rows.insert(1, ("mode", str(mode))) if row_action: rows.append( ("row_action", " ".join(str(part) for part in row_action if part is not None)) ) debug_panel( f"Selection replay {selection_token}", rows, border_style="magenta", ) except Exception: pass def set_live_progress(progress_ui: Any) -> None: state = _get_pipeline_state() state.live_progress = progress_ui def get_live_progress() -> Any: state = _get_pipeline_state() return state.live_progress def set_progress_event_callback(callback: Any) -> None: state = _get_pipeline_state() state.progress_event_callback = callback def get_progress_event_callback() -> Any: state = _get_pipeline_state() return state.progress_event_callback @contextmanager def suspend_live_progress() -> Any: ui = get_live_progress() paused = False try: if ui is not None and hasattr(ui, "pause"): try: ui.pause() paused = True except Exception as exc: logger.exception("Failed to pause live progress UI: %s", exc) paused = False yield finally: if get_pipeline_stop() is None: if paused and ui is not None and hasattr(ui, "resume"): try: ui.resume() except Exception: logger.exception("Failed to resume live progress UI after suspend") def _is_selectable_table(table: Any) -> bool: return table is not None and not getattr(table, "no_choice", False) # --------------------------------------------------------------------------- # PipelineState # --------------------------------------------------------------------------- @dataclass class PipelineState: current_context: Optional[PipelineStageContext] = None last_search_query: Optional[str] = None pipeline_refreshed: bool = False last_items: List[Any] = field(default_factory=list) last_result_table: Optional[Any] = None last_result_items: List[Any] = field(default_factory=list) last_result_subject: Optional[Any] = None result_table_history: List[tuple[Optional[Any], List[Any], Optional[Any]]] = field( default_factory=list ) result_table_forward: List[tuple[Optional[Any], List[Any], Optional[Any]]] = field( default_factory=list ) current_stage_table: Optional[Any] = None display_items: List[Any] = field(default_factory=list) display_table: Optional[Any] = None display_subject: Optional[Any] = None last_selection: List[int] = field(default_factory=list) pipeline_command_text: str = "" current_cmdlet_name: str = "" current_stage_text: str = "" pipeline_values: Dict[str, Any] = field(default_factory=dict) pending_pipeline_tail: List[List[str]] = field(default_factory=list) pending_pipeline_source: Optional[str] = None ui_library_refresh_callback: Optional[Any] = None pipeline_stop: Optional[Dict[str, Any]] = None live_progress: Any = None last_execution_result: Dict[str, Any] = field(default_factory=dict) progress_event_callback: Any = None def reset(self) -> None: self.current_context = None self.last_search_query = None self.pipeline_refreshed = False self.last_items = [] self.last_result_table = None self.last_result_items = [] self.last_result_subject = None self.result_table_history = [] self.result_table_forward = [] self.current_stage_table = None self.display_items = [] self.display_table = None self.display_subject = None self.last_selection = [] self.pipeline_command_text = "" self.current_cmdlet_name = "" self.current_stage_text = "" self.pipeline_values = {} self.pending_pipeline_tail = [] self.pending_pipeline_source = None self.ui_library_refresh_callback = None self.pipeline_stop = None self.live_progress = None self.last_execution_result = {} self.progress_event_callback = None # --------------------------------------------------------------------------- # ContextVar and global fallback # --------------------------------------------------------------------------- _CTX_STATE: ContextVar[Optional[PipelineState]] = ContextVar("_pipeline_state", default=None) _GLOBAL_STATE: PipelineState = PipelineState() def _get_pipeline_state() -> PipelineState: state = _CTX_STATE.get() return state if state is not None else _GLOBAL_STATE @contextmanager def new_pipeline_state() -> Any: token = _CTX_STATE.set(PipelineState()) try: yield _CTX_STATE.get() finally: _CTX_STATE.reset(token) def get_pipeline_state() -> PipelineState: return _get_pipeline_state() # --------------------------------------------------------------------------- # Constants # --------------------------------------------------------------------------- MAX_RESULT_TABLE_HISTORY = 20 PIPELINE_MISSING = object() # --------------------------------------------------------------------------- # Pipeline stop # --------------------------------------------------------------------------- def request_pipeline_stop(*, reason: str = "", exit_code: int = 0) -> None: state = _get_pipeline_state() state.pipeline_stop = { "reason": str(reason or "").strip(), "exit_code": int(exit_code), } def get_pipeline_stop() -> Optional[Dict[str, Any]]: state = _get_pipeline_state() return state.pipeline_stop def clear_pipeline_stop() -> None: state = _get_pipeline_state() state.pipeline_stop = None # --------------------------------------------------------------------------- # Stage context # --------------------------------------------------------------------------- def set_stage_context(context: Optional[PipelineStageContext]) -> None: state = _get_pipeline_state() state.current_context = context def get_stage_context() -> Optional[PipelineStageContext]: state = _get_pipeline_state() return state.current_context # --------------------------------------------------------------------------- # Emit helpers # --------------------------------------------------------------------------- def emit(obj: Any) -> None: ctx = _get_pipeline_state().current_context if ctx is not None: ctx.emit(obj) def emit_list(objects: List[Any]) -> None: ctx = _get_pipeline_state().current_context if ctx is not None: ctx.emit(objects) def print_if_visible(*args: Any, file: Any = None, **kwargs: Any) -> None: try: ctx = _get_pipeline_state().current_context should_print = (ctx is None) or (ctx and ctx.is_last_stage) if file is not None: should_print = True if should_print: log(*args, **kwargs) if file is None else log(*args, file=file, **kwargs) except Exception: logger.exception("Error in print_if_visible") # --------------------------------------------------------------------------- # Pipeline values # --------------------------------------------------------------------------- def store_value(key: str, value: Any) -> None: if not isinstance(key, str): return text = key.strip().lower() if not text: return try: state = _get_pipeline_state() state.pipeline_values[text] = value except Exception: logger.exception("Failed to store pipeline value '%s'", key) def load_value(key: str, default: Any = None) -> Any: if not isinstance(key, str): return default text = key.strip() if not text: return default parts = [segment.strip() for segment in text.split(".") if segment.strip()] if not parts: return default root_key = parts[0].lower() state = _get_pipeline_state() container = state.pipeline_values.get(root_key, PIPELINE_MISSING) if container is PIPELINE_MISSING: return default if len(parts) == 1: return container current: Any = container for fragment in parts[1:]: if isinstance(current, dict): fragment_lower = fragment.lower() if fragment in current: current = current[fragment] continue match = PIPELINE_MISSING for key_name, value in current.items(): if isinstance(key_name, str) and key_name.lower() == fragment_lower: match = value break if match is PIPELINE_MISSING: return default current = match continue if isinstance(current, (list, tuple)): if fragment.isdigit(): try: idx = int(fragment) except ValueError: return default if 0 <= idx < len(current): current = current[idx] continue return default if hasattr(current, fragment): try: current = getattr(current, fragment) continue except Exception: return default return default return current # --------------------------------------------------------------------------- # Execution result # --------------------------------------------------------------------------- def set_last_execution_result( *, status: str, error: str = "", command_text: str = "", ) -> None: state = _get_pipeline_state() text_status = str(status or "").strip().lower() or "unknown" state.last_execution_result = { "status": text_status, "success": text_status == "completed", "error": str(error or "").strip(), "command_text": str(command_text or "").strip(), "finished_at": time.time(), } def get_last_execution_result() -> Dict[str, Any]: state = _get_pipeline_state() payload = state.last_execution_result return dict(payload) if isinstance(payload, dict) else {} # --------------------------------------------------------------------------- # Pending pipeline tail # --------------------------------------------------------------------------- def set_pending_pipeline_tail( stages: Optional[Sequence[Sequence[str]]], source_command: Optional[str] = None, ) -> None: state = _get_pipeline_state() try: pending: List[List[str]] = [] for stage in stages or []: if isinstance(stage, (list, tuple)): pending.append([str(token) for token in stage]) state.pending_pipeline_tail = pending clean_source = (source_command or "").strip() state.pending_pipeline_source = clean_source if clean_source else None except Exception: logger.exception("Failed to set pending pipeline tail; keeping existing pending tail") def get_pending_pipeline_tail() -> List[List[str]]: state = _get_pipeline_state() return [list(stage) for stage in state.pending_pipeline_tail] def get_pending_pipeline_source() -> Optional[str]: state = _get_pipeline_state() return state.pending_pipeline_source def clear_pending_pipeline_tail() -> None: state = _get_pipeline_state() state.pending_pipeline_tail = [] state.pending_pipeline_source = None # --------------------------------------------------------------------------- # Reset # --------------------------------------------------------------------------- def reset() -> None: state = _get_pipeline_state() state.reset() # --------------------------------------------------------------------------- # Emitted items # --------------------------------------------------------------------------- def get_emitted_items() -> List[Any]: state = _get_pipeline_state() ctx = state.current_context if ctx is not None: return list(ctx.emits) return [] def clear_emits() -> None: state = _get_pipeline_state() ctx = state.current_context if ctx is not None: ctx.emits.clear() # --------------------------------------------------------------------------- # Selection # --------------------------------------------------------------------------- def set_last_selection(indices: Sequence[int]) -> None: state = _get_pipeline_state() state.last_selection = list(indices or []) def get_last_selection() -> List[int]: state = _get_pipeline_state() return list(state.last_selection) def clear_last_selection() -> None: state = _get_pipeline_state() state.last_selection = [] # --------------------------------------------------------------------------- # Command text # --------------------------------------------------------------------------- def set_current_command_text(command_text: Optional[str]) -> None: state = _get_pipeline_state() state.pipeline_command_text = (command_text or "").strip() def get_current_command_text(default: str = "") -> str: state = _get_pipeline_state() text = state.pipeline_command_text.strip() return text if text else default def clear_current_command_text() -> None: state = _get_pipeline_state() state.pipeline_command_text = "" # --------------------------------------------------------------------------- # Pipeline text splitting # --------------------------------------------------------------------------- def split_pipeline_text(pipeline_text: str) -> List[str]: text = str(pipeline_text or "") if not text: return [] stages: List[str] = [] buf: List[str] = [] quote: Optional[str] = None escape = False for ch in text: if escape: buf.append(ch) escape = False continue if ch == "\\" and quote is not None: buf.append(ch) escape = True continue if ch in ('"', "'"): if quote is None: quote = ch elif quote == ch: quote = None buf.append(ch) continue if ch == "|" and quote is None: stages.append("".join(buf).strip()) buf = [] continue buf.append(ch) tail = "".join(buf).strip() if tail: stages.append(tail) return [s for s in stages if s] def get_current_command_stages() -> List[str]: return split_pipeline_text(get_current_command_text("")) # --------------------------------------------------------------------------- # Stage text # --------------------------------------------------------------------------- def set_current_stage_text(stage_text: Optional[str]) -> None: state = _get_pipeline_state() state.current_stage_text = str(stage_text or "").strip() def get_current_stage_text(default: str = "") -> str: state = _get_pipeline_state() text = state.current_stage_text.strip() return text if text else default def clear_current_stage_text() -> None: state = _get_pipeline_state() state.current_stage_text = "" # --------------------------------------------------------------------------- # Cmdlet name # --------------------------------------------------------------------------- def set_current_cmdlet_name(cmdlet_name: Optional[str]) -> None: state = _get_pipeline_state() state.current_cmdlet_name = str(cmdlet_name or "").strip() def get_current_cmdlet_name(default: str = "") -> str: state = _get_pipeline_state() text = state.current_cmdlet_name.strip() return text if text else default def clear_current_cmdlet_name() -> None: state = _get_pipeline_state() state.current_cmdlet_name = "" # --------------------------------------------------------------------------- # Search query # --------------------------------------------------------------------------- def set_search_query(query: Optional[str]) -> None: state = _get_pipeline_state() state.last_search_query = query def get_search_query() -> Optional[str]: state = _get_pipeline_state() return state.last_search_query # --------------------------------------------------------------------------- # Refresh tracking # --------------------------------------------------------------------------- def set_pipeline_refreshed(refreshed: bool) -> None: state = _get_pipeline_state() state.pipeline_refreshed = refreshed def was_pipeline_refreshed() -> bool: state = _get_pipeline_state() return state.pipeline_refreshed # --------------------------------------------------------------------------- # Last items # --------------------------------------------------------------------------- def set_last_items(items: list) -> None: state = _get_pipeline_state() state.last_items = list(items) if items else [] def get_last_items() -> List[Any]: state = _get_pipeline_state() return list(state.last_items) # --------------------------------------------------------------------------- # UI library refresh callback # --------------------------------------------------------------------------- def set_ui_library_refresh_callback(callback: Any) -> None: state = _get_pipeline_state() state.ui_library_refresh_callback = callback def get_ui_library_refresh_callback() -> Optional[Any]: state = _get_pipeline_state() return state.ui_library_refresh_callback def trigger_ui_library_refresh(library_filter: str = "local") -> None: callback = get_ui_library_refresh_callback() if callback: try: callback(library_filter) except Exception as e: print( f"[trigger_ui_library_refresh] Error calling refresh callback: {e}", file=sys.stderr, ) # --------------------------------------------------------------------------- # Result table: set (push to history) # --------------------------------------------------------------------------- def set_last_result_table( result_table: Optional[Any], items: Optional[List[Any]] = None, subject: Optional[Any] = None, ) -> None: state = _get_pipeline_state() if state.last_result_table is not None: state.result_table_history.append( ( state.last_result_table, state.last_result_items, state.last_result_subject, ) ) if len(state.result_table_history) > MAX_RESULT_TABLE_HISTORY: state.result_table_history.pop(0) state.display_items = [] state.display_table = None state.display_subject = None state.last_result_table = result_table state.last_result_items = items or [] state.last_result_subject = subject if ( result_table is not None and hasattr(result_table, "sort_by_title") and not getattr(result_table, "preserve_order", False) ): try: result_table.sort_by_title() if state.last_result_items and hasattr(result_table, "rows"): sorted_items: List[Any] = [] for row in result_table.rows: src_idx = getattr(row, "source_index", None) if isinstance(src_idx, int) and 0 <= src_idx < len(state.last_result_items): sorted_items.append(state.last_result_items[src_idx]) if result_table.rows and len(sorted_items) == len(result_table.rows): state.last_result_items = sorted_items except Exception: logger.exception("Failed to sort result_table and reorder items") # --------------------------------------------------------------------------- # Result table: overlay (no history push) # --------------------------------------------------------------------------- def set_last_result_table_overlay( result_table: Optional[Any], items: Optional[List[Any]] = None, subject: Optional[Any] = None, ) -> None: state = _get_pipeline_state() state.display_table = result_table state.display_items = items or [] state.display_subject = subject # --------------------------------------------------------------------------- # Result table: items only (no history, no table) # --------------------------------------------------------------------------- def set_last_result_items_only(items: Optional[List[Any]]) -> None: state = _get_pipeline_state() state.display_items = items or [] state.display_table = None state.display_subject = None # --------------------------------------------------------------------------- # Result table history navigation (consolidated) # --------------------------------------------------------------------------- def _restore_result_table(forward: bool) -> bool: """Consolidated implementation for restore_previous/restore_next_result_table.""" state = _get_pipeline_state() pop_stack = state.result_table_forward if forward else state.result_table_history push_stack = state.result_table_history if forward else state.result_table_forward label = "restore_next_result_table" if forward else "restore_previous_result_table" if state.display_items or state.display_table or state.display_subject is not None: state.display_items = [] state.display_table = None state.display_subject = None if state.last_result_table is not None: state.current_stage_table = state.last_result_table return True if not pop_stack: state.current_stage_table = state.last_result_table return True if not pop_stack: return False push_stack.append( (state.last_result_table, state.last_result_items, state.last_result_subject) ) prev = pop_stack.pop() if isinstance(prev, tuple) and len(prev) >= 3: state.last_result_table, state.last_result_items, state.last_result_subject = ( prev[0], prev[1], prev[2], ) elif isinstance(prev, tuple) and len(prev) == 2: state.last_result_table, state.last_result_items = prev state.last_result_subject = None else: state.last_result_table, state.last_result_items, state.last_result_subject = None, [], None state.display_items = [] state.display_table = None state.display_subject = None state.current_stage_table = state.last_result_table try: debug_table_state(label) except Exception: logger.exception("Failed to debug_table_state during %s", label) return True def restore_previous_result_table() -> bool: return _restore_result_table(forward=False) def restore_next_result_table() -> bool: return _restore_result_table(forward=True) # --------------------------------------------------------------------------- # Display table accessors # --------------------------------------------------------------------------- def get_display_table() -> Optional[Any]: state = _get_pipeline_state() return state.display_table def get_last_result_subject() -> Optional[Any]: state = _get_pipeline_state() if state.display_subject is not None: return state.display_subject return state.last_result_subject def get_last_result_table() -> Optional[Any]: state = _get_pipeline_state() return state.last_result_table def get_last_result_items() -> List[Any]: state = _get_pipeline_state() if state.display_items: if state.display_table is not None and not _is_selectable_table(state.display_table): return [] return state.display_items if state.last_result_table is None: return state.last_result_items if _is_selectable_table(state.last_result_table): return state.last_result_items return [] # --------------------------------------------------------------------------- # Debug table state # --------------------------------------------------------------------------- def debug_table_state(label: str = "") -> None: if not is_debug_enabled(): return state = _get_pipeline_state() def _tbl(name: str, t: Any) -> None: if t is None: debug(f"[table] {name}: None") return try: table_type = getattr(t, "table", None) except Exception: table_type = None try: title = getattr(t, "title", None) except Exception: title = None try: src_cmd = getattr(t, "source_command", None) except Exception: src_cmd = None try: src_args = getattr(t, "source_args", None) except Exception: src_args = None try: no_choice = bool(getattr(t, "no_choice", False)) except Exception: no_choice = False try: preserve_order = bool(getattr(t, "preserve_order", False)) except Exception: preserve_order = False try: row_count = len(getattr(t, "rows", []) or []) except Exception: row_count = 0 try: meta = ( t.get_table_metadata() if hasattr(t, "get_table_metadata") else getattr(t, "table_metadata", None) ) except Exception: meta = None meta_keys = list(meta.keys()) if isinstance(meta, dict) else [] debug( f"[table] {name}: id={id(t)} class={type(t).__name__} title={repr(title)} table={repr(table_type)} rows={row_count} " f"source={repr(src_cmd)} source_args={repr(src_args)} no_choice={no_choice} preserve_order={preserve_order} meta_keys={meta_keys}" ) if label: debug(f"[table] state: {label}") _tbl("display_table", getattr(state, "display_table", None)) _tbl("current_stage_table", getattr(state, "current_stage_table", None)) _tbl("last_result_table", getattr(state, "last_result_table", None)) try: debug( f"[table] buffers: display_items={len(state.display_items or [])} last_result_items={len(state.last_result_items or [])} " f"history={len(state.result_table_history or [])} forward={len(state.result_table_forward or [])} last_selection={list(state.last_selection or [])}" ) except Exception: logger.exception("Failed to debug_table_state buffers summary") # --------------------------------------------------------------------------- # Selectable result items # --------------------------------------------------------------------------- def get_last_selectable_result_items() -> List[Any]: state = _get_pipeline_state() if state.last_result_table is None: return list(state.last_result_items) if _is_selectable_table(state.last_result_table): return list(state.last_result_items) return [] # --------------------------------------------------------------------------- # Table source command/args accessors (consolidated helpers) # --------------------------------------------------------------------------- def _get_table_source_command(table: Any) -> Optional[str]: if table is not None and _is_selectable_table(table) and hasattr(table, "source_command"): return getattr(table, "source_command") return None def _get_table_source_args(table: Any) -> List[str]: if table is not None and _is_selectable_table(table) and hasattr(table, "source_args"): return getattr(table, "source_args") or [] return [] def _get_table_row_selection_args(table: Any, row_index: int) -> Optional[List[str]]: if table is not None and _is_selectable_table(table) and hasattr(table, "rows"): rows = table.rows if 0 <= row_index < len(rows): row = rows[row_index] if hasattr(row, "selection_args"): return getattr(row, "selection_args") return None def _get_table_row_selection_action(table: Any, row_index: int) -> Optional[List[str]]: if table is not None and _is_selectable_table(table) and hasattr(table, "rows"): rows = table.rows if 0 <= row_index < len(rows): row = rows[row_index] if hasattr(row, "selection_action"): return getattr(row, "selection_action") return None # --------------------------------------------------------------------------- # Public table accessor functions (delegate to helpers) # --------------------------------------------------------------------------- def get_last_result_table_source_command() -> Optional[str]: state = _get_pipeline_state() return _get_table_source_command(state.last_result_table) def get_last_result_table_source_args() -> List[str]: state = _get_pipeline_state() return _get_table_source_args(state.last_result_table) def get_last_result_table_row_selection_args(row_index: int) -> Optional[List[str]]: state = _get_pipeline_state() return _get_table_row_selection_args(state.last_result_table, row_index) def get_last_result_table_row_selection_action(row_index: int) -> Optional[List[str]]: state = _get_pipeline_state() return _get_table_row_selection_action(state.last_result_table, row_index) def get_current_stage_table() -> Optional[Any]: state = _get_pipeline_state() return state.current_stage_table def set_current_stage_table(result_table: Optional[Any]) -> None: state = _get_pipeline_state() state.current_stage_table = result_table def get_current_stage_table_source_command() -> Optional[str]: state = _get_pipeline_state() return _get_table_source_command(state.current_stage_table) def get_current_stage_table_source_args() -> List[str]: state = _get_pipeline_state() return _get_table_source_args(state.current_stage_table) def get_current_stage_table_row_selection_args(row_index: int) -> Optional[List[str]]: state = _get_pipeline_state() return _get_table_row_selection_args(state.current_stage_table, row_index) def get_current_stage_table_row_selection_action(row_index: int) -> Optional[List[str]]: state = _get_pipeline_state() return _get_table_row_selection_action(state.current_stage_table, row_index) def get_current_stage_table_row_source_index(row_index: int) -> Optional[int]: state = _get_pipeline_state() table = state.current_stage_table if table is not None and _is_selectable_table(table) and hasattr(table, "rows"): rows = table.rows if 0 <= row_index < len(rows): row = rows[row_index] return getattr(row, "source_index", None) return None def clear_last_result() -> None: state = _get_pipeline_state() state.last_result_table = None state.last_result_items = [] state.last_result_subject = None # --------------------------------------------------------------------------- # Pipeline token splitting (used by executor) # --------------------------------------------------------------------------- def _split_pipeline_tokens(tokens: Sequence[str]) -> List[List[str]]: stages: List[List[str]] = [] current: List[str] = [] for token in tokens: if token == "|": if current: stages.append(current) current = [] continue current.append(str(token)) if current: stages.append(current) return [stage for stage in stages if stage] # --------------------------------------------------------------------------- # Module __all__ # --------------------------------------------------------------------------- __all__ = [ # State class "PipelineState", # ContextVar and factories "_CTX_STATE", "_GLOBAL_STATE", "_get_pipeline_state", "get_pipeline_state", "new_pipeline_state", # Constants "MAX_RESULT_TABLE_HISTORY", "PIPELINE_MISSING", "HELP_EXAMPLE_SOURCE_COMMANDS", # Deferred module loaders "_worker", "_cli_parsing", "_result_table", # Live progress "set_live_progress", "get_live_progress", "set_progress_event_callback", "get_progress_event_callback", "suspend_live_progress", # Pipeline stop "request_pipeline_stop", "get_pipeline_stop", "clear_pipeline_stop", # Stage context "set_stage_context", "get_stage_context", # Emit helpers "emit", "emit_list", "print_if_visible", # Pipeline values "store_value", "load_value", # Execution result "set_last_execution_result", "get_last_execution_result", # Pending pipeline tail "set_pending_pipeline_tail", "get_pending_pipeline_tail", "get_pending_pipeline_source", "clear_pending_pipeline_tail", # Reset "reset", # Emitted items "get_emitted_items", "clear_emits", # Selection "set_last_selection", "get_last_selection", "clear_last_selection", # Command text "set_current_command_text", "get_current_command_text", "clear_current_command_text", # Pipeline splitting "split_pipeline_text", "get_current_command_stages", "_split_pipeline_tokens", # Stage text "set_current_stage_text", "get_current_stage_text", "clear_current_stage_text", # Cmdlet name "set_current_cmdlet_name", "get_current_cmdlet_name", "clear_current_cmdlet_name", # Search query "set_search_query", "get_search_query", # Refresh "set_pipeline_refreshed", "was_pipeline_refreshed", # Last items "set_last_items", "get_last_items", # UI library "set_ui_library_refresh_callback", "get_ui_library_refresh_callback", "trigger_ui_library_refresh", # Result table setters "set_last_result_table", "set_last_result_table_overlay", "set_last_result_items_only", # History navigation "restore_previous_result_table", "restore_next_result_table", # Display getters "get_display_table", "get_last_result_subject", "get_last_result_table", "get_last_result_items", "get_last_selectable_result_items", # Table accessors "get_last_result_table_source_command", "get_last_result_table_source_args", "get_last_result_table_row_selection_args", "get_last_result_table_row_selection_action", "get_current_stage_table", "set_current_stage_table", "get_current_stage_table_source_command", "get_current_stage_table_source_args", "get_current_stage_table_row_selection_args", "get_current_stage_table_row_selection_action", "get_current_stage_table_row_source_index", # Clear "clear_last_result", # Debug "debug_table_state", # Helpers (used internally by executor) "_emit_selection_debug_panel", "_is_selectable_table", "_get_table_source_command", "_get_table_source_args", "_get_table_row_selection_args", "_get_table_row_selection_action", ]