É possível ler a entrada do usuário do STDIN enquanto emaranha um bloco de origem?

10

É possível ler a entrada do usuário do STDIN enquanto emaranha um bloco de origem org-babel-tangle?

Estou ciente disso: Org Mode Babel - avaliação interativa de blocos de código .

Isso não ajuda a resolver esse caso de uso específico, pois ainda não permite a entrada adequada de STDIN do shell, mas simula apenas uma entrada limitada internamente para o Emacs.

fundo

Eu gostaria de usar o Babel da organização para aprender novas linguagens de programação (Perl e Bash) executando alguns tutoriais em um arquivo organizacional.

O problema é que muitos tutoriais contam com o STDIN. Por exemplo, se alguém executar o seguinte perl tidbit:

#+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

O Emacs não aguardará a interação do usuário digitar corretamente um nome no STDIN e produzirá imediatamente:

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

A mesma coisa usando um exemplo do bash. Este:

#+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ão esperará pela entrada do usuário e o Emacs retornará imediatamente isso:

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

Existe uma maneira nativa do Emacs aguardar a entrada em um bloco emaranhado em execução?

Caso contrário, por favor, dê algumas dicas sobre como escrever algo como uma tangle-and-run-via-shell-bufferfunção que:

  • Emaranhe o bloco de código no ponto, salvando com o nome de arquivo fornecido,
  • execute o arquivo correspondente em um shellbuffer visível ,
  • possivelmente aceitando informações do usuário,
  • e finalmente informando STDOUT, se houver, para #+RESULTS:?

Se esse recurso ainda não foi implementado na Org, como alguém poderia implementá-lo com o elisp?


Atualização: Depois de pesquisar e estudar mais os manuais do Emacs e elisp, parece que a maneira de fazer isso seria alavancar o Comint , como talvez make-comint-in-buffer.

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

Infelizmente, isso está na minha cabeça agora 😣

gsl
fonte

Respostas:

4

Tente isto

Nota : Feito as seguintes pequenas alterações no seu bloco de código:

  • Movido #!/bin/bashpara o cabeçalho do bloco de código :shebang #!/bin/bashpara definir automaticamente as permissões de arquivo executável quando o bloco é emaranhado dir-input.sh.

  • Adicionado código de depuração para mostrar $TEST_DIRfoi atribuído corretamente a 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   

Em seguida, criou um novo bloco de código para chamar o arquivo emaranhado ./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

Cabeçalho da nota :var USER_INPUT=(read-string "Test Dir: ")

Este cabeçalho exibirá um Test Dir:prompt na minibufferjanela quando o bloco de código for executado usando a C-c C-c.

Digite o caminho, por exemplo, / path / to / test / dir enter

e o bloco passará a entrada para a ./dir-input.shvia STDIN. Você deve ver o seguinte#+RESULTS:

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

Espero que tenha ajudado!


Código testado com:
GNU Emacs 24.4.1 (x86_64-apple-darwin14.0.0, NS apple-appkit-1343.14) da
versão 2014-12-25 org-mode: 8.3.2

Melioratus
fonte
Isso ajuda bastante, obrigado. Uma maneira criativa de usar vars, muito instrutiva. Eu estou querendo saber como eu iria capturar STDIN "totalmente", tipo de falar, ou seja, como se pudesse a partir do shell nativo? Por exemplo, para poder ler novas linhas e controlar caracteres (ao lado de CTRL-D)?
GSL
11
@gsl - BTW - Ainda estou trabalhando em uma nova resposta para a pergunta sobre várias linhas e caracteres de controle. Se você descobrir isso antes de mim, poste sua resposta.
Melioratus 23/06
Muito obrigado por preparar uma nova resposta. Ainda estou procurando uma solução funcional. Não consigo descobrir sozinho, ainda acima da minha cabeça agora. Estou escolhendo sua resposta e, quando a nova aparecer, selecione-a mais tarde.
GSL
Oi @melioratus - você conseguiu encontrar uma maneira de lidar com várias linhas e controlar caracteres? Isso seria bastante útil em muitos casos.
gsl 12/03
11
@gsl - Obrigado por acompanhar! Você está lendo corretamente o stdin seria realmente útil e eu ainda estou procurando! Eu progredi lendo stdin no buffer nomeado na linha de comando e depois chamei o elisp para ler o buffer multilinha na variável. Isso funciona ao ler de um canal, mas infelizmente ainda não está disponível para streaming em stdin, ou seja, tail file |funciona, mas não tail -f file |. Examinarei minhas anotações e adicionarei meu exemplo de multilinha parcialmente funcional como nova resposta. Obrigado pelo lembrete!
Melioratus 12/03