1

The first function works when executed on or in the body of an org headline. The second function doesn't return anything even though more than one headline in my set of agenda files has the org properties noted in the doc string to the first function. Perhaps I should use org-element-map instead? Please help me get this working:

(require 's)  ; s.el string library for s-split
(defun my-org-task-schedule-warn-func ()
  "Use org properties such as

  :PROPERTIES:
  :COMPLETE-BEFORE: <2016-04-19 Tue 19:55>
  :Effort:   1:00
  :END:

  on an org headline to generate scheduling warnings, ala Watership Planner."

  ;; Only match headlines with the COMPLETE-BEFORE and EFFORT properties.
  (if (and (assoc "COMPLETE-BEFORE" (org-entry-properties))
          (assoc "EFFORT" (org-entry-properties)))
      (let* ((props (org-entry-properties)) ; Get the properties for the
                                            ; current headline.
            (complete-before-string
              (cdr (assoc "COMPLETE-BEFORE" props)))
            (complete-before
              (org-read-date nil t
                            complete-before-string nil))
            (effort-string
              (cdr (assoc "EFFORT" props)))   ; Using h:mm format.
            (effort-string-components (s-split ":" effort-string))
            (effort-hours  (string-to-int (first effort-string-components)))
            ;; Turn org-mode effort format into minutes.
            (effort-minutes
              (+ (* effort-hours 60)
                (string-to-int (second effort-string-components))))
            (time-buffer-minutes 15) ; Amount of warning time (in minutes) within
                                      ; which to start notifying user that
                                      ; they might not meet their scheduling
                                      ; objective. This would ideally be a
                                      ; customizable value.
            (current-time-plus-effort
              (time-add (current-time)
                        (seconds-to-time (* effort-minutes 60))))
            (current-time-plus-effort-plus-buffer
              (time-add
              current-time-plus-effort
              (seconds-to-time (* time-buffer-minutes 60)))))
        (print (current-time-string complete-before))
        (print (current-time-string current-time-plus-effort-plus-buffer))
        (if (time-less-p complete-before current-time-plus-effort-plus-buffer)
            (progn
              (let ((msg (nth 4 (org-heading-components))))
                (print
                (concat
                  "Warning! You are in danger of not completing the task titled: "
                  msg))
                (if (fboundp 'my-org-task-schedule-warn)
                    ;; Pop up an OS X notifier window with msg and play warning sound
                    (my-org-task-schedule-warn
                    "Schedule warning for task:"
                    msg))))
          (print "You are still ok.")))))

;;; TODO: It'd be nice to set the MATCH to only those headlines with
;;; the COMPLETE-BEFORE and EFFORT properties at the level of
;;; org-map-entries instead of inside my-org-task-schedule-warn.
(defun my-org-check-schedule-warnings ()
  (org-map-entries
  (my-org-task-schedule-warn-func) nil 'agenda))

UPDATE: Responding to @lawlist's request below, for the curious, I can say this is just a germinal idea toward implementing a small bit of functionality available in the Windows scheduling app named 'Watership Planner'. It doesn't compete with org agenda or any other features of org. Watership Planner has this nice feature (for my purposes - especially with org habits) whereby you can say that you want to complete a task before a certain time of day. WP looks at the duration you have specified for the task and if the current time is such that you are getting close to running out of time to start the task in order to finish by the completion time then it will warn you with a notification and sound. It is sort of like having a personal scheduling assistant since you don't specify exactly when you want to do something, just a window of time on a given day and the WP agent notifies you when your window is elapsing without completion. The first hack I have here does just that but it doesn't work like Watership Planner's version of this feature yet. If you are still curious, you can download Watership Planner demo and run it for free to see what I am talking about. Again, it is only this feature that I am exploring, not other aspects of Watership Planner, many of which would be redundant with org mode.

  • Welcome to stackexchange! Please add some details in English as to what it is that you are trying to accomplish, instead of just showing us some code. In general, it is not necessary to use org-map-entries to create something like the *Org Agenda* buffer or to extract the raw data that is used to create that buffer or similar calendar buffers such as calfw: emacs.stackexchange.com/a/12563/2287 I understand you want to have something to do with setting alarms and so forth, but I'd rather not guess. – lawlist Apr 20 '16 at 6:39
  • The function my-org-task-schedule-warn-func does not return a function. Therefore I assume that you should replace (my-org-task-schedule-warn-func) in my-org-check-shedule-warnings with #'my-org-task-schedule-warn-func (note the function-quote). – Tobias Apr 20 '16 at 15:55
  • Note, you do not need s-split. s-split is just a wrapper for split-string. So, see the help for split-string and simplify the example by using split-string and removing (require 's). – Tobias Apr 20 '16 at 15:58
  • @Tobias, that was it. Doh, thank you! I guess I was tired. If you make it an answer I can accept it. – Joe Apr 20 '16 at 16:57
  • I thought a moment whether this question-answer pair is of general interest. At first I tended to propose to delete the question because it was more like a hiccup in the programming flow. Afterwards I thought maybe someone actually really needs help in using org-map-entries with function argument. So I wrote an answer anyway and formulated it as clear as possible. – Tobias Apr 20 '16 at 17:18
4

org-map-entries requires a function as first argument.

You wrote

(org-map-entries (my-org-task-schedule-warn-func) nil 'agenda)

but (my-org-task-schedule-warn-func) does not return a function.

You actually wanted to use my-org-task-schedule-warn-func as the function. So you should replace the function call (my-org-task-schedule-warn-func) with the function symbol #'my-org-task-schedule-warn-func:

(org-map-entries #'my-org-task-schedule-warn-func nil 'agenda)
  • I don't know if things have changed since your answer, but I will point out that the docs say 'FUNC' is a function or a Lisp form. so his choice of form instead of function name should work. – jtgd Jul 10 '17 at 8:24
  • @jtgd No, org-map-entries is a function and not a macro. If the form (my-org-task-schedule-warn-func) is not quoted in the call of org-map-entries it will be evaluated before org-map-entries can do anything with it. – Tobias Jul 10 '17 at 9:21
  • 1
    I see your point about quoting it, but I was merely stating what the docs said. Perhaps the docstring should be updated. – jtgd Jul 11 '17 at 23:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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