Le site arthur.bebou.netlib.re - retour accueil
git clone git://bebou.netlib.re/arthur.bebou
Log | Files | Refs |
commit 693d2f3418a625857175bfce89ec030473280c10 parent dee2907d087df9ab9889bae8fba7e939dbbf5c57 Auterice: Arthur Pons <arthur.pons@unistra.fr> Date: Wed, 8 May 2024 16:23:34 +0200 Nouvel article liverepl Diffstat:
A | contents/liverepl/index.sh | | | 195 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 195 insertions(+), 0 deletions(-)
diff --git a/contents/liverepl/index.sh b/contents/liverepl/index.sh @@ -0,0 +1,195 @@ +#! page +title: Évaluer ses scripts en temps réel +author: Arthur Pons +description: Il est parfois fatiguant de faire l\'aller retour entre l\'écriture d\'une commande et son exécution. Créons, avec vim et/ou tmux des environnements permettant de fondre les deux +publication: 2024-05-09 + +sectionmd: main + +## Objectif + +L'objectif est d'avoir, l'un à côté de l'autre, un script et ses sorties STDERR +et STDOUT, en temps réel avec une mise à jour à chaque fois que l'on modifie le +script. Une interface comme celle-ci devrait permettre de faciliter l'écriture +de scripts dont la sortie nous intéresse, typiquement lorsqu'il faut traiter du +texte et quand itérer souvent et rapidement est souhaitable[^1]. Elle pourrait +également être un bon outil pour l'enseignement de `sed`, `awk`, `paste`, `cut`, +`tr` et toute la bande que j'aime bien. + +Il n'est pas question ici d'analyser les actions du script et d'afficher en +français les impacts qu'il a eu sur le système (création/suppression de fichier +etc). Il est question de faciliter l'écriture d'une commande `sed` un peu +dantesque sans avoir à systématiquement exécuter le script à la main. + +L'idée me vient de +[fzrepl](https://github.com/DanielFGray/fzf-scripts/blob/master/fzrepl) de +Daniel F Gray. Je voulais quelque chose de similaire mais qui fonctionne +pour une quantité arbitraire de commandes et éditable dans vim. + +Au passage je découvre sans l'avoir prévu que ce système me permet de résoudre +d'une manière bien plus puissante qu'auparavant un problème que j'avais documenté +dans ce [vieil article](/benchmarkfrancium/#et-alors-), section : +"L’utilisation d’éditeurs de texte s’interfaçant bien avec le système permet de +tester des bouts de markdown". En effet, si j'ouvre l'un des fichiers sources +de ce site avec la configuration vim qui va suivre j'obtiens automatiquement le +résultat html dans la fenêtre droite. + +## Implémentation + +J'ai pour le moment la flemme de gérer les arguments de façon à faire des +choses différentes selon si on passe un argument un script déjà existant ou +pas, selon si le chemin est absolu ou relatif etc. Les scripts tels que +présentés en dessous vont donc systématiquement tout créer en tant que fichier +temporaire. Si à la fin de votre expérimentation vous voulez sauvegarder le +script vous pouvez toujours lancer `:w votre_script.sh`. + +### Avec vim tout seul + +Commençons d'abord par créer les fichiers qui vont contenir le script et sa +sortie et rendre le script exécutable : + + script=$(mktemp) + data=$(mktemp) + chmod +x "$script" + +Vient ensuite l'ouverture de vim et sa configuration : + + vim -c "set autowrite"\ + -c "autocmd TextChanged * silent! !$script > $data 2>&1"\ + -c "autocmd TextChangedI * silent! !$script > $data 2>&1"\ + -c "vnew $data"\ + -c "set updatetime=100 | set autoread | autocommand CursorHoldI * checktime | autocommand CursorHold * checktime"\ + -c "wincmd h | doautocmd TextChanged"\ + "$script" + +Vim est appelé avec tout un tas de commandes suivant l'option `-c` qui +s'exécuteront automatiquement au lancement. Le denier argument est le chemin +vers le script. + +Expliquons chacune des commandes vim : + + * `set aw` : le fichier sera automatiquement écrit à chaque fois qu'une + commande externe sera lancée + * `autocmd TextChanged * silent! !$script > $data 2>&1` : A chaque fois que + le texte change en mode normal on exécute, en ignorant sa sortie et ses + erreurs éventuelles (`silent!`), le script dont on redirige tout vers le + fichier de sortie + * Idem mais en mode insertion + * `vnew $data` : on ouvre une fenêtre verticale avec le fichier de sortie + * `set updatetime=100 | set autoread | autocommand CursorHoldI * checktime | + autocommand CursorHold * checktime` : On modifie l'intervalle de mise à jour + à 100ms, on met le buffer avec e fichier de sortie en lecture automatique + (il se rafraichit à chaque changement), on force l'exécution de `checktime` + à chaque première fois que le curseur ne bouge plus pendant 100ms après + qu'il a bougé + * `wincmd h | doautocmd TextChanged` : on revient sur la fenêtre avec le + script et on déclenche une première fois l'un des évènements pour peupler + le fichier de sortie (utile si l'on ouvre un script déjà existant) + +Finalement on affiche les chemins des deux fichiers temporaire quand on ferme +vim au cas-où l'on en est besoin : + + echo "script : $script" + echo "données : $data" + +Les avantages de cette version sont de ne pas dépendre de watch ni de tmux et +de pouvoir parcourir la sortie dans un buffer vim avec tout ce que cela +implique comme possibilité. + +### Avec vim + tmux + watch + +Les dépendances sont : + + * Une version relativement à jour de vim (qui a les évènements `TextChanged*`) + * tmux + * watch + +On commence de la même manière : + + script=$(mktemp) + data=$(mktemp) + chmod +x "$script" + +Puis on crée la session tmux : + + tmux new \ + vim -c "set aw"\ + -c "autocmd TextChanged * silent! !$script > $data 2>&1"\ + -c "autocmd TextChangedI * silent! !$script > $data 2>&1"\ + -c "doautocmd TextChanged"\ + "$script"\ + \; split-window -h "watch -c -d -t -n 0.1 cat $data" \; select-pane -L + +Finalement on affiche les chemins en sortie de session : + + echo "script : $script" + echo "données : $data" + +Les avantages sont de ne pas avoir à utiliser le hack vim un peu étrange à base +de CursorHold pour que tout soit à jour, de voir ce qui a été modifié en sortie +à l'aide de `-d` de watch et être directement déposé dans tmux ce qui peut se +révéler utile pour retrouver votre travail plus tard. Évidemment ce dernier +point n'est pas essentiel si vous avez de toute façon l'habitude d'être dans +une session tmux quoi qu'il arrive. + +## L'espace entre les CLI des années 80 et les GUI + +Au delà des raisons évoquées [en intro](/liverepl/#objectif) j'ai une autre +motivation à écrire ce genre d'outils. + +De nombreuses critiques sont formulées envers les interfaces en ligne de +commande. Même si je pense qu'elles sont parfois injustes et le fruit d'apriori +culturels et techniques plus que de réelles limitations qui seraient par +ailleurs inexistantes dans les autres formes d'interfaces, il convient +d'admettre que l'expérience initiale dans un terminal linux est aride. +[Aurélien Tabard](https://tabard.fr/) en résume bien les principales raisons : + +> Si la découvrabilité est en effet un point important, la gestion des erreurs +> l'est tout autant. Le undo n'est pas tellement développé dans les cli, pourtant +> la capacité d'essai-erreur-correction est facteur d'apprentissage important +> (oui il y a des façons de se tromper élégamment dans un terminal, mais le jour +> ou tu te trompes pour une raison ou une autre, le undo n'est pas là). D'autre +> notions permettent comme celles de gouffre d'évaluation et d'exécution peuvent +> expliquer le succès des gui. Enfin la capacité des systèmes à communiquer sur +> ce qu'ils permettent de faire (voir [par exemple ce +> papier](http://jovermeulen.com/Research/FeedforwardCHI2013) sur les +> affordances percues et le feedforward) est peu présente dans les cli. + +De fait beaucoup de personnes sont introduites aux cli via des cours, des +tutos, des outils ne cherchant pas à faciliter l'apprentissage et l'usage des +cli et tombant la tête la première dans chacun des points soulevés par +Aurélien. Personnellement j'ai fait mes premières années de shell en école +d'ingénieur sans jamais savoir que l'on pouvait chercher dans l'historique des +commandes avec `ctrl+r`, que beaucoup de commandes avaient des options pour +lister ce qu'elles allaient faire avant de les faire, que l'on pouvait mettre +beaucoup de couleurs dans les terminaux modernes, que l'existence des TUI +implique que l'on puisse faire des choses comme fzy, qu'il existait des shells +moins complexes que bash et avec une super auto-complétion pour un large +ensemble de commande ou une simple liste, même un peu indigeste, des commandes +généralement disponibles sur un Unix. J'ai le sentiment que la conséquence de +cela est que de nombreuses personnes, même dans le métier, n'ont qu'une vision +très limitée de ce que peuvent les cli et a fortiori des TUI qui fonctionnent +dans un terminal. Il est donc naturel que la plupart des personnes perçoivent +ces interfaces comme bloquées dans les années 70/80 et ne s'y tournent que pour +les usages à raison catalogués comme les plus appropriés. Et pourtant on peut +y mener la majorité de sa vie numérique. + +Attention, contrairement à l'impression que j'ai trop souvent donné lorsque je +parle de ce sujet, l'idée n'est pas de tout faire dans un terminal simplement +parce que je kiffe le terminal. C'est parce que l'usage de GUI modernes me +pousse à changer mon matériel, à mettre de la distance entre les personnes qui +produisent les logiciels que j'utilise et moi et à cloisonner mes logiciels +plutôt que de les faire causer entre eux que je m'intéresse à autre chose. Ne +sachant pas où me tourner pour trouver une communauté et une culture +ingénieurale axées sur le développement de GUI sobres, interopérables et +techniquement simples, je me tourne vers une communauté et une culture qui, la +plupart du temps, regroupe toutes ces qualités, j'ai nommé celle des personnes +qui vivent dans un terminal Unix. + +Je cherche donc, avec des outils comme celui décrit dans cet article, à montrer +qu'il existe un espace entre les GUI d'aujourd'hui et les CLI des années 80 +dans lequel on peut aborder les points soulevés par Aurélien tout en profitant +des propriétés techniques plus avantageuses pour la sobriété de nos usages du +numérique. + +[^1]: typiquement l'écriture d'une regex un peu complexe d'où le succès d'interfaces type [regex101](https://regex101.com/)