Terminal window showing the manual page for the Mutt email client on Linux
Agence web » Actualités du digital » Comment ajouter l'achèvement du terminal à vos applications de ligne de commande

Comment ajouter l'achèvement du terminal à vos applications de ligne de commande

La complétion automatique est un excellent moyen de rendre vos propres outils plus accessibles. Découvrez comment faire les premiers pas en construisant un script automatique simple Bash et Zsh.

Comment fonctionne l'achèvement de l'onglet

La saisie semi-automatique – est passée partout, des applications de messagerie texte aux IDE – peut sembler une innovation assez moderne, mais elle est présente dans diverses formes d'Unix depuis le début des années 80, sinon plus tôt. Les coquilles Linux comme Bash et Zsh prennent en charge un écosystème d'achèvement plus puissant que vous pouvez vous attendre.

Vous utilisez probablement l'achèvement le plus souvent avec les commandes et les noms de fichiers. La complétion de l'onglet de commande fonctionne en inspectant la variable d'environnement de chemin pour identifier les commandes disponibles commençant par les lettres que vous avez tapées. L'achèvement du nom de fichier fournira le reste d'un chemin de fichier (absolu ou relatif) et vous aidera à affiner vos options, en résolvant les ambiguïtés au fur et à mesure. Les deux vous feront gagner beaucoup de temps et de frappe manuelle.

Mais il y a un troisième type d'achèvement, peut-être moins populaire, mais encore plus puissant, peut-être, que les types les plus courants. L'argument de l'assiette automatique s'applique à tout après le nom de commande, comme les options ou les sous-communs:

Comment ajouter l'achèvement à vos propres scripts

Je vais expliquer comment vous pouvez d'abord ajouter une complétion personnalisée pour ZSH, puis décrire un équivalent bash.

Un exemple de commande

Je vais démontrer la fin de l'argument de commande personnalisée avec un script trivial que j'utilise pour gérer ma liste de tâches. Le script complet n'est pas très compliqué, mais cet extrait se concentre sur les parties les plus pertinentes:

        #!/usr/bin/env zsh

FILE="$HOME/.local/state/todos/data"

if ( "$#" -eq "1" ) && ( "$1" = "edit" ) ; then
    "${EDITOR:-vi}" "$FILE"
elif ( "$#" -eq "1" ) && ( "$1" = "help" ) ; then
    echo "Usage: $(basename $0) ( edit | help )"
else
    <"$FILE" grep -v ^~
fi

J'ai ce script enregistré dans un fichier nommé Todos, donc les commandes suivantes s'exécutent maintenant sur mon système:

  • todos: contenu de sortie du fichier de données, ignorant les lignes commençant ~
  • Todos Aide: Afficher l'utilisation
  • Todos Modifier: Ouvrez le fichier de données dans l'éditeur

Il s'agit vraiment d'une commande de commodité, bien que le script complet fasse un travail supplémentaire pour maintenir un fichier JSON distinct sur les modifications. Je n'ai pas de page homme pour un script aussi simple, et la sous-commande d'aide est pratique, mais j'aimerais ajouter l'achèvement des arguments afin que je puisse découvrir la sous-commande d'édition ou d'autres sous-commandes que je pourrais ajouter à l'avenir.

La fonctionnalité de Todos n'a même pas d'importance pour cette démonstration. Vous pouvez créer un script vide avec ce nom et, tant qu'il est exécutable et sur votre chemin, les suggestions de saisie semi-automatique fonctionneront.

Un script de complétion personnalisé

Votre script complet complet doit faire deux choses: configurer le système d'achèvement de votre commande à l'aide d'échafaudage intégré et générer des compléments possibles.

Dans ZSH, l'achèvement le plus élémentaire est très simple:

        _complete_todos() {
    compadd help edit
}

autoload -Uz compinit
compinit
compdef _complete_todos todos

La fonction _COMPLETE_TODOS est un gestionnaire qui appelle Compadd pour spécifier des suggestions. La fonction compadd appartient au module Compinit de Zsh. Chaque mot que vous passez comme argument à compadd représente un achèvement possible. Pour un script aussi simple que cet exemple, il est parfaitement bien de les cocoder avec un appel statique à compadd.

Avec la fonction définie, le script charge et exécute ensuite le module de compinit avant d'appeler compdef pour connecter la fonction _Complete_todos avec la commande, todos.

Vous pouvez mettre le script ci-dessus dans votre fichier .zshrc, ou un autre fichier qu'il s'approvisionne. Vous pouvez également utiliser le système FPATH de ZSH pour le stocker dans un fichier commençant par un soulignement, dans un répertoire approprié.

Pour le développement et les tests, vous pouvez simplement exécuter le code ci-dessus directement sur la ligne de commande. Une fois que vous l'avez fait, essayez de taper todos et expérimenter le comportement de la saisie semi-automatique.

Différences de bash

