I'm using the org-pomodoro
, and I have added a function to the org-pomodoro-started-hook
that prompts the user for a reminder for what they should do during the break. However, I don't want to call read-from-minibuffer
directly from the hook, since that would block other hooks added to org-pomodoro-started-hook
from running until the user entered a prompt. What is the best way to prompt the user for input in a non-blocking manner? I'm envisioning a function that returns immediately after creating the minibuffer with the prompt but invokes a callback after the user input has been received.
1 Answer
The solution I've come up with is to run the function prompting for user input in a timer using run-at-time
:
(defun my-org-pomodoro-started-break-reminder-prompt (prompt)
"Create Google Calendar event for break reminder after ‘org-pomodoro' session."
(interactive "MBreak start reminder (leave empty for none): ")
(let ((remove? (or (null prompt) (string-empty-p prompt))))
(setq my-org-pomodoro-started-break-reminder-prompt
(if remove? nil prompt))
(unless (and remove? (null my-org-pomodoro-break-reminder-event-id))
(my-org-pomodoro--create-alarm-event
my-org-pomodoro-alarm-gcal-calendar-id
my-org-pomodoro-break-reminder-event-id
'my-org-pomodoro-break-reminder-event-id
(if remove? "break start" prompt)
org-pomodoro-end-time
remove?))))
(defun my-org-pomodoro-started-break-reminder-prompt-hook ()
"Adapt ‘my-org-pomodoro-started-break-reminder-prompt’ for hooks."
(run-at-time 0.1 nil
(lambda ()
(condition-case-unless-debug err
(progn
(call-interactively #'my-org-pomodoro-started-break-reminder-prompt)
(my-org-pomodoro-start-tick))
(t . (message "my-org-pomodoro-started-break-reminder-hook: error: %S" err))))))
(add-hook 'org-pomodoro-started-hook #'my-org-pomodoro-started-break-reminder-prompt-hook)
The hook is my-org-pomodoro-started-break-reminder-prompt-hook
, while my prompting function is my-org-pomodoro-started-break-reminder-prompt
(implicitly prompts using interactive
). I decided that, in order to remind myself to complete the break reminder prompt, I would not start my ticking sounds (by calling my-org-pomodoro-start-tick
) until after I've answered the prompt. This is easily done by just calling my-org-pomodoro-start-tick
after my-org-pomodoro-started-break-reminder-prompt
in a progn
block in the function run by run-at-time
.
edebug-trace
confirms that the other hook functions are immediately run after my-org-pomodoro-started-break-reminder-prompt-hook
, whereas the functions called by the timer only return after the other hooks run (in actuality, I didn't answer the prompt for 15 seconds or so).
======================================================================
1 -> (my-org-pomodoro-pomodoro-light-on)
1 <- my-org-pomodoro-pomodoro-light-on: #<process *pomodoro-light-on*>
======================================================================
1 -> (my-org-pomodoro-started-punch-in)
1 <- my-org-pomodoro-started-punch-in: t
======================================================================
1 -> (my-org-pomodoro-started-break-reminder-prompt-hook)
1 <- my-org-pomodoro-started-break-reminder-prompt-hook: [nil 25138 10149 773846 nil (closure (t) nil (condition-case err (progn (call-interactively #'my-org-pomodoro-started-break-reminder-prompt) (my-org-pomodoro-start-tick)) ((debug t) message "my-org-pomodoro-started-break-reminder-hook: error: %S" err))) nil nil 0 nil]
======================================================================
1 -> (my-org-pomodoro-started-create-log-event)
1 <- my-org-pomodoro-started-create-log-event: nil
======================================================================
1 -> (my-org-pomodoro-clear-break-end-alarm-id)
1 <- my-org-pomodoro-clear-break-end-alarm-id: nil
======================================================================
1 -> (my-org-pomodoro-pomodoro-light-on)
1 <- my-org-pomodoro-pomodoro-light-on: #<process *pomodoro-light-on*>
======================================================================
1 -> (my-org-pomodoro-started-punch-in)
1 <- my-org-pomodoro-started-punch-in: t
======================================================================
1 -> (my-org-pomodoro-started-break-reminder-prompt-hook)
1 <- my-org-pomodoro-started-break-reminder-prompt-hook: [nil 25138 10354 121408 nil (closure (t) nil (condition-case err (progn (call-interactively #'my-org-pomodoro-started-break-reminder-prompt) (my-org-pomodoro-start-tick)) ((debug t) message "my-org-pomodoro-started-break-reminder-hook: error: %S" err))) nil nil 0 nil]
======================================================================
1 -> (my-org-pomodoro-started-create-log-event)
1 <- my-org-pomodoro-started-create-log-event: nil
======================================================================
1 -> (my-org-pomodoro-clear-break-end-alarm-id)
1 <- my-org-pomodoro-clear-break-end-alarm-id: nil
======================================================================
1 -> (my-org-pomodoro-started-break-reminder-prompt "")
1 <- my-org-pomodoro-started-break-reminder-prompt: nil
======================================================================
1 -> (my-org-pomodoro-start-tick)
1 <- my-org-pomodoro-start-tick: #<process *org-pomodoro-ticking-process*>