Est-il possible de lire les entrées utilisateur de STDIN tout en emmêlant un bloc source?

10

Est-il possible de lire les entrées utilisateur de STDIN tout en emmêlant un bloc source avec org-babel-tangle?

J'en suis conscient: Org Mode Babel - Évaluation interactive des blocs de code .

Cela n'aide pas à résoudre ce cas d'utilisation particulier, car il ne permet toujours pas une entrée STDIN appropriée à partir du shell, mais simule uniquement une entrée limitée en interne pour Emacs.

Contexte

Je voudrais utiliser Babel d'Org pour apprendre de nouveaux langages de programmation (Perl et Bash) en exécutant quelques tutoriels à partir d'un seul fichier org.

Le problème est que de nombreux didacticiels reposent sur STDIN. Par exemple, si l'on exécute le tlbit perl suivant:

#+BEGIN_SRC perl :tangle hello-name.pl  :results output :export code
use 5.010;
use strict;
use warnings;

say "What is your name?";
my $name=<STDIN>;
say "Hello $name, how are you?";

#+END_SRC

Emacs n'attendra pas l'interaction de l'utilisateur pour taper correctement un nom sur STDIN, et il affichera immédiatement:

#+RESULTS:
: What is your name?
: Hello , how are you?

Même chose en utilisant un exemple bash. Ce:

#+BEGIN_SRC sh  :results output :export code :tangle dir-input.sh
#!/bin/bash

if [ -z "$TEST_DIR" ]
then
    echo "TEST_DIR was not set, please enter the path: "
    read input_variable
    export TEST_DIR=$input_variable
fi
#+END_SRC

N'attendra pas la saisie de l'utilisateur et Emacs retournera immédiatement ceci:

#+RESULTS:
: TEST_DIR was not set, please enter the path: 

Existe-t-il un moyen natif pour Emacs d'attendre l'entrée sur un bloc enchevêtré en cours d'exécution?

Sinon, pourriez-vous donner quelques conseils sur la façon d'écrire quelque chose comme une tangle-and-run-via-shell-bufferfonction qui:

  • Enchevêtrer le bloc de code au point, en enregistrant avec le nom de fichier donné,
  • exécuter le fichier correspondant dans un shelltampon visible ,
  • acceptant éventuellement une entrée de l'utilisateur,
  • et enfin de signaler STDOUT, le cas échéant, à #+RESULTS:?

Si une telle fonctionnalité n'est pas (encore) implémentée dans Org, comment pourrait-on l'implémenter avec elisp?


Mise à jour: Après avoir recherché et étudié davantage les manuels Emacs et elisp, il semble que la façon de le faire serait de tirer parti de Comint , comme peut-être make-comint-in-buffer.

(make-comint-in-buffer "*cmd-buffer*" nil "perl" nil "hello-name.pl")

Malheureusement, c'est au-dessus de ma tête en ce moment 😣

gsl
la source

Réponses:

4

Essaye ça

Remarque : Apportez les modifications mineures suivantes à votre bloc de code:

  • Déplacé #!/bin/bashdans l'en-tête du bloc de code :shebang #!/bin/bashpour définir automatiquement les autorisations des fichiers exécutables lorsque le bloc est emmêlé dir-input.sh.

  • Le code de débogage ajouté pour montrer a $TEST_DIRété attribué correctement à partir de read input_variable.

#+BEGIN_SRC sh  :results output :export code :tangle dir-input.sh :shebang #!/bin/bash

if [ -z "$TEST_DIR" ]
then
    echo "TEST_DIR was not set, please enter the path: "
    read input_variable
    export TEST_DIR=$input_variable
    echo "# export TEST_DIR=$TEST_DIR"
fi
#+END_SRC   

Puis créé un nouveau bloc de code pour appeler un fichier enchevêtré ./dir-input.sh.

#+BEGIN_SRC sh :results output :shebang #!/bin/bash  :var USER_INPUT=(read-string "Test Dir: ")
  echo $USER_INPUT | ./dir-input.sh 
#+END_SRC

En-tête d'avis :var USER_INPUT=(read-string "Test Dir: ")

Cet en-tête affichera une Test Dir:invite dans la minibufferfenêtre lorsque le bloc de code est exécuté à l'aide de a C-c C-c.

Entrez le chemin, par exemple / chemin / vers / test / dir enter

et le bloc passera l'entrée au ./dir-input.shvia STDIN. Vous devriez voir ce qui suit#+RESULTS:

#+RESULTS:
: TEST_DIR was not set, please enter the path: 
: # export TEST_DIR=/path/to/test/dir

J'espère que cela a aidé!


Code testé avec:
GNU Emacs 24.4.1 (x86_64-apple-darwin14.0.0, NS apple-appkit-1343.14) de 2014-12-25
version org-mode: 8.3.2

Melioratus
la source
Cela aide beaucoup, merci. Une façon créative d'utiliser les vars, très instructive. Je me demande comment pourrais-je capturer STDIN "entièrement", en quelque sorte parler, c'est-à-dire comme on pourrait le faire à partir d'un shell natif? Par exemple, pour pouvoir lire de nouvelles lignes et contrôler les caractères (à côté de CTRL-D)?
gsl
1
@gsl - BTW - Je travaille toujours sur une nouvelle réponse à une question sur plusieurs lignes et caractères de contrôle. Si vous le comprenez avant moi, veuillez poster votre réponse.
Melioratus
Merci beaucoup d'avoir préparé une nouvelle réponse. Je cherche toujours une solution de travail. Je ne peux pas le comprendre par moi-même, toujours au-dessus de ma tête en ce moment. Je choisis votre réponse, et lorsque votre nouvelle apparaîtra, sélectionnez-la plus tard.
gsl
Salut @melioratus - avez-vous trouvé un moyen de gérer plusieurs lignes et de contrôler les caractères? Ce serait très utile dans de nombreux cas.
gsl
1
@gsl - Merci d'avoir suivi! Vous avez une lecture correcte de stdin serait vraiment utile et je cherche toujours! J'ai progressé en lisant stdin dans le tampon nommé à partir de la ligne de commande, puis en appelant elisp pour lire le tampon multiligne en variable. Cela fonctionne lors de la lecture à partir d'un tuyau, mais malheureusement pas encore pour le streaming stdin, c'est à dire tail file |fonctionne mais pas tail -f file |. Je vais parcourir mes notes et ajouter mon exemple multiligne partiellement fonctionnel comme nouvelle réponse. Merci pour rappel!
Melioratus