pre-migration commit
This commit is contained in:
@@ -506,28 +506,21 @@ class CmdletIntrospection:
|
||||
if normalized_arg == "plugin":
|
||||
canonical_cmd = (cmd_name or "").replace("_", "-").lower()
|
||||
try:
|
||||
from ProviderCore.registry import list_search_plugins, list_upload_plugins
|
||||
from ProviderCore.registry import (
|
||||
list_search_plugin_names,
|
||||
list_upload_plugin_names,
|
||||
)
|
||||
except Exception:
|
||||
list_search_plugins = None # type: ignore
|
||||
list_upload_plugins = None # type: ignore
|
||||
list_search_plugin_names = None # type: ignore
|
||||
list_upload_plugin_names = None # type: ignore
|
||||
|
||||
provider_choices: List[str] = []
|
||||
|
||||
if canonical_cmd in {"add-file"} and list_upload_plugins is not None:
|
||||
providers = list_upload_plugins(config) or {}
|
||||
available = [
|
||||
name for name, is_ready in providers.items() if is_ready
|
||||
]
|
||||
return sorted(available) if available else sorted(providers.keys())
|
||||
if canonical_cmd in {"add-file"} and list_upload_plugin_names is not None:
|
||||
return list_upload_plugin_names() or []
|
||||
|
||||
if list_search_plugins is not None:
|
||||
providers = list_search_plugins(config) or {}
|
||||
available = [
|
||||
name for name, is_ready in providers.items() if is_ready
|
||||
]
|
||||
provider_choices = sorted(available) if available else sorted(
|
||||
providers.keys()
|
||||
)
|
||||
if list_search_plugin_names is not None:
|
||||
provider_choices = list_search_plugin_names() or []
|
||||
|
||||
if provider_choices:
|
||||
return provider_choices
|
||||
@@ -579,11 +572,90 @@ class CmdletIntrospection:
|
||||
class CmdletCompleter(Completer):
|
||||
"""Prompt-toolkit completer for the Medeia cmdlet REPL."""
|
||||
|
||||
_CMDLET_NAME_REFRESH_SECONDS = 2.0
|
||||
|
||||
def __init__(self, *, config_loader: "ConfigLoader") -> None:
|
||||
self._config_loader = config_loader
|
||||
self.cmdlet_names = CmdletIntrospection.cmdlet_names()
|
||||
self._cmdlet_names_refreshed_at = time.monotonic()
|
||||
self._cmdlet_args_cache: Dict[Tuple[str, int], List[str]] = {}
|
||||
self._query_args_cache: Dict[Tuple[str, int], List[Dict[str, Any]]] = {}
|
||||
self._arg_choices_cache: Dict[Tuple[str, str, int], List[str]] = {}
|
||||
self._inline_query_choices_cache: Dict[Tuple[str, str, int], List[str]] = {}
|
||||
|
||||
def _refresh_cmdlet_names(self) -> None:
|
||||
now = time.monotonic()
|
||||
if self.cmdlet_names and (now - self._cmdlet_names_refreshed_at) < self._CMDLET_NAME_REFRESH_SECONDS:
|
||||
return
|
||||
self.cmdlet_names = CmdletIntrospection.cmdlet_names(force=False)
|
||||
self._cmdlet_names_refreshed_at = now
|
||||
|
||||
@staticmethod
|
||||
def _config_cache_key(config: Dict[str, Any]) -> int:
|
||||
return id(config) if isinstance(config, dict) else 0
|
||||
|
||||
def _cmdlet_args(self, cmd_name: str, config: Dict[str, Any]) -> List[str]:
|
||||
key = (str(cmd_name or "").lower(), self._config_cache_key(config))
|
||||
cached = self._cmdlet_args_cache.get(key)
|
||||
if cached is not None:
|
||||
return cached
|
||||
value = CmdletIntrospection.cmdlet_args(cmd_name, config)
|
||||
self._cmdlet_args_cache[key] = value
|
||||
return value
|
||||
|
||||
def _query_args(self, cmd_name: str, config: Dict[str, Any]) -> List[Dict[str, Any]]:
|
||||
key = (str(cmd_name or "").lower(), self._config_cache_key(config))
|
||||
cached = self._query_args_cache.get(key)
|
||||
if cached is not None:
|
||||
return cached
|
||||
value = CmdletIntrospection.query_args(cmd_name, config)
|
||||
self._query_args_cache[key] = value
|
||||
return value
|
||||
|
||||
def _arg_choices(
|
||||
self,
|
||||
*,
|
||||
cmd_name: str,
|
||||
arg_name: str,
|
||||
config: Dict[str, Any],
|
||||
force: bool = False,
|
||||
) -> List[str]:
|
||||
key = (
|
||||
str(cmd_name or "").lower(),
|
||||
str(arg_name or "").lower(),
|
||||
self._config_cache_key(config),
|
||||
)
|
||||
if not force:
|
||||
cached = self._arg_choices_cache.get(key)
|
||||
if cached is not None:
|
||||
return cached
|
||||
value = CmdletIntrospection.arg_choices(
|
||||
cmd_name=cmd_name,
|
||||
arg_name=arg_name,
|
||||
config=config,
|
||||
force=force,
|
||||
)
|
||||
self._arg_choices_cache[key] = value
|
||||
return value
|
||||
|
||||
def _inline_query_choices(
|
||||
self,
|
||||
provider_name: str,
|
||||
field_name: str,
|
||||
config: Dict[str, Any],
|
||||
) -> List[str]:
|
||||
key = (
|
||||
str(provider_name or "").lower(),
|
||||
str(field_name or "").lower(),
|
||||
self._config_cache_key(config),
|
||||
)
|
||||
cached = self._inline_query_choices_cache.get(key)
|
||||
if cached is not None:
|
||||
return cached
|
||||
value = plugin_inline_query_choices(provider_name, field_name, config)
|
||||
self._inline_query_choices_cache[key] = value
|
||||
return value
|
||||
|
||||
def _used_arg_logicals(
|
||||
cmd_name: str,
|
||||
stage_tokens: List[str],
|
||||
@@ -595,7 +667,7 @@ class CmdletCompleter(Completer):
|
||||
Example: if the user has typed `download-file -url ...`, then `url`
|
||||
is considered used and should not be suggested again (even as `--url`).
|
||||
"""
|
||||
arg_flags = CmdletIntrospection.cmdlet_args(cmd_name, config)
|
||||
arg_flags = self._cmdlet_args(cmd_name, config)
|
||||
allowed = {a.lstrip("-").strip().lower()
|
||||
for a in arg_flags if a}
|
||||
if not allowed:
|
||||
@@ -636,8 +708,7 @@ class CmdletCompleter(Completer):
|
||||
document: Document,
|
||||
complete_event
|
||||
): # type: ignore[override]
|
||||
# Refresh cmdlet names from introspection to pick up dynamic updates
|
||||
self.cmdlet_names = CmdletIntrospection.cmdlet_names(force=True)
|
||||
self._refresh_cmdlet_names()
|
||||
|
||||
text = document.text_before_cursor
|
||||
tokens = text.split()
|
||||
@@ -660,7 +731,7 @@ class CmdletCompleter(Completer):
|
||||
if ends_with_space:
|
||||
cmd_name = current.replace("_", "-")
|
||||
|
||||
config = self._config_loader.load()
|
||||
config = self._config_loader.load_shared()
|
||||
|
||||
if cmd_name == "help":
|
||||
for cmd in self.cmdlet_names:
|
||||
@@ -670,7 +741,7 @@ class CmdletCompleter(Completer):
|
||||
if cmd_name not in self.cmdlet_names:
|
||||
return
|
||||
|
||||
arg_names = CmdletIntrospection.cmdlet_args(cmd_name, config)
|
||||
arg_names = self._cmdlet_args(cmd_name, config)
|
||||
seen_logicals: Set[str] = set()
|
||||
for arg in arg_names:
|
||||
arg_low = arg.lower()
|
||||
@@ -701,13 +772,13 @@ class CmdletCompleter(Completer):
|
||||
current_token = stage_tokens[-1].lower()
|
||||
prev_token = stage_tokens[-2].lower() if len(stage_tokens) > 1 else ""
|
||||
|
||||
config = self._config_loader.load()
|
||||
config = self._config_loader.load_shared()
|
||||
|
||||
provider_name = None
|
||||
if cmd_name == "search-file":
|
||||
provider_name = self._flag_value(stage_tokens, "-plugin", "--plugin")
|
||||
|
||||
query_specs = CmdletIntrospection.query_args(cmd_name, config)
|
||||
query_specs = self._query_args(cmd_name, config)
|
||||
query_flag_index = -1
|
||||
for idx, tok in enumerate(stage_tokens):
|
||||
if str(tok or "").strip().lower() in {"-query", "--query"}:
|
||||
@@ -754,7 +825,7 @@ class CmdletCompleter(Completer):
|
||||
|
||||
inline_choices = []
|
||||
if cmd_name == "search-file" and provider_name:
|
||||
inline_choices = plugin_inline_query_choices(provider_name, field, config)
|
||||
inline_choices = self._inline_query_choices(provider_name, field, config)
|
||||
|
||||
choice_pool = inline_choices or field_choices.get(field, [])
|
||||
if choice_pool:
|
||||
@@ -800,7 +871,7 @@ class CmdletCompleter(Completer):
|
||||
field, partial = inline_token.split(":", 1)
|
||||
field = field.strip().lower()
|
||||
partial_lower = partial.strip().lower()
|
||||
inline_choices = plugin_inline_query_choices(provider_name, field, config)
|
||||
inline_choices = self._inline_query_choices(provider_name, field, config)
|
||||
if inline_choices:
|
||||
filtered = (
|
||||
[c for c in inline_choices if partial_lower in str(c).lower()]
|
||||
@@ -814,11 +885,11 @@ class CmdletCompleter(Completer):
|
||||
yield Completion(suggestion, start_position=start_pos)
|
||||
return
|
||||
|
||||
choices = CmdletIntrospection.arg_choices(
|
||||
choices = self._arg_choices(
|
||||
cmd_name=cmd_name,
|
||||
arg_name=prev_token,
|
||||
config=config,
|
||||
force=True
|
||||
force=False,
|
||||
)
|
||||
if choices:
|
||||
choice_list = choices
|
||||
@@ -835,7 +906,7 @@ class CmdletCompleter(Completer):
|
||||
# is considered used and should not be suggested again (even as `--url`).
|
||||
return
|
||||
|
||||
arg_names = CmdletIntrospection.cmdlet_args(cmd_name, config)
|
||||
arg_names = self._cmdlet_args(cmd_name, config)
|
||||
used_logicals = self._used_arg_logicals(cmd_name, stage_tokens, config)
|
||||
logical_seen: Set[str] = set()
|
||||
for arg in arg_names:
|
||||
@@ -869,9 +940,15 @@ class ConfigLoader:
|
||||
def __init__(self, *, root: Path) -> None:
|
||||
self._root = root
|
||||
|
||||
def load_shared(self) -> Dict[str, Any]:
|
||||
try:
|
||||
return load_config(emit_summary=False)
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
def load(self) -> Dict[str, Any]:
|
||||
try:
|
||||
return deepcopy(load_config())
|
||||
return deepcopy(self.load_shared())
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user