1

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 1

1

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*>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.