I'm wondering if it is possible to display lines from an org table on my agenda.

Suppose I have an org file with the following content:

* expense

| <2017-08-17 15:11> | 13.00 | barber | :care: |
| <2017-08-17 12:06> |  7.60 | lunch  | :food: | 

I would like to see the following on my agenda:

Donnerstag 17 August 2017
               8:00...... ----------------
              10:00...... ----------------
              12:00...... ----------------
  gtd:        12:06...... 7.60 lunch :food:
              14:00...... ----------------
  gtd:        15:11...... 13.00 barber :care:

But unfortunately, the following is displayed:

Donnerstag 17 August 2017
               8:00...... ----------------
              10:00...... ----------------
              12:00...... ----------------
  gtd:        12:06...... expense
              14:00...... ----------------
  gtd:        15:11...... expense

If I do string-replace "|<" with "** <" and then "|" with " " (whitespace) I get the desired result.

Is there any way to make it work without modifying the table?

  • Can you provide a way to reproduce your problem starting with "emacs -Q"?
    – Realraptor
    Jan 1 '18 at 21:16

Maybe, there is a simpler way. But, one way is to do automagically just what you did manually. I.e., change the table rows to subheadings. Clearly we don't want to modify the original buffer. We just edit a clone of it. The only things we need to take care of are:

  1. Kill the clone when we are done.
  2. Don't create markers for the clone but for the original buffer.
  3. Find the right header-level for the sub-headings created for the table-rows.

If you paste the following stuff into your init file and re-start emacs table rows with time-stamps in the first column are interpreted like header lines in org-agenda.

(defun my-org-agenda-get-timestamps (oldfun &rest args)
  "Run OLDFUN (being `org-agenda-get-timestamps') with ARGS in clone buffer.
Before running `org-agenda-get-timestamps' change table rows
into header lines within the clone.
Kill clone when done.

This function can serve as :around advice for `org-agenda-get-timestamps'."
  (let* ((local-buffer-file-name (buffer-file-name))
         buffer-file-name ; Fake that this buffer had no file. `clone-buffer' needs that.
         (original-buffer (current-buffer)) ; markers are generated for the original buffer with ...
         (last-header-level 0) ; 
         (clone (clone-buffer)))
           (lambda (oldfun &rest args)
             (with-current-buffer original-buffer
               (apply oldfun args)))))
    (with-current-buffer clone
      (let ((re (concat "^\\(?:\\([[:space:]]*|[[:space:]]*\\)" org-element--timestamp-regexp "[[:space:]]*|\\)\\|\\([*]+\\) ")))
        (setq buffer-file-name local-buffer-file-name) ; `org-agenda-get-timestamps' uses buffer-file-name in link
        (goto-char (point-min))
        (while (re-search-forward re nil t)
          (if (match-string 1)
            (replace-match (concat (make-string (1+ last-header-level) ?*) " ") nil nil nil 1)
            (subst-char-in-region (line-beginning-position) (line-end-position) ?| ?\s t))
        (setq last-header-level (length (match-string 3)))))
        (advice-add 'org-agenda-new-marker :around org-agenda-new-marker-ad)
        (apply oldfun args))
    ;; 1st unwind form:
    (advice-remove 'org-agenda-new-marker org-agenda-new-marker-ad)
    ;; 2nd unwind form: kill clone
    (when (buffer-live-p clone)
      (with-current-buffer clone
        (set-buffer-modified-p nil)

(advice-add 'org-agenda-get-timestamps :around #'my-org-agenda-get-timestamps)

If you encounter problems with the code just delete it from your init file and re-start emacs again. Alternatively you could also just run the following form:

(advice-remove 'org-agenda-get-timestamps #'my-org-agenda-get-timestamps)

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.