core/cli: autocomplete module names

This commit is contained in:
Sean Breckenridge 2022-02-21 05:29:25 -08:00 committed by karlicoss
parent 8b01674fed
commit 6185942f78
4 changed files with 21 additions and 11 deletions

View file

@ -8,7 +8,7 @@ eval "$(_HPI_COMPLETE=zsh_source hpi)" # in ~/.zshrc
eval "$(_HPI_COMPLETE=fish_source hpi)" # in ~/.config/fish/config.fish eval "$(_HPI_COMPLETE=fish_source hpi)" # in ~/.config/fish/config.fish
``` ```
That is slightly slower since its generating the completion code on the fly -- see [click docs](https://click.palletsprojects.com/en/8.0.x/shell-completion/?highlight=completion#enabling-completion) for more info That is slightly slower since its generating the completion code on the fly -- see [click docs](https://click.palletsprojects.com/en/8.0.x/shell-completion/#enabling-completion) for more info
To use the completions here: To use the completions here:
@ -32,4 +32,4 @@ If your zsh configuration doesn't automatically run `compinit`, after modifying
### fish ### fish
`cp ./fish/hpi.fish ~/.config/fish/completions/`, an then restart your shell `cp ./fish/hpi.fish ~/.config/fish/completions/`, then restart your shell

View file

@ -8,10 +8,10 @@ _hpi_completion() {
IFS=',' read type value <<< "$completion" IFS=',' read type value <<< "$completion"
if [[ $type == 'dir' ]]; then if [[ $type == 'dir' ]]; then
COMREPLY=() COMPREPLY=()
compopt -o dirnames compopt -o dirnames
elif [[ $type == 'file' ]]; then elif [[ $type == 'file' ]]; then
COMREPLY=() COMPREPLY=()
compopt -o default compopt -o default
elif [[ $type == 'plain' ]]; then elif [[ $type == 'plain' ]]; then
COMPREPLY+=($value) COMPREPLY+=($value)

View file

@ -2,7 +2,6 @@ import functools
import importlib import importlib
import inspect import inspect
import os import os
import re
import sys import sys
import traceback import traceback
from typing import Optional, Sequence, Iterable, List, Type, Any, Callable from typing import Optional, Sequence, Iterable, List, Type, Any, Callable
@ -399,7 +398,7 @@ def _locate_functions_or_prompt(qualified_names: List[str], prompt: bool = True)
if prompt is False: if prompt is False:
# theres more than one possible data provider in this module, # theres more than one possible data provider in this module,
# STDOUT is not a TTY, can't prompt # STDOUT is not a TTY, can't prompt
eprint(f"During fallback, more than one possible data provider, can't prompt since STDOUT is not a TTY") eprint("During fallback, more than one possible data provider, can't prompt since STDOUT is not a TTY")
eprint("Specify one of:") eprint("Specify one of:")
for funcname in choices: for funcname in choices:
eprint(f"\t{qualname}.{funcname}") eprint(f"\t{qualname}.{funcname}")
@ -520,12 +519,23 @@ def main(debug: bool) -> None:
os.chdir(tdir) os.chdir(tdir)
@functools.lru_cache(maxsize=1)
def _all_mod_names() -> List[str]:
"""Should include all modules, in case user is trying to diagnose issues"""
# sort this, so that the order doesn't change while tabbing through
return sorted([m.name for m in modules()])
def _module_autocomplete(ctx: click.Context, args: Sequence[str], incomplete: str) -> List[str]:
return [m for m in _all_mod_names() if m.startswith(incomplete)]
@main.command(name='doctor', short_help='run various checks') @main.command(name='doctor', short_help='run various checks')
@click.option('--verbose/--quiet', default=False, help='Print more diagnostic information') @click.option('--verbose/--quiet', default=False, help='Print more diagnostic information')
@click.option('--all', 'list_all', is_flag=True, help='List all modules, including disabled') @click.option('--all', 'list_all', is_flag=True, help='List all modules, including disabled')
@click.option('-q', '--quick', is_flag=True, help='Only run partial checks (first 100 items)') @click.option('-q', '--quick', is_flag=True, help='Only run partial checks (first 100 items)')
@click.option('-S', '--skip-config-check', 'skip_conf', is_flag=True, help='Skip configuration check') @click.option('-S', '--skip-config-check', 'skip_conf', is_flag=True, help='Skip configuration check')
@click.argument('MODULE', nargs=-1, required=False) @click.argument('MODULE', nargs=-1, required=False, shell_complete=_module_autocomplete)
def doctor_cmd(verbose: bool, list_all: bool, quick: bool, skip_conf: bool, module: Sequence[str]) -> None: def doctor_cmd(verbose: bool, list_all: bool, quick: bool, skip_conf: bool, module: Sequence[str]) -> None:
''' '''
Run various checks Run various checks
@ -572,7 +582,7 @@ def module_grp() -> None:
@module_grp.command(name='requires', short_help='print module reqs') @module_grp.command(name='requires', short_help='print module reqs')
@click.argument('MODULE') @click.argument('MODULE', shell_complete=_module_autocomplete)
def module_requires_cmd(module: str) -> None: def module_requires_cmd(module: str) -> None:
''' '''
Print MODULE requirements Print MODULE requirements
@ -584,7 +594,7 @@ def module_requires_cmd(module: str) -> None:
@module_grp.command(name='install', short_help='install module deps') @module_grp.command(name='install', short_help='install module deps')
@click.option('--user', is_flag=True, help='same as pip --user') @click.option('--user', is_flag=True, help='same as pip --user')
@click.argument('MODULE') @click.argument('MODULE', shell_complete=_module_autocomplete)
def module_install_cmd(user: bool, module: str) -> None: def module_install_cmd(user: bool, module: str) -> None:
''' '''
Install dependencies for a module using pip Install dependencies for a module using pip
@ -660,7 +670,7 @@ def module_install_cmd(user: bool, module: str) -> None:
default=False, default=False,
is_flag=True, is_flag=True,
help='ignore any errors returned as objects from the functions') help='ignore any errors returned as objects from the functions')
@click.argument('FUNCTION_NAME', nargs=-1, required=True) @click.argument('FUNCTION_NAME', nargs=-1, required=True, shell_complete=_module_autocomplete)
def query_cmd( def query_cmd(
function_name: Sequence[str], function_name: Sequence[str],
output: str, output: str,

View file

@ -8,7 +8,7 @@ INSTALL_REQUIRES = [
'appdirs', # very common, and makes it portable 'appdirs', # very common, and makes it portable
'more-itertools', # it's just too useful and very common anyway 'more-itertools', # it's just too useful and very common anyway
'decorator' , # less pain in writing correct decorators. very mature and stable, so worth keeping in core 'decorator' , # less pain in writing correct decorators. very mature and stable, so worth keeping in core
'click' , # for the CLI, printing colors, decorator-based - may allow extensions to CLI 'click>=8.0' , # for the CLI, printing colors, decorator-based - may allow extensions to CLI
] ]