Как я могу ответить на приглашение минибуфера от elisp?

10

Иногда я использую интерактивные функции внутри функции, которую я пишу для собственного использования. Если функция запрашивает некоторую информацию (например, «Выходной файл: ~ /»), существует ли общий способ добавления текста в минибуфер, а затем нажмите клавишу ВВОД, чтобы пользователю не нужно было это делать?

В качестве примера предположим, что я хочу запустить org-latex-export-to-pdfвнутри функции, но не хочу, чтобы пользователь указывал имя файла. Запуск (org-latex-export-to-pdf)переместит точку в минибуфер, но, похоже, что-то вроде (insert "filename.tex")следующей строки не работает.

Сет Ротшильд
источник
3
Как правило, интерактивная функция должна запрашивать такую ​​информацию в своем interactiveпредложении. При вызове из elisp вы должны быть в состоянии передать информацию в качестве аргумента функции. Конечно, это не поможет вам, если функция, которую вы пытаетесь вызвать, не соответствует этой схеме.
Lindydancer
Да, я обнаружил, что это также имеет место, как правило (к сожалению, не в данный момент), поэтому может быть так трудно найти ответ на этот вопрос. Знаете ли вы, есть ли причина, по которой вы действительно хотите, чтобы пользователь печатал ответы на запросы из минибуфера?
Сет Ротшильд
Ваш комментарий неясен для меня. Вы хотите, чтобы пользователь запрашивал и отвечал или нет? Если нет, то программно найдите значения аргументов (имя выходного файла), которые вы хотите / нуждаетесь, и передайте их функции. Я предлагаю вам показать какой-нибудь код или каким-то другим образом прояснить и понять, в чем заключается ваша проблема и вопрос , или вопрос может быть закрыт как неясный.
Дрю
Я не хочу, чтобы пользователь (я) запрашивался. Я могу уточнить вопрос. Прочитав часть электронного письма, в котором вас несколько лет назад рассказывалось о том, как вернуть минибуфер, я думаю, что знаю, как это сделать. Если я получу это, я напишу это.
Сет Ротшильд
1
Пожалуйста, опубликуйте конкретный пример интерактивной функции, которую вы хотели бы использовать при написании своей собственной функции, чтобы другой участник форума мог продемонстрировать, как передать аргумент функции и полностью обойти минибуфер.
юрист

Ответы:

3

Интересная проблема. Похоже , редактор запускается post-command-hookкаждый раз , когда он вводит новую команду петлю, т.е. recursive-edit. Но мы можем начать с того minibuffer-setup-hook, что выполняет функцию после входа в минибуфер. Хотя это позволяет вставлять ввод, слишком рано выходить из минибуфера, потому что перехват еще не настроен.

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

Вот где нам нужно обернуть «аргументы» в нашем собственном «командном цикле», который выполняется каждый раз, когда мы вводим a recursive-edit, и в этот момент он получает один аргумент и выбрасывает на один уровень вверх через 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
politza
источник
3

Я написал для этого макрос with-simulated-input, который вы можете получить здесь . Это позволяет вам предоставлять произвольный ввод, а также выполнять произвольные формы lisp для имитации взаимодействия с пользователем.

Например:

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

возвратил бы "hello world", с "hello", вставленным первой строкой, "world", вставленным через код lisp, и, наконец, "RET", чтобы завершить ввод.

Он поставляется с набором тестов, который вы можете посмотреть для большего количества примеров использования.

Райан Томпсон
источник
0

Похоже, что использование run-with-timerс insertсделает работу.

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

Команда, insertпомещенная впоследствии, появляется слишком быстро. Он пытается вставить строку, прежде чем найдется место для ее вставки.

Сет Ротшильд
источник
Я бы порекомендовал пересмотреть ваш вопрос, чтобы обратиться за помощью, чтобы программно передать имя файла org-export-output-file-nameпри использовании, org-latex-export-to-pdfчтобы у пользователя не запрашивалось имя файла. Вы можете приложить свои усилия в вопросе - например, run-with-timerи т. Д. - однако, это не очень хорошее решение (на мой взгляд). Лучшее решение - правильно передать имя файла программно, чтобы минибуфер никогда не открывался. Я бы порекомендовал удалить этот ответ, чтобы кто-то с большим elispопытом получил лучшее решение .
юрист
@lawlist вопрос о том, как передать имя файла org-latex-export-to-pdf, не тот, который меня интересует. Это пример, поскольку вы, похоже, намеревались добавить его. Я задал вопрос, который я имел в виду: есть ли способ надежно ответить на запрос минибуфера через elisp. Индивидуальное решение очень не то, что я ищу. Из вашего комментария могу сделать вывод, что это не рекомендуется.
Сет Ротшильд