Skip to content

Commit

Permalink
Add shell autocomplete (#228)
Browse files Browse the repository at this point in the history
  • Loading branch information
Chad Smith authored and theacodes committed Aug 12, 2019
1 parent 9477a91 commit 9f2f32b
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 1 deletion.
37 changes: 37 additions & 0 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,40 @@ This will create a ``noxfile.py`` based on the environments in your ``tox.ini``.

.. _Generative environments: http://tox.readthedocs.io/en/latest/config.html#generating-environments-conditional-settings
.. _substitutions: http://tox.readthedocs.io/en/latest/config.html#substitutions


Shell Completion
----------------
Add the appropriate command to your shell's config file
so that it is run on startup. You will likely have to restart
or re-login for the autocompletion to start working.

bash

.. code-block:: console
eval "$(register-python-argcomplete nox)"
zsh

.. code-block:: console
# To activate completions for zsh you need to have
# bashcompinit enabled in zsh:
autoload -U bashcompinit
bashcompinit
# Afterwards you can enable completion for nox:
eval "$(register-python-argcomplete nox)"
tcsh

.. code-block:: console
eval `register-python-argcomplete --shell tcsh nox`
fish

.. code-block:: console
register-python-argcomplete --shell fish nox | .
8 changes: 7 additions & 1 deletion nox/_option_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import collections
import functools

import argcomplete # type: ignore

Namespace = argparse.Namespace
ArgumentError = argparse.ArgumentError
Expand Down Expand Up @@ -68,6 +69,7 @@ def __init__(
finalizer_func=None,
default=None,
hidden=False,
completer=None,
**kwargs
):
self.name = name
Expand All @@ -78,6 +80,7 @@ def __init__(
self.merge_func = merge_func
self.finalizer_func = finalizer_func
self.hidden = hidden
self.completer = completer
self.kwargs = kwargs
self._default = default

Expand Down Expand Up @@ -187,9 +190,11 @@ def add_group(self, name, *args, **kwargs):
self.groups[name] = (args, kwargs)

def _add_to_parser(self, parser, option):
parser.add_argument(
argument = parser.add_argument(
*option.flags, help=option.help, default=option.default, **option.kwargs
)
if option.completer:
argument.completer = option.completer

def parser(self):
"""Returns an ``ArgumentParser`` for this option set.
Expand Down Expand Up @@ -233,6 +238,7 @@ def _finalize_args(self, args):

def parse_args(self):
parser = self.parser()
argcomplete.autocomplete(parser)
args = parser.parse_args()

try:
Expand Down
12 changes: 12 additions & 0 deletions nox/_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import sys

from nox import _option_set
from nox.tasks import discover_manifest, filter_manifest, load_nox_module

"""All of nox's configuration options."""

Expand Down Expand Up @@ -97,6 +98,16 @@ def _color_finalizer(value, args):
return sys.stdin.isatty()


def _session_completer(prefix, parsed_args, **kwargs):
global_config = parsed_args
module = load_nox_module(global_config)
manifest = discover_manifest(module, global_config)
filtered_manifest = filter_manifest(manifest, global_config)
return [
session.friendly_name for session, _ in filtered_manifest.list_all_sessions()
]


def _posargs_finalizer(value, unused_args):
"""Removes any leading "--"s in the posargs array."""
if value and value[0] == "--":
Expand Down Expand Up @@ -141,6 +152,7 @@ def _posargs_finalizer(value, unused_args):
nargs="*",
default=_sessions_default,
help="Which sessions to run. By default, all sessions will run.",
completer=_session_completer,
),
_option_set.Option(
"keywords",
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
packages=["nox"],
include_package_data=True,
install_requires=[
"argcomplete>=1.9.4, <2.0",
"colorlog>=2.6.1,<4.0.0",
"py>=1.4.0,<2.0.0",
"virtualenv>=14.0.0",
Expand Down
15 changes: 15 additions & 0 deletions tests/test__option_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import sys
from unittest import mock

import pytest

from nox import _option_set
from nox import _options


# The vast majority of _option_set is tested by test_main, but the test helper
Expand Down Expand Up @@ -45,3 +49,14 @@ def test_namespace_non_existant_options_with_values(self):

with pytest.raises(KeyError):
optionset.namespace(non_existant_option="meep")

def test_session_completer(self):
with mock.patch("sys.argv", [sys.executable]):
parsed_args = _options.options.parse_args()
all_nox_sessions = _options._session_completer(
prefix=None, parsed_args=parsed_args
)
# if noxfile.py changes, this will have to change as well since these are
# some of the actual sessions found in noxfile.py
some_expected_sessions = ["cover", "blacken", "lint", "docs"]
assert len(set(some_expected_sessions) - set(all_nox_sessions)) == 0

0 comments on commit 9f2f32b

Please sign in to comment.