diff --git a/README.md b/README.md index 436a3456b..c539e854d 100644 --- a/README.md +++ b/README.md @@ -252,6 +252,33 @@ WSL-based installation. See [here](INSTALL_FROM_SOURCE.md). +## Shell Tab Completion + +Tab completion is available for the following shells: Bash, Zsh, and Tcsh. + +To enable tab completion, run the following command to generate the appropriate script: + +```bash +fairseq2 --print-completion {bash|zsh|tcsh} +``` + +You can either save the output to the shell's completion directory for permanent use or apply it directly to your current session. + +For example, to enable Bash completion for the current session, use: +```bash +eval "$(fairseq2 --print-completion bash)" +``` + +For a permanent setup, run the following command to store the completion script: +```bash +echo "eval $(fairseq2 --print-completion bash)" >> "$BASH_COMPLETION_COMPAT_DIR/shtab" +``` + +Here, `BASH_COMPLETION_COMPAT_DIR` is the path to your system's shell completion directory. + +This ensures that tab completion will be enabled every time you start a new shell session. + + ## Contributing We always welcome contributions to fairseq2! Please refer to [Contribution Guidelines](CONTRIBUTING.md) to learn how to format, test, and diff --git a/setup.py b/setup.py index 662ac97ba..8c65ceb55 100644 --- a/setup.py +++ b/setup.py @@ -62,6 +62,7 @@ "torcheval~=0.0.6", "tqdm~=4.62", "typing_extensions~=4.12", + "shtab~=1.7", ], extras_require={ "arrow": ["pyarrow>=13.0.0", "pandas~=2.0.0"], diff --git a/src/fairseq2/recipes/cli.py b/src/fairseq2/recipes/cli.py index 6ac2ab231..d0fe73978 100644 --- a/src/fairseq2/recipes/cli.py +++ b/src/fairseq2/recipes/cli.py @@ -16,6 +16,7 @@ from types import FrameType from typing import Generic, Protocol, TypeVar, final, runtime_checkable +import shtab import yaml from rich.console import Console from typing_extensions import override @@ -139,6 +140,7 @@ def __call__(self) -> None: def _run_command(self) -> None: parser = ArgumentParser(self._name, description=self._description) + shtab.add_argument_to(parser, ["-s", "--print-completion"]) self.init_parser(parser) @@ -484,7 +486,7 @@ def init_parser(self, parser: ArgumentParser) -> None: type=Path, nargs="*", help="yaml configuration file(s)", - ) + ).complete = shtab.FILE # type: ignore[attr-defined] parser.add_argument( "--config", @@ -527,7 +529,7 @@ def init_parser(self, parser: ArgumentParser) -> None: type=Path, nargs=OPTIONAL, help="directory to store recipe artifacts", - ) + ).complete = shtab.DIRECTORY # type: ignore[attr-defined] @override def __call__(self, args: Namespace) -> None: diff --git a/src/fairseq2/recipes/llama/convert_checkpoint.py b/src/fairseq2/recipes/llama/convert_checkpoint.py index 4e87b43df..c90dba7a9 100644 --- a/src/fairseq2/recipes/llama/convert_checkpoint.py +++ b/src/fairseq2/recipes/llama/convert_checkpoint.py @@ -15,6 +15,7 @@ from typing import final from warnings import catch_warnings +import shtab from typing_extensions import override from fairseq2.console import get_error_console @@ -43,13 +44,13 @@ def init_parser(self, parser: ArgumentParser) -> None: "input_dir", type=Path, help="checkpoint directory", - ) + ).complete = shtab.DIRECTORY # type: ignore[attr-defined] parser.add_argument( "output_dir", type=Path, help="output directory to store reference checkpoint", - ) + ).complete = shtab.DIRECTORY # type: ignore[attr-defined] @override def __call__(self, args: Namespace) -> None: