Como posso responder a um prompt do minibuffer da elisp?


10

Ocasionalmente, me pego usando funções interativas dentro de uma função que estou escrevendo para meu próprio uso. Se uma função solicitar algumas informações (por exemplo, "Arquivo de saída: ~ /"), existe uma maneira geral de adicionar texto ao minibuffer e pressione enter para que o usuário não precise fazer isso?

Como exemplo, suponha que eu queira executar org-latex-export-to-pdfdentro de uma função, mas não quero que o usuário precise especificar um nome de arquivo. Correr (org-latex-export-to-pdf)moverá o ponto para o minibuffer, mas colocar algo como (insert "filename.tex")na próxima linha não parece funcionar.


3
Normalmente, uma função interativa deve solicitar essas informações em sua interactivecláusula. Quando chamado de elisp, você deve ser capaz de passar as informações como argumento de função. Obviamente, isso não ajuda, caso a função que você está tentando chamar não siga esse design.
Lindydancer 30/03

Sim, descobri que esse também é o caso (infelizmente não no momento) e talvez seja por isso que a resposta foi tão difícil de encontrar. Você sabe se existe um motivo de design para realmente querer que o usuário digite respostas para solicitações do minibuffer?
Seth Rothschild

Seu comentário não é claro para mim. Deseja que o usuário seja consultado e responda ou não? Caso contrário, apareça programaticamente os valores do argumento (nome do arquivo de saída) que você deseja / precisa e os passe para a função. Sugiro que você mostre algum código ou, de alguma outra forma, especifique e esclareça qual é o seu problema e pergunta , ou a pergunta corre o risco de ser encerrada por não ser clara.
Tirou

Eu não quero que o usuário (eu) seja consultado. Eu posso esclarecer a pergunta. Depois de ler parte de um tópico de e-mail envolvendo você de alguns anos atrás sobre como puxar o minibuffer, acho que sei como fazer isso. Se eu conseguir, eu escreverei.
Seth Rothschild

11
Poste um exemplo específico de uma função interativa que você gostaria de usar ao escrever sua própria função, para que outro participante do fórum possa demonstrar como passar um argumento para a função e ignorar completamente o minibuffer.
lawlist

Respostas:


3

Problema interessante. Parece que o editor é executado post-command-hooktoda vez que entra em um novo loop de comando, ou seja, a recursive-edit. Mas podemos começar com minibuffer-setup-hook, que executa uma função depois de inserir o minibuffer. Embora isso permita a inserção de entrada, é muito cedo para sair do minibuffer, porque a captura ainda não foi configurada.

(defmacro with-minibuffer-input (form &rest inputs)
  (declare (indent 1))
  `(minibuffer-with-setup-hook
       (lambda ()
         (minibuffer-input-provider ',inputs))
     ,form))

É aí que precisamos envolver os 'argumentos' em nosso próprio 'loop de comando', que são executados toda vez que inserimos a recursive-edit, quando ele abre um argumento e sobe um nível, via exit-minibuffer.

;; -*- lexical-binding: t -*-
(defun minibuffer-input-provider (inputs)
  (let ((hook (make-symbol "hook")))
    (fset hook (lambda ()
                 (remove-hook 'post-command-hook hook)
                 (when inputs
                   (when (= 0 (minibuffer-depth))
                     (error "Too many inputs"))
                   (when (cdr inputs)
                     (add-hook 'post-command-hook hook))
                   (insert (pop inputs))
                   (exit-minibuffer))))
    (add-hook 'post-command-hook hook)))


(with-minibuffer-input (call-interactively 'find-file)
  "/")

(with-minibuffer-input (call-interactively 'occur)
  "\\(foo\\)\\(bar\\)" "\\1");;C-u C-x C-e

;;foobar

(with-minibuffer-input (call-interactively 'replace-string)
  "foo" "bar")

;; foo

3

Eu escrevi uma macro para isso chamada with-simulated-input, que você pode obter aqui . Ele permite que você forneça entradas arbitrárias, bem como execute formulários arbitrários de lisp para simular a interação do usuário.

Por exemplo:

(with-simulated-input '("hello SPC" (insert "world") "RET")
  (read-string "Enter greeting: "))

retornaria "hello world", com o "hello" inserido pela primeira string, o "world" inserido via código lisp e, finalmente, "RET" para finalizar a entrada.

Ele vem com um conjunto de testes que você pode ver para obter mais exemplos de uso.


0

Parece que o uso run-with-timercom insertfará o trabalho.

(run-with-timer .2 nil 'insert "filename.tex")
(run-with-timer .3 nil 'execute-kbd-macro (kbd "RET"))
(org-latex-export-to-pdf)

O comando, insertquando colocado depois, está surgindo muito rapidamente. Ele tenta inserir a string antes que haja um local para inseri-la.


Eu recomendaria revisar sua pergunta para procurar assistência através da programação de um nome de arquivo ao org-export-output-file-nameusá- org-latex-export-to-pdflo para que o usuário não seja solicitado. Você pode colocar seus esforços na questão - por exemplo, run-with-timeretc. - no entanto, não é uma boa solução (na minha opinião). A melhor solução é passar adequadamente um nome de arquivo programaticamente, para que o minibuffer nunca seja aberto. Eu recomendaria excluir esta resposta para que você obtenha uma solução melhor por alguém com mais elispexperiência.
lawlist

@lawlist a questão de como passar um nome de arquivo org-latex-export-to-pdfnão é a que me interessa. É um exemplo, já que você parecia querer que eu adicionasse um. A pergunta que fiz foi a que eu quis dizer: existe uma maneira de responder com segurança a um prompt do minibuffer através do elisp. Uma solução caso a caso não é muito o que estou procurando. Pelo seu comentário, posso deduzir que isso não é recomendado.
Seth Rothschild
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.