Créer un script d'achèvement bash pour les chemins de saisie semi-automatique après le signe is-equal?

11

Je veux créer un script d'achèvement bash qui reconnaît les arguments du formulaire --arget --some-arg=file.

Après avoir lu ce tutoriel et quelques exemples /usr/share/bash_completion/completions/, j'ai écrit le script suivant (pour gagner du temps à taper des drapeaux avec Chromium):

_chromium() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    # Some interesting options
    opts="
--disable-web-security
--easy-off-store-extension-install
--incognito
--load-extension=
--pack-extension=
--pack-extension-key=
--user-data-dir=
"
    # Handle --xxxxxx=file
    if [[ ${cur} == "--"*"=" ]] ; then
        # Removed failures (is my logic OK?)
        return 0
    fi

    # Handle other options
    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
}
complete -F _chromium chromium

Je l'ai enregistré dans ~/bash_completions/chromiumet créé un lien symbolique à l'aide de sudo ln -s ~/bash_completions/chromium /usr/share/bash_completion/completions/chromium.
Ensuite, je l'ai chargé en utilisant . /usr/share/bash_completions/completions/chromium.

Maintenant, je rencontre deux problèmes:

  • chromium --u<TAB>se développe en chromium --user-data-dir=<SPACE>(je ne veux pas de l'espace).
  • Les chemins (répertoires et fichiers) ne sont plus complétés.

Comment puis-je résoudre ces problèmes?

Rob W
la source
Le passage à zsh est-il une option?
Gilles 'SO- arrête d'être méchant'

Réponses:

11

J'ai trouvé la solution aux deux problèmes!

  1. Pour ne pas ajouter d'espace, utilisez l' nospaceoption. Ceci peut être fait de deux façons:

    • Passez-le au complete:
      complete -o nospace -F _chromium chromium
    • Utilisez la fonction compoptintégrée:
      compopt -o nospace(pour activer l'option)
      compopt +o nospace(pour désactiver l'option)

    Je l'ai trouvé dans la documentation de Bash sur gnu.org, 8.7 Builtin Completion Completion Builtins .

  2. Achèvement des fichiers.
    • peterph a suggéré d'utiliser le -fdrapeau avec compgen. J'ai suivi ce conseil et l'ai mis en œuvre comme COMPREPLY=( $(compgen -f "$cur") ). Cela a bien fonctionné, jusqu'à ce que j'essaie de terminer un chemin contenant des espaces.
      Sur Stack Overflow, j'ai trouvé cette réponse qui recommande la création manuelle de la liste d'achèvement (sans utiliser compgen). Cette approche a bien fonctionné.
    • Utilisez l' filenamesoption pour indiquer à Readline que la spécification comp génère des noms de fichiers, afin qu'elle puisse:
      • effectuer tout traitement spécifique au nom de fichier (comme ajouter une barre oblique aux noms de répertoire, citer des caractères spéciaux ou supprimer les espaces de fin)
      • utiliser différentes couleurs pour indiquer le type de fichier (avec colored-statsactivé)

Avec l'aide de la manipulation des chaînes de Bash (pour développer ~et gérer les espaces), j'ai construit un script de complétion bash qui répond à tous les critères énoncés dans la question.

_chromium() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    # Some interesting options
    opts="
--disable-web-security
--easy-off-store-extension-install
--incognito
--load-extension=
--pack-extension=
--pack-extension-key=
--user-data-dir=
"
    # Handle --xxxxxx=
    if [[ ${prev} == "--"* && ${cur} == "=" ]] ; then
        compopt -o filenames
        COMPREPLY=(*)
        return 0
    fi
    # Handle --xxxxx=path
    if [[ ${prev} == '=' ]] ; then
        # Unescape space
        cur=${cur//\\ / }
        # Expand tilder to $HOME
        [[ ${cur} == "~/"* ]] && cur=${cur/\~/$HOME}
        # Show completion if path exist (and escape spaces)
        compopt -o filenames
        local files=("${cur}"*)
        [[ -e ${files[0]} ]] && COMPREPLY=( "${files[@]// /\ }" )
        return 0
    fi

    # Handle other options
    COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
    if [[ ${#COMPREPLY[@]} == 1 && ${COMPREPLY[0]} != "--"*"=" ]] ; then
        # If there's only one option, without =, then allow a space
        compopt +o nospace
    fi
    return 0
}
complete -o nospace -F _chromium chromium
Rob W
la source
Super réponse, merci beaucoup. Vous avez économisé beaucoup de temps. J'ai utilisé le -fcommutateur pour l'achèvement du chemin d'accès au fichier, mais il ne complète pas le caractère /s'il s'agit d'un répertoire ... c'est une petite chose cependant.
Jiri Kremser
1

Pour compléter les noms de fichiers, essayez de passer -fà compgen.

Je crains que vous ne puissiez pas vous débarrasser des espaces après les options, car c'est ainsi que l'achèvement fonctionne - une fois qu'il trouve une correspondance unique, il la complète complètement.

peterph
la source
Merci pour la suggestion de -f. Je l'ai essayé, mais il ne traite pas correctement les espaces: le chemin d'accès /tmp/foo barentraîne deux entrées de complétion /tmp/fooet bar. À propos des indésirables --arg=<SPACE>: j'ai trouvé la solution à cela et je l'ai affichée dans la réponse ci-dessous .
Rob W