This commit is contained in:
2026-01-03 03:37:48 -08:00
parent 6e9a0c28ff
commit 73f3005393
23 changed files with 1791 additions and 442 deletions

View File

@@ -15,7 +15,10 @@ 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]:
_HELP_EXAMPLE_SOURCE_COMMAND = ".help-example"
def _example_for_cmd(name: str) -> List[str]:
"""Return example invocations for a given command (best-effort)."""
lookup = {
".adjective": [
@@ -28,6 +31,21 @@ def _examples_for_cmd(name: str) -> List[str]:
return lookup.get(key, [])
def _parse_example_tokens(example: str) -> List[str]:
"""Split an example string into CLI tokens suitable for @N selection."""
text = str(example or "").strip()
if not text:
return []
try:
tokens = shlex.split(text)
except Exception:
tokens = text.split()
return [token for token in tokens if token]
def _normalize_cmdlet_key(name: Optional[str]) -> str:
return str(name or "").replace("_", "-").lower().strip()
@@ -103,6 +121,16 @@ def _gather_metadata_from_cmdlet_classes() -> Tuple[Dict[str, Dict[str, Any]], D
canonical_key = _normalize_cmdlet_key(getattr(cmdlet_obj, "name", None) or "")
if not canonical_key:
continue
example_entries: List[str] = []
seen_example_entries: set[str] = set()
for attr in ("examples", "example"):
for value in (getattr(cmdlet_obj, attr, []) or []):
text = str(value or "").strip()
if not text or text in seen_example_entries:
continue
seen_example_entries.add(text)
example_entries.append(text)
entry = {
"name": str(getattr(cmdlet_obj, "name", "") or canonical_key),
"summary": str(getattr(cmdlet_obj, "summary", "") or ""),
@@ -110,6 +138,7 @@ def _gather_metadata_from_cmdlet_classes() -> Tuple[Dict[str, Dict[str, Any]], D
"aliases": _cmdlet_aliases(cmdlet_obj),
"details": list(getattr(cmdlet_obj, "detail", []) or []),
"args": [_cmdlet_arg_to_dict(a) for a in getattr(cmdlet_obj, "arg", []) or []],
"examples": example_entries,
"raw": getattr(cmdlet_obj, "raw", None),
}
metadata[canonical_key] = entry
@@ -185,60 +214,66 @@ def _render_list(
ctx.set_last_result_table(table, items)
ctx.set_current_stage_table(table)
setattr(table, "_rendered_by_cmdlet", True)
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] = []
def _render_detail(meta: Dict[str, Any], _args: Sequence[str]) -> None:
cmd_name = str(meta.get("name", "") or "cmd")
title = f"Help: {cmd_name}"
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
details = meta.get("details", []) or []
seen_examples: set[str] = set()
explicit_example: List[str] = []
for attr in ("examples", "example"):
for value in (meta.get(attr, []) or []):
text = str(value or "").strip()
if not text or text in seen_examples:
continue
seen_examples.add(text)
explicit_example.append(text)
fallback_example = _example_for_cmd(cmd_name)
for fallback in fallback_example:
text = str(fallback or "").strip()
if not text or text in seen_examples:
continue
seen_examples.add(text)
explicit_example.append(text)
header_lines: List[str] = []
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)
if details:
header_lines.extend(str(line) for line in details if str(line).strip())
if explicit_example:
header_lines.append("Examples available below")
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, [])
args_table = ResultTable(title)
if header_lines:
args_table.set_header_lines(header_lines)
args_table.set_preserve_order(True)
args_table.set_no_choice(True)
if not args_meta:
row = table.add_row()
row = args_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()
row = args_table.add_row()
name = arg.get("name") or ""
row.add_column("Arg", f"-{name}" if name else "")
row.add_column("Type", arg.get("type", ""))
@@ -249,15 +284,38 @@ def _render_detail(meta: Dict[str, Any], args: Sequence[str]) -> None:
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)
example_table = ResultTable(f"{cmd_name} Examples")
example_table.set_preserve_order(True)
example_table.set_header_line("Select @N to insert the example command into the REPL.")
example_items: List[str] = []
if explicit_example:
for idx, example_cmd in enumerate(explicit_example):
example_text = str(example_cmd or "").strip()
row = example_table.add_row()
row.add_column("Example", example_text or "(empty example)")
example_items.append(example_text)
if example_text:
tokens = _parse_example_tokens(example_text)
if tokens:
example_table.set_row_selection_args(idx, tokens)
else:
example_table.set_no_choice(True)
row = example_table.add_row()
row.add_column("Example", "(no examples available)")
ctx.set_last_result_table(example_table, example_items)
ctx.set_current_stage_table(example_table)
setattr(example_table, "_rendered_by_cmdlet", True)
example_table.set_source_command(_HELP_EXAMPLE_SOURCE_COMMAND)
from SYS.rich_display import stdout_console
stdout_console().print(table)
stdout_console().print()
stdout_console().print(args_table)
stdout_console().print()
stdout_console().print(example_table)
stdout_console().print()
def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int: