diff --git a/docs/tutorial/commands/name.md b/docs/tutorial/commands/name.md
index ab18ff633a..7937ada1c1 100644
--- a/docs/tutorial/commands/name.md
+++ b/docs/tutorial/commands/name.md
@@ -54,3 +54,91 @@ def create_user(username: str):
...
```
Then the command name will be `create-user`.
+
+## Command Aliases
+
+You can define aliases for commands so users can call them with different names.
+
+### Positional Aliases
+
+Pass additional positional arguments to `@app.command()`:
+
+{* docs_src/commands/name/tutorial002.py hl[6,9] *}
+
+The `list` command can be called with `list` or `ls`:
+
+
+
+```console
+$ python main.py --help
+
+Usage: main.py [OPTIONS] COMMAND [ARGS]...
+
+Options:
+ --install-completion Install completion for the current shell.
+ --show-completion Show completion for the current shell, to copy it or customize the installation.
+ --help Show this message and exit.
+
+Commands:
+ list, ls
+ remove, rm, delete
+
+$ python main.py list
+
+Listing items
+
+$ python main.py ls
+
+Listing items
+
+$ python main.py remove
+
+Removing items
+
+$ python main.py rm
+
+Removing items
+
+$ python main.py delete
+
+Removing items
+```
+
+
+
+### Keyword Aliases
+
+Use the `aliases` parameter:
+
+{* docs_src/commands/name/tutorial002.py hl[9] *}
+
+Positional aliases and the `aliases` parameter can be combined.
+
+### Hidden Aliases
+
+Use `hidden_aliases` for aliases that work but don't appear in help:
+
+{* docs_src/commands/name/tutorial003.py hl[6] *}
+
+
+
+```console
+$ python main.py --help
+
+Usage: main.py [OPTIONS] COMMAND [ARGS]...
+
+Options:
+ --install-completion Install completion for the current shell.
+ --show-completion Show completion for the current shell, to copy it or customize the installation.
+ --help Show this message and exit.
+
+Commands:
+ list, ls
+ remove
+
+$ python main.py secretlist
+
+Listing items
+```
+
+
diff --git a/docs_src/commands/name/tutorial002.py b/docs_src/commands/name/tutorial002.py
new file mode 100644
index 0000000000..e8f97439aa
--- /dev/null
+++ b/docs_src/commands/name/tutorial002.py
@@ -0,0 +1,17 @@
+import typer
+
+app = typer.Typer()
+
+
+@app.command("list", "ls")
+def list_items():
+ print("Listing items")
+
+
+@app.command("remove", aliases=["rm", "delete"])
+def remove_items():
+ print("Removing items")
+
+
+if __name__ == "__main__":
+ app()
diff --git a/docs_src/commands/name/tutorial003.py b/docs_src/commands/name/tutorial003.py
new file mode 100644
index 0000000000..7f88527272
--- /dev/null
+++ b/docs_src/commands/name/tutorial003.py
@@ -0,0 +1,17 @@
+import typer
+
+app = typer.Typer()
+
+
+@app.command("list", "ls", hidden_aliases=["secretlist"])
+def list_items():
+ print("Listing items")
+
+
+@app.command("remove")
+def remove_items():
+ print("Removing items")
+
+
+if __name__ == "__main__":
+ app()
diff --git a/tests/test_commands_aliases.py b/tests/test_commands_aliases.py
new file mode 100644
index 0000000000..fca2913f40
--- /dev/null
+++ b/tests/test_commands_aliases.py
@@ -0,0 +1,459 @@
+import pytest
+import typer
+import typer.core
+from typer.testing import CliRunner
+
+runner = CliRunner()
+
+
+def test_command_aliases_positional():
+ app = typer.Typer()
+
+ @app.command("list", "ls")
+ def list_items():
+ print("listed")
+
+ @app.command("remove")
+ def remove_items():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["list"])
+ assert result.exit_code == 0
+ assert "listed" in result.stdout
+
+ result = runner.invoke(app, ["ls"])
+ assert result.exit_code == 0
+ assert "listed" in result.stdout
+
+
+def test_command_aliases_keyword():
+ app = typer.Typer()
+
+ @app.command("list", aliases=["ls", "l"])
+ def list_items():
+ print("listed")
+
+ @app.command("remove")
+ def remove_items():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["list"])
+ assert result.exit_code == 0
+ assert "listed" in result.stdout
+
+ result = runner.invoke(app, ["ls"])
+ assert result.exit_code == 0
+ assert "listed" in result.stdout
+
+ result = runner.invoke(app, ["l"])
+ assert result.exit_code == 0
+ assert "listed" in result.stdout
+
+
+def test_command_aliases_combined():
+ app = typer.Typer()
+
+ @app.command("list", "ls", aliases=["l"])
+ def list_items():
+ print("listed")
+
+ @app.command("remove")
+ def remove_items():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["list"])
+ assert result.exit_code == 0
+ assert "listed" in result.stdout
+
+ result = runner.invoke(app, ["ls"])
+ assert result.exit_code == 0
+ assert "listed" in result.stdout
+
+ result = runner.invoke(app, ["l"])
+ assert result.exit_code == 0
+ assert "listed" in result.stdout
+
+
+def test_command_aliases_help_output():
+ app = typer.Typer()
+
+ @app.command("list", "ls")
+ def list_items():
+ pass # pragma: no cover
+
+ @app.command("remove", aliases=["rm", "delete"])
+ def remove_items():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "list, ls" in result.stdout or "ls, list" in result.stdout
+ assert (
+ "remove, rm, delete" in result.stdout or "rm, delete, remove" in result.stdout
+ )
+
+
+def test_command_hidden_aliases():
+ app = typer.Typer()
+
+ @app.command("list", "ls", hidden_aliases=["secretlist"])
+ def list_items():
+ pass # pragma: no cover
+
+ @app.command("remove")
+ def remove_items():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "list, ls" in result.stdout or "ls, list" in result.stdout
+ assert "secretlist" not in result.stdout
+
+ result = runner.invoke(app, ["secretlist"])
+ assert result.exit_code == 0
+
+
+def test_command_aliases_subcommands():
+ app = typer.Typer()
+
+ @app.command("versions", "ver", "v")
+ def show_versions():
+ print("versions")
+
+ @app.command("documents", aliases=["docs"])
+ def show_documents():
+ print("documents")
+
+ result = runner.invoke(app, ["versions"])
+ assert result.exit_code == 0
+ assert "versions" in result.stdout
+
+ result = runner.invoke(app, ["ver"])
+ assert result.exit_code == 0
+ assert "versions" in result.stdout
+
+ result = runner.invoke(app, ["v"])
+ assert result.exit_code == 0
+ assert "versions" in result.stdout
+
+ result = runner.invoke(app, ["documents"])
+ assert result.exit_code == 0
+ assert "documents" in result.stdout
+
+ result = runner.invoke(app, ["docs"])
+ assert result.exit_code == 0
+ assert "documents" in result.stdout
+
+
+def test_command_no_aliases_help_output():
+ app = typer.Typer()
+
+ @app.command("list")
+ def list_items():
+ pass # pragma: no cover
+
+ @app.command("remove")
+ def remove_items():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert " list" in result.stdout or "list " in result.stdout
+ assert " remove" in result.stdout or "remove " in result.stdout
+
+
+def test_command_empty_aliases_list():
+ app = typer.Typer()
+
+ @app.command("list", aliases=[])
+ def list_items():
+ print("listed")
+
+ @app.command("remove")
+ def remove_items():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "list" in result.stdout
+ assert "remove" in result.stdout
+
+ result = runner.invoke(app, ["list"])
+ assert result.exit_code == 0
+ assert "listed" in result.stdout
+
+
+def test_multiple_commands_with_aliases():
+ app = typer.Typer()
+
+ @app.command("cmd1", "c1")
+ def command1():
+ pass # pragma: no cover
+
+ @app.command("cmd2", aliases=["c2"])
+ def command2():
+ pass # pragma: no cover
+
+ @app.command("cmd3")
+ def command3():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "cmd1, c1" in result.stdout or "c1, cmd1" in result.stdout
+ assert "cmd2, c2" in result.stdout or "c2, cmd2" in result.stdout
+ assert "cmd3" in result.stdout
+
+
+def test_commands_list_deduplication():
+ app = typer.Typer()
+
+ @app.command("same", "alias1")
+ def cmd1():
+ pass # pragma: no cover
+
+ @app.command("other", "alias2")
+ def cmd2():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ commands_output = result.stdout
+ assert "same" in commands_output
+ assert "other" in commands_output
+ assert commands_output.count("same") == 1
+
+
+def test_list_commands_covers_all_branches():
+ app = typer.Typer()
+
+ @app.command("cmd1")
+ def command1():
+ pass # pragma: no cover
+
+ @app.command("cmd2", "alias")
+ def command2():
+ pass # pragma: no cover
+
+ @app.command("cmd3", aliases=["a3"])
+ def command3():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "cmd1" in result.stdout
+ assert "cmd2" in result.stdout or "alias" in result.stdout
+ assert "cmd3" in result.stdout or "a3" in result.stdout
+
+
+def test_commands_with_hidden_and_aliases():
+ app = typer.Typer()
+
+ @app.command("visible", "v", aliases=["vis"])
+ def visible_cmd():
+ pass # pragma: no cover
+
+ @app.command("hidden", hidden=True)
+ def hidden_cmd():
+ pass # pragma: no cover
+
+ @app.command("another", aliases=["a"])
+ def another_cmd():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "visible" in result.stdout or "v" in result.stdout or "vis" in result.stdout
+ assert "hidden" not in result.stdout
+ assert "another" in result.stdout or "a" in result.stdout
+
+
+def test_comprehensive_alias_scenarios():
+ app = typer.Typer()
+
+ @app.command("a1", "a2", aliases=["a3", "a4"])
+ def cmd_a():
+ pass # pragma: no cover
+
+ @app.command("b1", hidden_aliases=["b2"])
+ def cmd_b():
+ pass # pragma: no cover
+
+ @app.command("c1")
+ def cmd_c():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert (
+ "a1" in result.stdout
+ or "a2" in result.stdout
+ or "a3" in result.stdout
+ or "a4" in result.stdout
+ )
+ assert "b1" in result.stdout
+ assert "b2" not in result.stdout
+ assert "c1" in result.stdout
+
+ result = runner.invoke(app, ["a1"])
+ assert result.exit_code == 0
+
+ result = runner.invoke(app, ["a2"])
+ assert result.exit_code == 0
+
+ result = runner.invoke(app, ["a3"])
+ assert result.exit_code == 0
+
+ result = runner.invoke(app, ["b2"])
+ assert result.exit_code == 0
+
+
+def test_list_commands_deduplication_with_aliases():
+ app = typer.Typer()
+
+ @app.command("main1", "alias1", aliases=["a1"])
+ def cmd1():
+ pass # pragma: no cover
+
+ @app.command("main2", "alias2")
+ def cmd2():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert (
+ "main1" in result.stdout or "alias1" in result.stdout or "a1" in result.stdout
+ )
+ assert "main2" in result.stdout or "alias2" in result.stdout
+ assert result.stdout.count("main1") <= 1
+ assert result.stdout.count("main2") <= 1
+
+ result = runner.invoke(app, ["main1"])
+ assert result.exit_code == 0
+
+ result = runner.invoke(app, ["alias1"])
+ assert result.exit_code == 0
+
+ result = runner.invoke(app, ["a1"])
+ assert result.exit_code == 0
+
+
+def test_format_commands_with_aliases_no_rich(monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setattr(typer.core, "HAS_RICH", False)
+
+ app = typer.Typer()
+
+ @app.command("list", "ls", aliases=["l"])
+ def list_items():
+ pass # pragma: no cover
+
+ @app.command("remove", aliases=["rm"])
+ def remove_items():
+ pass # pragma: no cover
+
+ @app.command("create")
+ def create_items():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "list" in result.stdout or "ls" in result.stdout or "l" in result.stdout
+ assert "remove" in result.stdout or "rm" in result.stdout
+ assert "create" in result.stdout
+
+
+def test_format_commands_no_aliases_no_rich(monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setattr(typer.core, "HAS_RICH", False)
+
+ app = typer.Typer()
+
+ @app.command("list")
+ def list_items():
+ pass # pragma: no cover
+
+ @app.command("remove")
+ def remove_items():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "list" in result.stdout
+ assert "remove" in result.stdout
+
+
+def test_format_commands_with_hidden_no_rich(monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setattr(typer.core, "HAS_RICH", False)
+
+ app = typer.Typer()
+
+ @app.command("visible")
+ def visible_cmd():
+ pass # pragma: no cover
+
+ @app.command("hidden", hidden=True)
+ def hidden_cmd():
+ pass # pragma: no cover
+
+ @app.command("another")
+ def another_cmd():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "visible" in result.stdout
+ assert "hidden" not in result.stdout
+ assert "another" in result.stdout
+
+
+def test_format_commands_empty_no_rich(monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setattr(typer.core, "HAS_RICH", False)
+
+ app = typer.Typer()
+
+ @app.callback(invoke_without_command=True)
+ def main():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "Commands" not in result.stdout or "Commands:" not in result.stdout
+
+
+def test_format_help_command_no_rich(monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setattr(typer.core, "HAS_RICH", False)
+
+ app = typer.Typer()
+
+ @app.command(help="Test command")
+ def test_cmd():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["test-cmd", "--help"])
+ assert result.exit_code == 0
+ assert "Test command" in result.stdout
+
+
+def test_format_help_group_no_rich(monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setattr(typer.core, "HAS_RICH", False)
+
+ app = typer.Typer(help="Test group")
+
+ @app.command()
+ def test_cmd():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "Test group" in result.stdout or "Usage:" in result.stdout
+
+
+def test_format_help_rich_markup_mode_none():
+ app = typer.Typer(rich_markup_mode=None)
+
+ @app.command(help="Test command")
+ def test_cmd():
+ pass # pragma: no cover
+
+ result = runner.invoke(app, ["test-cmd", "--help"])
+ assert result.exit_code == 0
+ assert "Test command" in result.stdout
diff --git a/tests/test_tutorial/test_commands/test_name/test_tutorial002.py b/tests/test_tutorial/test_commands/test_name/test_tutorial002.py
new file mode 100644
index 0000000000..67531e84e3
--- /dev/null
+++ b/tests/test_tutorial/test_commands/test_name/test_tutorial002.py
@@ -0,0 +1,47 @@
+from typer.testing import CliRunner
+
+from docs_src.commands.name import tutorial002 as mod
+
+app = mod.app
+
+runner = CliRunner()
+
+
+def test_help():
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "Commands" in result.output
+ assert "list" in result.output or "ls" in result.output
+ assert (
+ "remove" in result.output or "rm" in result.output or "delete" in result.output
+ )
+
+
+def test_list():
+ result = runner.invoke(app, ["list"])
+ assert result.exit_code == 0
+ assert "Listing items" in result.output
+
+
+def test_ls():
+ result = runner.invoke(app, ["ls"])
+ assert result.exit_code == 0
+ assert "Listing items" in result.output
+
+
+def test_remove():
+ result = runner.invoke(app, ["remove"])
+ assert result.exit_code == 0
+ assert "Removing items" in result.output
+
+
+def test_rm():
+ result = runner.invoke(app, ["rm"])
+ assert result.exit_code == 0
+ assert "Removing items" in result.output
+
+
+def test_delete():
+ result = runner.invoke(app, ["delete"])
+ assert result.exit_code == 0
+ assert "Removing items" in result.output
diff --git a/tests/test_tutorial/test_commands/test_name/test_tutorial003.py b/tests/test_tutorial/test_commands/test_name/test_tutorial003.py
new file mode 100644
index 0000000000..43dc9060e8
--- /dev/null
+++ b/tests/test_tutorial/test_commands/test_name/test_tutorial003.py
@@ -0,0 +1,40 @@
+from typer.testing import CliRunner
+
+from docs_src.commands.name import tutorial003 as mod
+
+app = mod.app
+
+runner = CliRunner()
+
+
+def test_help():
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "Commands" in result.output
+ assert "list" in result.output or "ls" in result.output
+ assert "remove" in result.output
+ assert "secretlist" not in result.output
+
+
+def test_list():
+ result = runner.invoke(app, ["list"])
+ assert result.exit_code == 0
+ assert "Listing items" in result.output
+
+
+def test_ls():
+ result = runner.invoke(app, ["ls"])
+ assert result.exit_code == 0
+ assert "Listing items" in result.output
+
+
+def test_secretlist():
+ result = runner.invoke(app, ["secretlist"])
+ assert result.exit_code == 0
+ assert "Listing items" in result.output
+
+
+def test_remove():
+ result = runner.invoke(app, ["remove"])
+ assert result.exit_code == 0
+ assert "Removing items" in result.output
diff --git a/typer/core.py b/typer/core.py
index 83eb8ec52b..2d98bf32c3 100644
--- a/typer/core.py
+++ b/typer/core.py
@@ -764,6 +764,30 @@ def format_options(
_typer_format_options(self, ctx=ctx, formatter=formatter)
self.format_commands(ctx, formatter)
+ def format_commands(
+ self, ctx: click.Context, formatter: click.HelpFormatter
+ ) -> None:
+ commands = []
+ for name in self.list_commands(ctx):
+ cmd = self.get_command(ctx, name)
+ if cmd is None or cmd.hidden:
+ continue
+ aliases = getattr(cmd, "_typer_aliases", [])
+ hidden_aliases = getattr(cmd, "_typer_hidden_aliases", [])
+ visible_aliases = [a for a in aliases if a not in hidden_aliases]
+
+ if visible_aliases:
+ cmd_name = ", ".join([name] + visible_aliases)
+ else:
+ cmd_name = name
+
+ help_text = cmd.short_help or cmd.help or ""
+ commands.append((cmd_name, help_text))
+
+ if commands:
+ with formatter.section(_("Commands")):
+ formatter.write_dl(commands)
+
def _main_shell_completion(
self,
ctx_args: MutableMapping[str, Any],
@@ -826,4 +850,10 @@ def list_commands(self, ctx: click.Context) -> list[str]:
"""Returns a list of subcommand names.
Note that in Click's Group class, these are sorted.
In Typer, we wish to maintain the original order of creation (cf Issue #933)"""
- return [n for n, c in self.commands.items()]
+ seen = set()
+ result = []
+ for _name, cmd in self.commands.items():
+ if cmd.name and cmd.name not in seen:
+ seen.add(cmd.name)
+ result.append(cmd.name)
+ return result
diff --git a/typer/main.py b/typer/main.py
index e8c6b9e429..edb5f7c5e5 100644
--- a/typer/main.py
+++ b/typer/main.py
@@ -221,7 +221,7 @@ def decorator(f: CommandFunctionType) -> CommandFunctionType:
def command(
self,
name: Optional[str] = None,
- *,
+ *positional_aliases: str,
cls: Optional[type[TyperCommand]] = None,
context_settings: Optional[dict[Any, Any]] = None,
help: Optional[str] = None,
@@ -232,12 +232,20 @@ def command(
no_args_is_help: bool = False,
hidden: bool = False,
deprecated: bool = False,
+ aliases: Optional[Sequence[str]] = None,
+ hidden_aliases: Optional[Sequence[str]] = None,
# Rich settings
rich_help_panel: Union[str, None] = Default(None),
) -> Callable[[CommandFunctionType], CommandFunctionType]:
if cls is None:
cls = TyperCommand
+ all_aliases_list: list[str] = []
+ if positional_aliases:
+ all_aliases_list.extend(positional_aliases)
+ if aliases:
+ all_aliases_list.extend(aliases)
+
def decorator(f: CommandFunctionType) -> CommandFunctionType:
self.registered_commands.append(
CommandInfo(
@@ -255,6 +263,8 @@ def decorator(f: CommandFunctionType) -> CommandFunctionType:
no_args_is_help=no_args_is_help,
hidden=hidden,
deprecated=deprecated,
+ aliases=all_aliases_list if all_aliases_list else None,
+ hidden_aliases=hidden_aliases,
# Rich settings
rich_help_panel=rich_help_panel,
)
@@ -489,6 +499,10 @@ def get_group_from_info(
)
if command.name:
commands[command.name] = command
+ cmd_aliases = getattr(command, "_typer_aliases", [])
+ cmd_hidden_aliases = getattr(command, "_typer_hidden_aliases", [])
+ for alias in cmd_aliases + cmd_hidden_aliases:
+ commands[alias] = command
for sub_group_info in group_info.typer_instance.registered_groups:
sub_group = get_group_from_info(
sub_group_info,
@@ -613,6 +627,8 @@ def get_command_from_info(
# Rich settings
rich_help_panel=command_info.rich_help_panel,
)
+ command._typer_aliases = command_info.aliases or [] # type: ignore
+ command._typer_hidden_aliases = command_info.hidden_aliases or [] # type: ignore
return command
diff --git a/typer/models.py b/typer/models.py
index 78d1a5354d..ce436d7447 100644
--- a/typer/models.py
+++ b/typer/models.py
@@ -95,6 +95,8 @@ def __init__(
no_args_is_help: bool = False,
hidden: bool = False,
deprecated: bool = False,
+ aliases: Optional[Sequence[str]] = None,
+ hidden_aliases: Optional[Sequence[str]] = None,
# Rich settings
rich_help_panel: Union[str, None] = None,
):
@@ -110,6 +112,8 @@ def __init__(
self.no_args_is_help = no_args_is_help
self.hidden = hidden
self.deprecated = deprecated
+ self.aliases = aliases or []
+ self.hidden_aliases = hidden_aliases or []
# Rich settings
self.rich_help_panel = rich_help_panel
diff --git a/typer/rich_utils.py b/typer/rich_utils.py
index ad110cb8d6..f9a54cbfb9 100644
--- a/typer/rich_utils.py
+++ b/typer/rich_utils.py
@@ -497,12 +497,23 @@ def _print_commands_panel(
deprecated_rows: list[Union[RenderableType, None]] = []
for command in commands:
helptext = command.short_help or command.help or ""
- command_name = command.name or ""
+ cmd_name = command.name or ""
+ aliases = getattr(command, "_typer_aliases", [])
+ hidden_aliases = getattr(command, "_typer_hidden_aliases", [])
+ visible_aliases = [a for a in aliases if a not in hidden_aliases]
+
+ if visible_aliases:
+ cmd_name_display = ", ".join([cmd_name] + visible_aliases)
+ else:
+ cmd_name_display = cmd_name
+
if command.deprecated:
- command_name_text = Text(f"{command_name}", style=STYLE_DEPRECATED_COMMAND)
+ command_name_text = Text(
+ f"{cmd_name_display}", style=STYLE_DEPRECATED_COMMAND
+ )
deprecated_rows.append(Text(DEPRECATED_STRING, style=STYLE_DEPRECATED))
else:
- command_name_text = Text(command_name)
+ command_name_text = Text(cmd_name_display)
deprecated_rows.append(None)
rows.append(
[
@@ -633,12 +644,20 @@ def rich_format_help(
)
panel_to_commands[panel_name].append(command)
- # Identify the longest command name in all panels
max_cmd_len = max(
[
- len(command.name or "")
- for commands in panel_to_commands.values()
- for command in commands
+ len(
+ ", ".join(
+ [cmd.name or ""]
+ + [
+ a
+ for a in getattr(cmd, "_typer_aliases", [])
+ if a not in getattr(cmd, "_typer_hidden_aliases", [])
+ ]
+ )
+ )
+ for cmds in panel_to_commands.values()
+ for cmd in cmds
],
default=0,
)