Bash est très différent en ce qui concerne l'achèvement. En particulier, il ne tiendra pas la main autant que Zsh. Alors que ZSH gère les suggestions complètes elle-même, Bash s'attend à ce que vous soyez approprié quelles suggestions sont appropriées, en fonction de ce qui a été dactylographié et où l'onglet a été pressé.

Considérez un équivalent naïf du script Zsh ci-dessus:

        _complete_todos_bash() {
    COMPREPLY=(help edit)
}

complete -F _complete_todos_bash todos

Bash fournit une commande complète au lieu de l'approche de fonction de Zsh, il n'est donc pas nécessaire de charger ou d'initialiser quoi que ce soit. Le gestionnaire d'achèvement établit une variable connue – complexe – au lieu des suggestions d'écho. Cette variable est un tableau bash.

Si vous testez ce script en bash, vous verrez qu'il répertorie toutes les suggestions de sous-commande comme vous vous y attendez:

        $ todos 
help edit

Le problème est que Bash fera toujours confiance à votre gestionnaire pour fournir toutes les suggestions pertinentes, sans appliquer aucune de sa propre logique en plus. Ces résultats ne sont donc pas toujours utiles:

        $ todos he
help edit

Il est de votre responsabilité de dire à Bash que «il» ne devrait suggérer que «l'aide» comme achèvement possible. Vous pouvez le faire en inspectant certaines variables utiles que Bash fournit lorsque l'onglet est enfoncé:

  • Comp_words est un tableau contenant la ligne de commande complète divisée en mots individuels.

  • Comp_cword est un index dans comp_words se référant au mot que le curseur est actuellement à l'intérieur.

En utilisant ces données, vous pouvez déterminer quel mot est terminé et fournir des suggestions contextuelles. Bien qu'il existe des moyens de le faire manuellement, Bash fournit une autre commande utile, Compgen. Cela peut générer de nombreux types de suggestions basées sur des choses comme les fonctions ou commandes disponibles, et le mot tapé jusqu'à présent. L'option -W recherchera une liste de mots statique:

        $ compgen -W "one two three" o
one
$ compgen -W "one two three" t
two
three

Ainsi, vous pouvez passer un appel à Compgen dans le gestionnaire de suggestions et profiter de suggestions appropriées et spécifiques au contexte avec un script très minime:

        _complete_todos_bash() {
    COMPREPLY=( $( compgen -W "edit help" -- "${COMP_WORDS($COMP_CWORD)}" ) )
}

complete -F _complete_todos_bash todos

Tout rassembler

Pour vos scripts personnels, vous courez probablement dans un environnement connu: c'est-à-dire Bash ou Zsh. Mais pour des scripts plus portables, que vous voudrez peut-être partager avec d'autres ou utiliser sur plusieurs systèmes, vous devez résumer une partie de ce code.

Voici une version complète du script d'achèvement qui fonctionne dans Zsh ou Bash, en détectant le shell dans lequel il s'exécute et en exécutant le code pertinent.

        SUBCOMMANDS=(help edit halt)

_complete_todos_zsh() {
    compadd $SUBCOMMANDS
}

_complete_todos_bash() {
    COMPREPLY=( $( compgen -W "${SUBCOMMANDS(*)}" -- "${COMP_WORDS($COMP_CWORD)}" ) )
}

if ( -n "${ZSH_VERSION:-}" ); then
    autoload -Uz compinit
    compinit
    compdef _complete_todos_zsh todos
elif ( -n "${BASH_VERSION:-}" ); then
    complete -F _complete_todos_bash todos
fi

Les variables d'environnement Zsh_Version et Bash_Version annoncent dans quel shell nous exécutons actuellement. N'oubliez pas que le shell dans lequel votre commande fonctionne est sans importance, c'est le shell qui invoque le système d'achèvement, dans lequel l'utilisateur a appuyé sur l'onglet, qui compte ici.

Ce script stocke ses suggestions dans une variable de sous-communs auxquelles les deux fonctions ont accès. Ils l'utilisent chacun pour définir les compléments pris en charge, Zsh en appelant la fonction compadd et en basant en définissant la variable compreply. Notez que Bash doit effectuer beaucoup de massage syntaxiquement lourde des types à convertir entre les tableaux et les chaînes.

Vous pouvez enregistrer le script ci-dessus dans un seul fichier – EG completion.sh – puis la saisie de ce fichier à partir de votre .bashrc et / ou .zshrc comme ceci:

        . /path/to/completion.sh

Étapes suivantes

Nous avons à peine rayé la surface des compléments personnalisés de la coquille. En utilisant ce script simple, vous pouvez ajouter des compléments pour un ensemble fixe de sous-communs simples, mais il y a beaucoup plus à exécuter des programmes sur la ligne de commande que vous voudrez peut-être tenir compte.

Un script d'achèvement robuste doit tenir compte de la ligne de commande complète, car d'autres arguments pourraient affecter celui que vous essayez de terminer.

★★★★★