Skip to content

Latest commit

 

History

History
491 lines (396 loc) · 19.3 KB

examples.org

File metadata and controls

491 lines (396 loc) · 19.3 KB

Examples

There are a lot of possibilities, so here are some examples to spark your imagination. Please do share your own examples by posting them on the issue tracker, and I will add them here. It will be very helpful to others to see your creativity!

Note: You can test any of these examples by evaluating the whole let form in Emacs (or, if you open this file in Emacs, by executing the code block with C-c C-c).

Contents

Feature examples

Apply faces and transformations

The :face and :transformer keywords can be used to apply faces to items in groups, or transform their strings before display. For example:

(let ((org-agenda-span 'day)
      (org-super-agenda-groups
       '((:name "Time grid items in all-uppercase with RosyBrown1 foreground"
                :time-grid t
                :transformer (--> it
                                  (upcase it)
                                  (propertize it 'face '(:foreground "RosyBrown1"))))
         (:name "Priority >= C items underlined, on black background"
                :face (:background "black" :underline t)
                :not (:priority>= "C")
                :order 100))))
  (org-agenda nil "a"))

images/screenshots/faces-and-transformations.png

Of course, this is a contrived example, but you get the idea.

Automatically by group

By setting the Org property agenda-group and using the :auto-group selector, you can automatically sort agenda items into groups. By default, this property is inherited, so you can set it for an entire subtree of items at once. For example, if you had this Org file:

* Tasks
** TODO Take over the universe
   DEADLINE: <2017-08-01 Tue>
:PROPERTIES:
:agenda-group: grandiose plans
:END:
*** TODO Take over the world
    DEADLINE: <2017-07-29 Sat>
*** TODO Take over the moon
    DEADLINE: <2017-07-30 Sun>
*** TODO Take over Mars
    DEADLINE: <2017-07-31 Mon>
** Recurring
:PROPERTIES:
:agenda-group: recurring
:END:

*** TODO Pay Internet bill
    DEADLINE: <2017-07-28 Fri>

You could use an agenda command like this:

