12

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?

  • 2
    Is the org-agenda-time-grid not sufficient for your needs? gnu.org/software/emacs/manual/html_node/org/… – lawlist Dec 15 '14 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. – scaramouche Dec 15 '14 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. – scaramouche Dec 17 '14 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 Jan 6 '15 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. – scaramouche Jan 7 '15 at 0:29
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).

  • 1
    Useful, but I really hope someone comes up with a solution that does not involve directly overriding a function in org-agenda. – holocronweaver Dec 28 '17 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 Dec 30 '17 at 10:26

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.