update
This commit is contained in:
+140
-1
@@ -32,6 +32,7 @@ _PREFERENCES_BROWSE_PATH = "__preferences__"
|
||||
_PLUGINS_BROWSE_PATH = "__plugins__"
|
||||
_PLUGIN_CATEGORY_KEYS = ("plugin",)
|
||||
_CREATE_INSTANCE_FLAG = "-create-instance"
|
||||
_CHOOSE_FLAG = "-choose"
|
||||
_KNOWN_SECTION_LABELS = {
|
||||
"plugin": "Plugins",
|
||||
}
|
||||
@@ -65,6 +66,7 @@ _CONFIG_ITEM_FIELDS = (
|
||||
"type",
|
||||
"display_path",
|
||||
"instance_target",
|
||||
"choices",
|
||||
)
|
||||
|
||||
CMDLET = Cmdlet(
|
||||
@@ -576,6 +578,7 @@ def _build_value_item(
|
||||
key_path: str,
|
||||
name: str,
|
||||
value: Any,
|
||||
choices: Any = None,
|
||||
) -> Dict[str, Any]:
|
||||
display_value = "***" if _is_sensitive_config_key(key_path) else _format_config_value(value)
|
||||
path_parts = [part for part in str(key_path or "").split(".") if part]
|
||||
@@ -583,6 +586,7 @@ def _build_value_item(
|
||||
[_format_config_path_label(".".join(path_parts[:-1]))] if len(path_parts) > 1 else []
|
||||
+ [_format_config_label(path_parts[-1])] if path_parts else [_format_config_label(name)]
|
||||
)
|
||||
choice_list = list(choices) if isinstance(choices, (list, tuple)) else []
|
||||
return {
|
||||
"kind": "value",
|
||||
"key": key_path,
|
||||
@@ -592,6 +596,7 @@ def _build_value_item(
|
||||
"value_display": display_value,
|
||||
"display_path": display_path,
|
||||
"type": type(value).__name__,
|
||||
"choices": choice_list,
|
||||
}
|
||||
|
||||
|
||||
@@ -700,6 +705,25 @@ def _build_root_config_items(config_data: Dict[str, Any]) -> List[Dict[str, Any]
|
||||
return items
|
||||
|
||||
|
||||
def _lookup_plugin_choices(browse_path: str, key_name: str) -> Optional[List[str]]:
|
||||
parts = _split_config_path(browse_path)
|
||||
if len(parts) < 2 or parts[0] != "plugin":
|
||||
return None
|
||||
plugin_name = parts[1]
|
||||
try:
|
||||
from SYS.plugin_config import get_plugin_schema
|
||||
schema = get_plugin_schema(plugin_name)
|
||||
except Exception:
|
||||
return None
|
||||
for field in schema:
|
||||
if field.get("key") == key_name:
|
||||
choices = field.get("choices")
|
||||
if isinstance(choices, list):
|
||||
return [str(c) for c in choices]
|
||||
break
|
||||
return None
|
||||
|
||||
|
||||
def _build_nested_config_items(
|
||||
config_data: Dict[str, Any],
|
||||
browse_path: str,
|
||||
@@ -737,6 +761,7 @@ def _build_nested_config_items(
|
||||
key_path=full_key,
|
||||
name=key,
|
||||
value=value,
|
||||
choices=_lookup_plugin_choices(browse_path, key),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -799,6 +824,21 @@ def _extract_browse_arg(args: Sequence[str]) -> Optional[str]:
|
||||
return _extract_arg_value(args, flags={"-browse", "--browse"}, allow_positional=False)
|
||||
|
||||
|
||||
def _extract_choose_arg(args: Sequence[str]) -> Optional[str]:
|
||||
return _extract_arg_value(args, flags={_CHOOSE_FLAG}, allow_positional=False)
|
||||
|
||||
|
||||
def _resolve_config_value_raw(config: Dict[str, Any], key_path: str) -> Any:
|
||||
parts = [p for p in str(key_path or "").split(".") if p]
|
||||
current: Any = config
|
||||
for part in parts:
|
||||
if isinstance(current, dict):
|
||||
current = current.get(part)
|
||||
else:
|
||||
return None
|
||||
return current
|
||||
|
||||
|
||||
def _extract_selected_update_value(args: Sequence[str]) -> Optional[str]:
|
||||
explicit = _extract_arg_value(args, flags=VALUE_ARG_FLAGS, allow_positional=False)
|
||||
if explicit is not None:
|
||||
@@ -871,6 +911,44 @@ def _normalize_config_item(candidate: Any) -> Optional[Dict[str, Any]]:
|
||||
return normalized or None
|
||||
|
||||
|
||||
def _show_choice_table(
|
||||
target_key: str,
|
||||
choices: List[str],
|
||||
current_value: str,
|
||||
display_name: str,
|
||||
) -> int:
|
||||
items: List[Dict[str, Any]] = []
|
||||
for choice in choices:
|
||||
choice_str = str(choice)
|
||||
marker = " ← current" if choice_str == current_value else ""
|
||||
items.append({
|
||||
"kind": "choice",
|
||||
"key": target_key,
|
||||
"title": choice_str,
|
||||
"value": choice_str,
|
||||
"display": f"{choice_str}{marker}",
|
||||
})
|
||||
|
||||
table = Table(f"Configuration: {display_name}", preserve_order=True)
|
||||
table.set_table("config")
|
||||
table.set_source_command(".config", [target_key])
|
||||
table.set_header_lines([
|
||||
f"Available values for {display_name}. Current: {current_value}",
|
||||
"Use @N to select a value. Use @.. to go back.",
|
||||
])
|
||||
|
||||
for idx, item in enumerate(items):
|
||||
row = table.add_row()
|
||||
row.add_column("Choice", item.get("display", item.get("title", "")))
|
||||
table.set_row_selection_action(idx, [".config", str(item.get("key")), str(item.get("value"))])
|
||||
|
||||
ctx.set_last_result_table(table, items)
|
||||
ctx.set_current_stage_table(table)
|
||||
print()
|
||||
print(table)
|
||||
return 0
|
||||
|
||||
|
||||
def _show_config_table(
|
||||
config_data: Dict[str, Any],
|
||||
*,
|
||||
@@ -893,13 +971,23 @@ def _show_config_table(
|
||||
for idx, item in enumerate(items):
|
||||
row = table.add_row()
|
||||
row.add_column("Name", item.get("title", ""))
|
||||
row.add_column("Value", item.get("summary") or item.get("value_display", ""))
|
||||
value_text = item.get("summary") or item.get("value_display", "")
|
||||
choices = item.get("choices")
|
||||
if choices and isinstance(choices, list) and len(choices) > 0:
|
||||
choices_repr = ", ".join(str(c) for c in choices)
|
||||
value_text = f"{value_text} [{choices_repr}]"
|
||||
row.add_column("Value", value_text)
|
||||
row.add_column("Type", item.get("type", ""))
|
||||
if item.get("kind") == "section" and item.get("browse_path"):
|
||||
table.set_row_selection_action(
|
||||
idx,
|
||||
[".config", "-browse", str(item.get("browse_path"))],
|
||||
)
|
||||
elif item.get("kind") == "value" and choices and isinstance(choices, list) and len(choices) > 0 and item.get("key"):
|
||||
table.set_row_selection_action(
|
||||
idx,
|
||||
[".config", "-choose", str(item.get("key"))],
|
||||
)
|
||||
elif item.get("kind") == "create_instance" and item.get("instance_target"):
|
||||
table.set_row_selection_action(
|
||||
idx,
|
||||
@@ -966,6 +1054,22 @@ def _run(piped_result: Any, args: List[str], config: Dict[str, Any]) -> int:
|
||||
if browse_path:
|
||||
return _show_config_table(current_config, browse_path=browse_path)
|
||||
|
||||
choose_key = _extract_choose_arg(args)
|
||||
if choose_key:
|
||||
choices = _lookup_plugin_choices(choose_key, choose_key.split(".")[-1]) or []
|
||||
if not choices:
|
||||
nested_branch = _resolve_config_branch(current_config, choose_key)
|
||||
if isinstance(nested_branch, dict):
|
||||
return _show_config_table(current_config, browse_path=choose_key)
|
||||
print(f"No choices available for '{_format_config_path_label(choose_key)}'")
|
||||
return 0
|
||||
try:
|
||||
current_value = str(_resolve_config_value_raw(current_config, choose_key) or "").strip()
|
||||
except Exception:
|
||||
current_value = ""
|
||||
display_name = _format_config_path_label(choose_key)
|
||||
return _show_choice_table(choose_key, choices, current_value, display_name)
|
||||
|
||||
selection_item = _get_selected_config_item() or _normalize_config_item(piped_result)
|
||||
|
||||
create_instance_target = _extract_create_instance_target(args)
|
||||
@@ -1025,6 +1129,31 @@ def _run(piped_result: Any, args: List[str], config: Dict[str, Any]) -> int:
|
||||
log(f"Error updating config '{target_key}': {exc}")
|
||||
print(f"Error updating config: {exc}")
|
||||
return 1
|
||||
choices = (selection_item or {}).get("choices")
|
||||
if choices and isinstance(choices, list) and len(choices) > 0:
|
||||
current_value = str((selection_item or {}).get("value") or "").strip()
|
||||
display_name = selection_display_path or selection_key
|
||||
return _show_choice_table(selection_key, choices, current_value, display_name)
|
||||
|
||||
if selection_kind == "choice" and selection_key:
|
||||
choice_value = str((selection_item or {}).get("value") or "").strip()
|
||||
if choice_value:
|
||||
try:
|
||||
target_key = _resolve_update_key(current_config, selection_key)
|
||||
set_nested_config(current_config, target_key, choice_value)
|
||||
_save_updated_config(current_config, target_key)
|
||||
print(f"Updated '{_format_config_path_label(selection_key)}' to '{choice_value}'")
|
||||
current_config = load_config()
|
||||
key_parts = [p for p in str(selection_key).split(".") if p]
|
||||
if len(key_parts) >= 2:
|
||||
parent_path = ".".join(key_parts[:-1])
|
||||
if _resolve_config_branch(current_config, parent_path):
|
||||
return _show_config_table(current_config, browse_path=parent_path)
|
||||
return 0
|
||||
except Exception as exc:
|
||||
log(f"Error updating config '{selection_key}': {exc}")
|
||||
print(f"Error updating config: {exc}")
|
||||
return 1
|
||||
|
||||
if not args:
|
||||
if sys.stdin.isatty() and not piped_result:
|
||||
@@ -1047,6 +1176,16 @@ def _run(piped_result: Any, args: List[str], config: Dict[str, Any]) -> int:
|
||||
set_nested_config(current_config, key, value)
|
||||
_save_updated_config(current_config, key)
|
||||
print(f"Updated '{key}' to '{value}'")
|
||||
current_config = load_config()
|
||||
parent_path = _resolve_direct_browse_path(current_config, key)
|
||||
if not parent_path:
|
||||
key_parts = [p for p in str(key).split(".") if p]
|
||||
if len(key_parts) >= 2:
|
||||
candidate = ".".join(key_parts[:-1])
|
||||
if _resolve_config_branch(current_config, candidate):
|
||||
parent_path = candidate
|
||||
if parent_path:
|
||||
return _show_config_table(current_config, browse_path=parent_path)
|
||||
return 0
|
||||
except Exception as exc:
|
||||
log(f"Error updating config '{key}': {exc}")
|
||||
|
||||
Reference in New Issue
Block a user