(let ((org-super-agenda-groups
       '((:auto-group t))))
  (org-agenda-list))

And you’d get an agenda looking like this:

images/screenshots/auto-group.png

The property name can be customized. This becomes handy if you already have, for instance, an Org property named ProjectId attached to your items. Instead of duplicating this Org property and renaming it to agenda-group, you can set org-super-agenda-group-property-name to an appropriate value:

(let ((org-super-agenda-group-property-name "ProjectId")
      (org-super-agenda-groups
       '((:auto-group t))))
  (org-agenda-list))

This causes the :auto-group selector to sort your agenda items into groups that reflect your ProjectIds.

Note: This selector might become obsolete in the future. A more flexible way to group by properties is the :auto-property selector.

Automatically by category

In the same way, items can automatically be grouped by their category (which is usually the filename of the buffer they’re in).

(let ((org-super-agenda-groups
       '((:auto-category t))))
  (org-agenda-list))

Automatically by mapping a function

This example groups items by the name of the directory their file is in:

(let ((org-super-agenda-groups
       '((:auto-map (lambda (item)
                      (-when-let* ((marker (or (get-text-property 0 'org-marker item)
                                               (get-text-property 0 'org-hd-marker item)))
                                   (file-path (->> marker marker-buffer buffer-file-name))
                                   (directory-name (->> file-path file-name-directory directory-file-name file-name-nondirectory)))
                        (concat "Directory: " directory-name)))))))
  (org-agenda-list))

Conveniently, a function is already defined which does that, so you can simply pass the function name (note that, since the list is already quoted, the symbol is not quoted again, nor is #' used):

(let ((org-super-agenda-groups
       '((:auto-map org-super-agenda--dir-name))))
  (org-agenda-list))

This example could also be written by using the :file-path selector, which would return the whole path.

Automatically by property

This example groups items by the value of their ProjectId property (a more flexible way to group by property than this example):

(let ((org-super-agenda-groups
       '((:auto-property "ProjectId"))))
  (org-agenda-list))

By predicate

You can also use one or more arbitrary predicate functions, including lambdas. Note that, since the group list is already quoted, function name symbols are not quoted again, nor is #' used.

(defun emacs-p (item)
  (s-matches? "emacs" item))

(let ((org-super-agenda-groups
       '((:pred emacs-p))))
  (org-agenda-list))

(let ((org-super-agenda-groups
       '((:pred
          ;; A list of two functions
          (emacs-p (lambda (item)
                     (s-matches? "Lisp" item)))))))
  (org-agenda-list))

Of course, this example would be better written using the :regexp selector, but you get the idea (better examples would be appreciated).

Forward-looking

Here’s an example of a date-oriented, forward-looking agenda grouping.

(let ((org-super-agenda-groups
       '((:log t)  ; Automatically named "Log"
         (:name "Schedule"
                :time-grid t)
         (:name "Today"
                :scheduled today)
         (:habit t)
         (:name "Due today"
                :deadline today)
         (:name "Overdue"
                :deadline past)
         (:name "Due soon"
                :deadline future)
         (:name "Unimportant"
                :todo ("SOMEDAY" "MAYBE" "CHECK" "TO-READ" "TO-WATCH")
                :order 100)
         (:name "Waiting..."
                :todo "WAITING"
                :order 98)
         (:name "Scheduled earlier"
                :scheduled past))))
  (org-agenda-list))

Log mode

When the agenda log mode is activated, these groups separate out tasks that you worked on or completed today. The :order-multi sets the :order for each subgroup to 1, which makes it display below any groups without a defined :order (although there are no other groups in this example).

(let ((org-super-agenda-groups
       '((:order-multi (1 (:name "Done today"
                                 :and (:regexp "State \"DONE\""
                                               :log t))
                          (:name "Clocked today"
                                 :log t))))))
  (org-agenda-list))

If you’d prefer them at the top of the agenda, you could use this:

(let ((org-super-agenda-groups
       '((:name "Done today"
                :and (:regexp "State \"DONE\""
                              :log t))
         (:name "Clocked today"
                :log t))))
  (org-agenda-list))

Concrete dates

Let’s say it’s approaching the start of a new school year, and you want to see all tasks with a deadline before school starts. You might use something like this:

(let ((org-super-agenda-groups
       '((:deadline (before "2017-09-01"))
         (:discard (:anything t)))))
  (org-todo-list))

Of course, you could also write that as a standard agenda command with the advanced searching syntax, and it would execute faster.

What if you wanted to group tasks that are due before the end of the current month? You could use something like this:

(-let* (((sec minute hour day month year dow dst utcoff) (decode-time))
        (last-day-of-month (calendar-last-day-of-month month year))
        (target-date
         ;; A hack that seems to work fine.  Yay, Postel!
         (format "%d-%02d-%02d" year month (1+ last-day-of-month)))
        (org-super-agenda-groups
         `((:deadline (before ,target-date))
           (:discard (:anything t)))))
  (org-todo-list))

Projects

With the :children selector you can select items that have children. Assuming items without children aren’t considered projects, you can view projects like this:

(let ((org-super-agenda-groups
       '((:name "Projects"
                :children t)
         (:discard (:anything t)))))
  (org-todo-list))

You might want to put that at the end of a daily/weekly agenda view using a custom command that runs a series of agenda commands, like this:

(let ((org-agenda-custom-commands
       '(("u" "Super view"
          ((agenda "" ((org-super-agenda-groups
                        '((:name "Today"
                                 :time-grid t)))))
           (todo "" ((org-agenda-overriding-header "Projects")
                     (org-super-agenda-groups
                      '((:name none  ; Disable super group header
                               :children todo)
                        (:discard (:anything t)))))))))))
  (org-agenda nil "u"))

Note that the :children matcher may be quite slow in views like org-todo-list (i.e. the todo agenda command in the list above), especially if used to match to-do items. It would be faster to use org-agenda-skip-function. In a daily/weekly agenda it should perform well enough.

Books to-read

This shows TO-READ to-do items with the tags :book: or :books:.

(let ((org-super-agenda-groups
       '((:discard (:not  ; Is it easier to read like this?
                    (:and
                     (:todo "TO-READ" :tag ("book" "books"))))))))
  (org-todo-list))

Remember that items that are not matched by a group selector fall through to the next selector or to the catch-all group. So you might think that this simpler command would work:

(let ((org-super-agenda-groups
       '((:and (:todo "TO-READ" :tag ("book" "books"))))))
  (org-todo-list))

But while it would indeed group together those items, it would also display all other to-do items in the Other items section below, so you must :discard the items you don’t want. So another way to write this query would be to select the items you want and discard everything else:

(let ((org-super-agenda-groups
       '((:name "Books to read"
                :and (:todo "TO-READ" :tag ("book" "books")))
         (:discard (:anything t)))))
  (org-todo-list))

Note that you could run part of this query with a standard agenda command, and it would be faster. But since the org-tags-view and org-todo-list can only select by tags or todo-keywords, respectively, the other part of the selection must be done with grouping. Here are two examples (note that they each produce the same results):

(let ((org-super-agenda-groups
       '((:discard (:not (:todo "TO-READ"))))))
  (org-tags-view nil "books|book"))

;; These commands produce the same results

(let ((org-super-agenda-groups
       '((:discard (:not (:tag ("book" "books")))))))
  (org-todo-list "TO-READ"))

Of course, the most canonical (and probably fastest) way to write this query is to use org-search-view, like this:

(org-search-view t "+{:book\\|books:} +TO-READ")

Or if you’re inputting the string manually after pressing C-c a S, you’d input +{:book\|books:} +TO-READ. But if you’re like me, and you forget the advanced searching syntax, you might find these more “lispy” grouping/selecting constructs easier to use, even if they can be slower on large datasets.

And note that even if you use the built-in searching with org-search-view, you might still want to use this package to group results, perhaps like this:

(let ((org-super-agenda-groups
       '((:name "Computer books"
                :tag ("computer" "computers" "programming" "software"))
         ;; All other books would be displayed here
         )))
  (org-search-view t "+{:book\\|books:} +TO-READ"))

Emacs and Org-mode to-do items

This shows all to-do items with the :Emacs: tag, and groups together anything related to Org. You can see the use of the rx macro by backquoting the list and unquoting the rx form.

(let ((org-super-agenda-groups
       `((:name "Org-related"
                :tag "Org"
                :regexp ("org-mode"
                         ,(rx bow "org" eow))))))
  (org-tags-view t "Emacs"))

Automatically fold certain groups with Origami

The origami package works “out-of-the-box” with org-super-agenda. Just activate origami-mode in the agenda buffer and use the command origami-toggle-node to fold groups. You can bind, e.g. TAB to that command in the header map, and then you can easily collapse groups as if they were an outline.

You could even fold certain groups by default, perhaps like this (this use-package form should probably go inside a (use-package org-super-agenda ...) form’s :config section):

(use-package origami
  :general (:keymaps 'org-super-agenda-header-map
                     "TAB" #'origami-toggle-node)
  :config

  (defvar ap/org-super-agenda-auto-show-groups
    '("Schedule" "Bills" "Priority A items" "Priority B items"))

  (defun ap/org-super-agenda-origami-fold-default ()
    "Fold certain groups by default in Org Super Agenda buffer."
    (forward-line 3)
    (cl-loop do (origami-forward-toggle-node (current-buffer) (point))
             while (origami-forward-fold-same-level (current-buffer) (point)))
    (--each ap/org-super-agenda-auto-show-groups
      (goto-char (point-min))
      (when (re-search-forward (rx-to-string `(seq bol " " ,it)) nil t)
        (origami-show-node (current-buffer) (point)))))

  :hook ((org-agenda-mode . origami-mode)
         (org-agenda-finalize . ap/org-super-agenda-origami-fold-default)))

Contributed examples

images/screenshots/bascht.png

(setq org-super-agenda-groups
      '((:name "Next Items"
               :time-grid t
               :tag ("NEXT" "outbox"))
        (:name "Important"
               :priority "A")
        (:name "Quick Picks"
               :effort< "0:30")
        (:priority<= "B"
                     :scheduled future
                     :order 1)))

images/screenshots/zaen323.png

(setq spacemacs-theme-org-agenda-height nil
      org-agenda-time-grid '((daily today require-timed) "----------------------" nil)
      org-agenda-skip-scheduled-if-done t
      org-agenda-skip-deadline-if-done t
      org-agenda-include-deadlines t
      org-agenda-include-diary t
      org-agenda-block-separator nil
      org-agenda-compact-blocks t
      org-agenda-start-with-log-mode t)

(setq org-agenda-custom-commands
      '(("z" "Super zaen view"
         ((agenda "" ((org-agenda-span 'day)
                      (org-super-agenda-groups
                       '((:name "Today"
                                :time-grid t
                                :date today
                                :todo "TODAY"
                                :scheduled today
                                :order 1)))))
          (alltodo "" ((org-agenda-overriding-header "")
                       (org-super-agenda-groups
                        '((:name "Next to do"
                                 :todo "NEXT"
                                 :order 1)
                          (:name "Important"
                                 :tag "Important"
                                 :priority "A"
                                 :order 6)
                          (:name "Due Today"
                                 :deadline today
                                 :order 2)
                          (:name "Due Soon"
                                 :deadline future
                                 :order 8)
                          (:name "Overdue"
                                 :deadline past
                                 :order 7)
                          (:name "Assignments"
                                 :tag "Assignment"
                                 :order 10)
                          (:name "Issues"
                                 :tag "Issue"
                                 :order 12)
                          (:name "Projects"
                                 :tag "Project"
                                 :order 14)
                          (:name "Emacs"
                                 :tag "Emacs"
                                 :order 13)
                          (:name "Research"
                                 :tag "Research"
                                 :order 15)
                          (:name "To read"
                                 :tag "Read"
                                 :order 30)
                          (:name "Waiting"
                                 :todo "WAITING"
                                 :order 20)
                          (:name "trivial"
                                 :priority<= "C"
                                 :tag ("Trivial" "Unimportant")
                                 :todo ("SOMEDAY" )
                                 :order 90)
                          (:discard (:tag ("Chore" "Routine" "Daily")))))))))))