Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add shell tab completion #366

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ packaging = ">=22.0"
psutil = ">= 5.8.0"
pyjwt = "^2.4.0"
requests = ">= 2.25"
argcomplete = "^3.1.2"

[tool.poetry.group.dev.dependencies]
black = "*"
Expand Down
4 changes: 3 additions & 1 deletion src/codemagic/cli/argument/argument_parser_builder.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from __future__ import annotations

import argparse
import textwrap
from typing import TYPE_CHECKING
from typing import Dict
from typing import Type
from typing import cast

from codemagic.cli.cli_help_formatter import CliHelpFormatter
from codemagic.cli.colors import Colors
Expand Down Expand Up @@ -52,7 +54,7 @@ def _create_action_parser(self, parent_parser: SubParsersAction, for_deprecated_
self._cli_action.action_name,
formatter_class=CliHelpFormatter,
description=Colors.BOLD(self._cli_action.__doc__),
help=self._cli_action.__doc__,
help=textwrap.dedent(cast(str, self._cli_action.__doc__)).strip().replace("\n", " "),
)

@property
Expand Down
7 changes: 6 additions & 1 deletion src/codemagic/cli/cli_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import shlex
import shutil
import sys
import textwrap
import time
from functools import wraps
from itertools import chain
Expand All @@ -28,6 +29,8 @@
from typing import TypeVar
from typing import Union

import argcomplete

from codemagic import __version__
from codemagic.utilities import auditing
from codemagic.utilities import log
Expand Down Expand Up @@ -300,7 +303,7 @@ def _add_action_group(cls, action_group, parent_parser):
group_parser = parent_parser.add_parser(
action_group.name,
formatter_class=CliHelpFormatter,
help=action_group.description,
help=textwrap.dedent(action_group.description).strip().replace("\n", " "),
description=action_group.description,
)
ArgumentParserBuilder.set_default_cli_options(group_parser)
Expand Down Expand Up @@ -337,6 +340,8 @@ def _setup_cli_options(cls) -> argparse.ArgumentParser:
main_action: ActionCallable = action_or_group
cls._register_cli_action(main_action, action_parsers, action_parsers)

argcomplete.autocomplete(main_parser)

return main_parser

@classmethod
Expand Down
51 changes: 51 additions & 0 deletions src/codemagic/tools/codemagic_cli_tools.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import pathlib
import shutil
import textwrap

import argcomplete

from codemagic import __version__
from codemagic import cli
from codemagic.cli import Colors


class CodemagicCliTools(cli.CliApp):
Expand All @@ -27,6 +32,52 @@ def installed_tools(self):
executable = tool_class.get_executable_name()
self.echo(f"{executable} installed at {shutil.which(executable) or executable}")

@cli.action("enable-shell-autocompletion")
def enable_shell_autocompletion(self):
"""
Enable tab autocompletion for Codemagic CLI tools in your shell
"""

# TODO: Add required shell argument
# TODO: Add optional argument for completion script location

executables = [tool_class.get_executable_name() for tool_class in cli.CliApp.__subclasses__()]

completion_scripts_dir = pathlib.Path("~/.codemagic-cli-tools/completions").expanduser()
completion_scripts_dir.mkdir(parents=True, exist_ok=True)

zsh_completion_path = completion_scripts_dir / "zsh_autocomplete.sh"
zsh_completion_path.write_text(argcomplete.shellcode(executables, shell="zsh"))

bash_completion_path = completion_scripts_dir / "bash_autocomplete.sh"
bash_completion_path.write_text(argcomplete.shellcode(executables, shell="bash"))

completion_path = completion_scripts_dir / "autocomplete.sh"
completion_path.write_text(
textwrap.dedent(
f"""\
#!/bin/sh

if [ -n "$BASH_VERSION" ]; then
source {bash_completion_path}
elif [ -n "$ZSH_VERSION" ]; then
source {zsh_completion_path}
fi

""",
),
)

self.echo(Colors.GREEN(f"Shell autocompletion instructions were saved to {completion_path}"))
self.echo(
"To use autocomplete for Codemagic CLI tools, add the following "
"line to your shell profile (~/.zshrc, ~/.bashrc, etc):",
)
self.echo("")
self.echo(Colors.WHITE(f" source {completion_path}"))
self.echo("")
self.echo("Don't forget to source the completion script in your current shell.")


if __name__ == "__main__":
CodemagicCliTools.invoke_cli()
Loading