Files
Medios-Macina/cmdnat/help.py
Nose ef01ca03a0
Some checks failed
smoke-mm / Install & smoke test mm --help (push) Has been cancelled
Migrate imports to SYS package (pipeline/result_table) and update related imports
2025-12-29 23:28:15 -08:00

203 lines
6.3 KiB
Python

from __future__ import annotations
from typing import Any, Dict, Sequence, List, Optional
import shlex
import sys
from cmdlet._shared import Cmdlet, CmdletArg, parse_cmdlet_args
from SYS.logger import log
from SYS.result_table import ResultTable
from SYS import pipeline as ctx
def _normalize_choice_list(arg_names: Optional[List[str]]) -> List[str]:
return sorted(set(arg_names or []))
def _examples_for_cmd(name: str) -> List[str]:
"""Return example invocations for a given command (best-effort)."""
lookup = {
".adjective": [
'.adjective -add "example"',
'.adjective -delete "example"',
],
}
key = name.replace("_", "-").lower()
return lookup.get(key, [])
def _find_cmd_metadata(name: str,
metadata: Dict[str,
Dict[str,
Any]]) -> Optional[Dict[str,
Any]]:
target = name.replace("_", "-").lower()
for cmd_name, meta in metadata.items():
if target == cmd_name:
return meta
aliases = meta.get("aliases", []) or []
if target in aliases:
return meta
return None
def _render_list(
metadata: Dict[str,
Dict[str,
Any]],
filter_text: Optional[str],
args: Sequence[str]
) -> None:
table = ResultTable("Help")
table.set_source_command(".help", list(args))
items: List[Dict[str, Any]] = []
needle = (filter_text or "").lower().strip()
for name in sorted(metadata.keys()):
meta = metadata[name]
summary = meta.get("summary", "") or ""
if needle and needle not in name.lower() and needle not in summary.lower():
continue
row = table.add_row()
row.add_column("Cmd", name)
aliases = ", ".join(meta.get("aliases", []) or [])
row.add_column("Aliases", aliases)
arg_names = [a.get("name") for a in meta.get("args", []) if a.get("name")]
row.add_column("Args", ", ".join(f"-{a}" for a in arg_names))
table.set_row_selection_args(len(table.rows) - 1, ["-cmd", name])
items.append(meta)
ctx.set_last_result_table(table, items)
ctx.set_current_stage_table(table)
from SYS.rich_display import stdout_console
stdout_console().print(table)
def _render_detail(meta: Dict[str, Any], args: Sequence[str]) -> None:
title = f"Help: {meta.get('name', '') or 'cmd'}"
table = ResultTable(title)
table.set_source_command(".help", list(args))
header_lines: List[str] = []
summary = meta.get("summary", "")
usage = meta.get("usage", "")
aliases = meta.get("aliases", []) or []
examples = _examples_for_cmd(meta.get("name", ""))
first_example_tokens: List[str] = []
first_example_cmd: Optional[str] = None
if examples:
try:
split_tokens = shlex.split(examples[0])
if split_tokens:
first_example_cmd = split_tokens[0]
first_example_tokens = split_tokens[1:]
except Exception:
pass
if summary:
header_lines.append(summary)
if usage:
header_lines.append(f"Usage: {usage}")
if aliases:
header_lines.append("Aliases: " + ", ".join(aliases))
if examples:
header_lines.append("Examples: " + " | ".join(examples))
if header_lines:
table.set_header_lines(header_lines)
args_meta = meta.get("args", []) or []
example_text = " | ".join(examples)
# If we have an example, use it as the source command so @N runs that example
if first_example_cmd:
table.set_source_command(first_example_cmd, [])
if not args_meta:
row = table.add_row()
row.add_column("Arg", "(none)")
row.add_column("Type", "")
row.add_column("Req", "")
row.add_column("Description", "")
row.add_column("Example", example_text)
if first_example_tokens:
table.set_row_selection_args(len(table.rows) - 1, first_example_tokens)
else:
for arg in args_meta:
row = table.add_row()
name = arg.get("name") or ""
row.add_column("Arg", f"-{name}" if name else "")
row.add_column("Type", arg.get("type", ""))
row.add_column("Req", "yes" if arg.get("required") else "")
desc = arg.get("description", "") or ""
choices = arg.get("choices", []) or []
if choices:
choice_text = f"choices: {', '.join(choices)}"
desc = f"{desc} ({choice_text})" if desc else choice_text
row.add_column("Description", desc)
row.add_column("Example", example_text)
if first_example_tokens:
table.set_row_selection_args(len(table.rows) - 1, first_example_tokens)
ctx.set_last_result_table_overlay(table, [meta])
ctx.set_current_stage_table(table)
from SYS.rich_display import stdout_console
stdout_console().print(table)
def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
try:
import cmdlet_catalog as _catalog
CMDLET.arg[0].choices = _normalize_choice_list(
_catalog.list_cmdlet_names(config=config)
)
metadata = _catalog.list_cmdlet_metadata(config=config)
except Exception:
CMDLET.arg[0].choices = []
metadata = {}
parsed = parse_cmdlet_args(args, CMDLET)
filter_text = parsed.get("filter")
cmd_arg = parsed.get("cmd")
if cmd_arg:
target_meta = _find_cmd_metadata(str(cmd_arg), metadata)
if not target_meta:
log(f"Unknown command: {cmd_arg}", file=sys.stderr)
return 1
_render_detail(target_meta, args)
return 0
_render_list(metadata, filter_text, args)
return 0
CMDLET = Cmdlet(
name=".help",
alias=["help",
"?"],
summary="Show cmdlet or detailed help",
usage=".help [cmd] [-filter text]",
arg=[
CmdletArg(
name="cmd",
type="string",
description="Cmdlet name to show detailed help",
required=False,
choices=[],
),
CmdletArg(
name="-filter",
type="string",
description="Filter cmdlet by substring",
required=False,
),
],
)
CMDLET.exec = _run