13

I would like to make it easy to find where are the free blocks of time in my org-mode agenda.

For instance, if I have two appointments one 9:30am-10:30am and another 11:15am-12:30pm, I would like to see at a glance that the 10:30am-11:15am block is free.

In other words, I want to be able to distinguish free time as easily as it is done in a graphical agenda such as Google calendar.

Is there a way to make the empty blocks of time easy to see? Perhaps to colorize the empty blocks that are longer than a given number of minutes?

5
  • 2
    Is the org-agenda-time-grid not sufficient for your needs? gnu.org/software/emacs/manual/html_node/org/…
    – lawlist
    Commented Dec 15, 2014 at 6:05
  • 2
    The grid is not enough, as it shows ups even when the time is busy (e.g., if there's a 9:30am-10:30am meeting, there will be a grid line at 10:00am). I would like busy and non-busy times to be easy to distinguish. Commented Dec 15, 2014 at 6:22
  • 1
    I have thought a little bit more about this functionality. I believe the most useful and simplest to implement would be to change the color of the time block (only the name of the time block, e.g., 8:00-9:00) for those time blocks that have more than a given amount of free time (e.g., more than 15 minutes). Both the color and the minimum free time should be user configurable. Commented Dec 17, 2014 at 14:01
  • 3
    @scaramouche, a user on the org-mode mailing list (orgmode.org/worg/org-mailing-list.html) asks if you've tried calfw (emacswiki.org/emacs/Calfw).
    – daveloyall
    Commented Jan 6, 2015 at 23:39
  • 2
    @daveloyall, many thanks for pointing to the mailing list discussion. I just tried calfw (and it is beautiful!), but it does not seem to have the function I want (to visually spot open times in the day). For those who want to try calfw+org (highly recommended): get calfw from Melpa, in init.el, include (require 'calfw-org), and to call the calendar do M-x cfw:open-org-calendar. Commented Jan 7, 2015 at 0:29

1 Answer 1

2

Because of this question of my own I looked at the function org-agenda-add-time-grid-maybe which creates the time grid. The code posted there (which is not written by me) does remove a grid line if the time is busy as requested in the OP's comment.

Like you, I wanted to create a visual block in some way. By mixing up the original code of org-agenda-add-time-grid-maybe and the defadvice by Michael Ekstrand posted in the other thread I came up with the following code for org-agenda-add-time-grid-maybe. It will output the grid lines in a different color (for the moment I use the face org-archived) and the times will be followed by a different string. Both can be changed to your liking.

(defun org-agenda-add-time-grid-maybe (list ndays todayp)
  "Add a time-grid for agenda items which need it.

LIST is the list of agenda items formatted by `org-agenda-list'.
NDAYS is the span of the current agenda view.
TODAYP is t when the current agenda view is on today."

  (catch 'exit
   (cond ((not org-agenda-use-time-grid) (throw 'exit list))
         ((and todayp (member 'today (car org-agenda-time-grid))))
         ((and (= ndays 1) (member 'daily (car org-agenda-time-grid))))
         ((member 'weekly (car org-agenda-time-grid)))
         (t (throw 'exit list)))
   (let* ((blocks (mapcar (lambda (x)
                            (let ((start (get-text-property 1 'time-of-day x))
                                  (dur (get-text-property 1 'duration x)))
                              (cond
                               ((and start dur) (cons start
                                                      (org-time-from-minutes
                                                       (truncate
                                                        (+ dur (org-time-to-minutes start))))))
                               (start start)
                               (t nil))))
                          list))
          (have (delq nil (mapcar
                           (lambda (x) (get-text-property 1 'time-of-day x))
                           list)))
          (string (nth 3 org-agenda-time-grid))
          (gridtimes (nth 1 org-agenda-time-grid))
          (req (car org-agenda-time-grid))
          (remove (member 'remove-match req))
          new time)
     (if (and (member 'require-timed req) (not have))
         ;; don't show empty grid
         (throw 'exit list))

     (while (setq time (pop gridtimes))
       (unless (and remove (member time have))
         (let* ((windows (delq nil blocks))
                (hit nil))
           (dolist (busy windows)
             (unless hit
               (when (and (>= time (car busy))
                          (< time (cdr busy)))
                 (setq hit t))))
           (setq time (replace-regexp-in-string " " "0" (format "%04s" time)))
           (if hit
               (progn
                 (push (org-agenda-format-item
                        (concat string " dito") string nil "" nil
                        (concat (substring time 0 -2) ":" (substring time -2)))
                       new)
                 (put-text-property 2 (length (car new)) 'face 'org-archived (car new)))
             (progn
               (push (org-agenda-format-item
                      nil string nil "" nil
                      (concat (substring time 0 -2) ":" (substring time -2)))
                     new)
               (put-text-property 2 (length (car new)) 'face 'org-time-grid (car new))))
           (setq hit nil))))

     (when (and todayp org-agenda-show-current-time-in-grid)
       (push (org-agenda-format-item
              nil org-agenda-current-time-string nil "" nil
              (format-time-string "%H:%M "))
             new)
       (put-text-property
        2 (length (car new)) 'face 'org-agenda-current-time (car new)))

     (if (member 'time-up org-agenda-sorting-strategy-selected)
         (append new list)
       (append list new)))))

(defun org-time-to-minutes (time)
  "Convert an HHMM TIME to minutes."
  (+ (* (/ time 100) 60) (% time 100)))

(defun org-time-from-minutes (minutes)
  "Convert a number of MINUTES to an HHMM time."
  (+ (* (/ minutes 60) 100) (% minutes 60)))

Obviously, it would be more elegant to use defadvice, but I could not figure out where exactly to intervene. The function itself goes through every grid time (set in org-agenda-time-grid) and creates a new list with the final grid including faces (new).

2
  • 1
    Useful, but I really hope someone comes up with a solution that does not involve directly overriding a function in org-agenda. Commented Dec 28, 2017 at 20:47
  • I absolutely agree! Unfortunately, my knowledge of elisp and the org-mode code is not sufficient to come up with a working defadvice. Maybe, someone else can help out here, possibly using some of "my" code.
    – Fabian
    Commented Dec 30, 2017 at 10:26

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.