Tagging in Org – plus bonus code for timeclocks and tags!
| emacs, orgThe section on projects introduced tags as a way to differentiate
active and inactive projects. In this section, you’ll learn more about
tags and how you can use them to filter your task list.
What’s a tag, anyway? In Org, tags are keywords at the end of
headlines. Each tag can contain letters, numbers, and the symbols ‘_’
and ‘@’. Tags begin and end with colons, and a single colon separates
multiple tags. For example, you could have headlines like this:
* Personal :PERSONAL: ** TODO Buy milk :@ERRANDS: ** TODO Call Mom :@PHONE: ** TODO Send letters :@ERRANDS: * Work :WORK: ** TODO Call John about report :@PHONE:JOHN: ** TODO Prepare for presentation on Monday ** TODO Call Mary about the presentation :@PHONE:URGENT:MARY:
One way to use tags is to filter your task list by priority. For
example, you may want to focus on your urgent tasks first without
getting distracted by other items on your task list. Another way to
use tags is to keep track of the context of your tasks as suggested in
GTD. By doing similar tasks together, you might be able to work more
efficiently. For example, if you’re on the phone at the office, it may
be a good idea to do all of your work-related phone calls. If you’re
going to go to the post office, you might want to drop by the
supermarket on your way back. You can use tags to categorize your
headlines any way you want.
Tags can take advantage of the outline structure. For example,
although the tasks “Buy milk”, “Call Mom”, and “Send letters” have one
tag each, they also inherit the “PERSONAL” tag from the parent
headline. A tag search for “PERSONAL” would display all three
tasks. To customize this behavior, look at the documentation for the
variables org-use-tag-inheritance and org-tags-match-list-sublevels.
Tags can help you organize and filter your task list. In this section,
you’ll learn how to add tags to your headlines, view tagged items in
your Org file and in your agenda, and define custom agenda
views. You’ll also learn about custom tag searches and other
interesting things you can do once you’ve tagged your headlines.
Adding tags
You can edit your ~/organizer.org file and add tags manually by typing
in :tagname: at the end of the headline. You can also add tags by
typing C-c C-c (org-ctrl-c-ctrl-c) when the point is on a
headline. Use M-TAB (complete-symbol) to complete a tag based on all
the tags used in the current file. If Alt-TAB is not processed by
Emacs, you can use ESC-TAB instead.
Separate multiple tags with a single colon, like this:
(:@PHONE:URGENT:). The beginning and ending colons are optional when
using C-c C-c (org-ctrl-c-ctrl-c), because the function will
automatically add them.
If you add certain tags frequently, you can set up single-key
shortcuts. For example, if you frequently tag tasks as “URGENT”, you
may want to define a shortcut (at least until your life gets under
control). You can assign shortcuts globally by adding this code to
your ~/.emacs and evaluating it:
(setq org-tag-alist '(("URGENT" . ?u) ("@PHONE" . ?p) ("@ERRANDS" . ?e)))
You can also set this on a per-file basis by adding the following line
to the beginning of your file:
#+TAGS: URGENT(u) @PHONE(p) @ERRANDS(e)
You can then use these C-c C-c (org-ctrl-c-ctrl-c) to enter these
single-key shortcuts, ending it with RET. If you are assigning a
single tag, type C-c C-c C-c (org-ctrl-c-ctrl-c, next change exits) to
make it even faster by skipping the RET.
If you use single-key shortcuts, you’ll need another way to enter tags
that start with the shortcut key. You can type them in manually, or
you can use C-c C-c (org-ctrl-c-ctrl-c) and type TAB to enter in any tag.
To remove a tag, you could use C-c C-c (org-ctrl-c-ctrl-c) again, or
delete it manually. To remove all tags, use C-c C-c
(org-ctrl-c-ctrl-c) and press SPC.
Viewing tagged items
Whether you want to view tagged headlines by themselves or in the
context of your other headlines, tasks, and notes, Org has some nifty
tagging features for you.
Agenda view
To view tagged headlines by themselves, use C-c a m (org-agenda,
org-tags-view) and specify the search tag. For example, you can view
your urgent tasks by specifying “URGENT”. Note that this command
displays the top headlines matching that tag, whether they’re tasks or
not. For example, if you searched for “WORK”, you would just get the
“* Work” headline. To view tagged tasks, use C-c a M (org-agenda,
org-tags-view with a prefix argument). This shows only the tasks that
have that tag.
To search for a combination of tags, you can combine tags like this:
WORK&@PHONE only your work phone calls PERSONAL-@ERRANDS personal tasks, but without errands JOHN|MARY Anything tagged with "JOHN" or "MARY" For example, if you're going to have a meeting with both of them
If you check certain lists often, you might want to create a custom
agenda command for them. In the section on Projects, you configured
custom agenda commands for active and inactive projects by adding the
following code in your ~/.emacs:
(setq org-agenda-custom-commands '(("p" tags "PROJECT-MAYBE-DONE" nil) ("m" tags "PROJECT&MAYBE" nil) ("a" "My agenda" ((org-agenda-list) (tags "PROJECT-MAYBE-DONE"))) ;; ... put your other custom commands here ))
You can use the same idea to create quick custom views for your other
tagged tasks. For example, to create custom views for your urgent work
tasks and your phone calls, modify the org-agenda-custom-commands
setting in your ~/.emacs to be like this:
(setq org-agenda-custom-commands '(("u" todo "WORK&URGENT" nil) ;; (1) ("c" todo "WORK&@PHONE" nil) ;; (2) ("h" todo "PERSONAL-@ERRANDS" nil) ;; (3) ("p" tags "PROJECT-MAYBE-DONE" nil) ;; (4) ("m" tags "PROJECT&MAYBE" nil) ("a" "My agenda" ((org-agenda-list) (tags-todo "URGENT") ;; (5) (tags "PROJECT-MAYBE-DONE"))) ;; (6) ;; ... put your other custom commands here ))
- (1) “u” is for “urgent”, “todo” specifies that TODO headlines are to be shown, “WORK&URGENT” is the query string, and the last item means that there aren’t any options
- (2) “c” is for “call”
- (3) “h” is for “home”
- (4) The second item here is “tags” instead of “todo”, which means that the highest-level matching headlines should be shown whether or not they’re tasks.
- (5) This is how to add a tag search for tasks into a custom agenda command.
- (6) This is how to add a tag search for headlines into a custom agenda command.
Sometimes you’ll want to see more context instead of just a list of
headlines. You can jump from your Org agenda to the corresponding
headline by pressing RET (org-agenda-switch-to) on the entry. You can
also quickly browse through the headlines in another window by
pressing f (org-agenda-follow-mode) while in the Org agenda view, then
moving your point to the different lines. These commands work with the
summary in the Org agenda view.
If you want to show only matching headlines in your ~/organizer.org
file, you can use Org’s sparse tree search commands.
In your agenda file
A sparse tree shows only the matching headlines in the context of the
headlines above them. This is useful when you want to see your tasks
within your outline structure. All other headlines are collapsed so
that they’re easy to skip. To do a sparse tree search, type C-c \
(org-tags-sparse-tree). You can then expand and collapse subtrees with
the TAB (org-cycle) command. To limit the search to only task
headlines, type C-u C-c \ (org-tags-sparse-tree with a prefix).
Other cool things you can do with tags
And if you ever want to know how much time you spent on urgent tasks,
you can call the following function from your organizer.org file with:
M-x wicked/org-calculate-tag-time RET URGENT RET
to see something like this:
Time: 98:44 (98 hours and 44 minutes)
You can call it with a prefix in order to be prompted for a start time
(inclusive) and end time (exclusive).
Here’s the code to add to your ~/.emacs:
(defun wicked/org-calculate-tag-time (matcher &optional ts te) "Return the total minutes clocked in headlines matching MATCHER. MATCHER is a string or a Lisp form to be evaluated, testing if a given set of tags qualifies a headline for inclusion. TS and TE are time start (inclusive) and time end (exclusive). Call with a prefix to be prompted for TS and TE. For example, to see how much time you spent on tasks tagged as URGENT, call M-x wicked/org-calculate-tag-time RET URGENT RET. To see how much time you spent on tasks tagged as URGENT today, call C-u M-x wicked/org-calculate-tag-time RET URGENT RET . RET +1 RET." (interactive (list (read-string "Tag query: ") (if current-prefix-arg (org-read-date)) (if current-prefix-arg (org-read-date)))) ;; Convert strings to proper arguments (if (stringp matcher) (setq matcher (cdr (org-make-tags-matcher matcher)))) (if (stringp ts) (setq ts (time-to-seconds (apply 'encode-time (org-parse-time-string ts))))) (if (stringp te) (setq te (time-to-seconds (apply 'encode-time (org-parse-time-string te))))) (let* ((re (concat "[\n\r]" outline-regexp " *\\(\\<\\(" (mapconcat 'regexp-quote org-todo-keywords-1 "\\|") (org-re "\\>\\)\\)? *\\(.*?\\)\\(:[[:alnum:]_@:]+:\\)?[ \t]*$"))) (case-fold-search nil) lspos tags tags-list tags-alist (llast 0) rtn level category i txt p marker entry priority (total 0)) (save-excursion (org-clock-sum ts te) (goto-char (point-min)) (while (re-search-forward re nil t) (catch :skip (setq tags (if (match-end 4) (match-string 4))) (goto-char (setq lspos (1+ (match-beginning 0)))) (setq level (org-reduced-level (funcall outline-level)) category (org-get-category)) (setq i llast llast level) ;; remove tag lists from same and sublevels (while (>= i level) (when (setq entry (assoc i tags-alist)) (setq tags-alist (delete entry tags-alist))) (setq i (1- i))) ;; add the nex tags (when tags (setq tags (mapcar 'downcase (org-split-string tags ":")) tags-alist (cons (cons level tags) tags-alist))) ;; compile tags for current headline (setq tags-list (if org-use-tag-inheritance (apply 'append (mapcar 'cdr tags-alist)) tags)) (when (and (eval matcher) (or (not org-agenda-skip-archived-trees) (not (member org-archive-tag tags-list)))) ;; Get the time for the headline at point (goto-char (line-beginning-position)) (setq total (+ total (or (get-text-property (1+ (point)) :org-clock-minutes) 0))) ;; if we are to skip sublevels, jump to end of subtree (org-end-of-subtree t))))) (if (interactive-p) (let* ((h (/ total 60)) (m (- total (* 60 h)))) (message "Time: %d:%02d (%d hours and %d minutes)" h m h m))) total))
Now you can slice and dice your timeclock records any way you want, thanks to tags!
Random Emacs symbol: cc-imenu-java-generic-expression – Variable: Imenu generic expression for Java mode. See `imenu-generic-expression’.
14 comments
Raymond Zeitler
2010-06-22T22:10:49ZHi! Guess who just started to learn org-mode? :)
Someone suggested that I could implement a platform independent password manager using org-mode (with org-crypt). It's not quite working yet, but I'm also having fun with many other features!
Org is Amazing! It's daunting, but luckily there are great tutorials, and the Customization is well-done.
Sacha Chua
2010-06-22T22:15:42ZAha! Welcome to the Org side, old friend. <laugh> John Wiegley's on Org, too. It's all good.
That does sound promising!
Joc
2013-07-19T17:45:49ZHi!, have you write something about the organizer.org file?, I'm a newbie and I am having difficulties understanding that
sachac
2013-07-19T18:30:52ZMy organizer.org file is this really big text file with TODOs, notes (in a date tree, using org-capture) and projects... You can organize it however you want to. =) Could you tell me more about what you would like to do? orgmode.org/worg/org-tutori... has a number of great tutorials.
Jiajian
2016-01-08T04:48:44ZWhat is the meaning of tag name that start with an '@' ?
sachac
2016-01-08T19:30:51ZNothing special, it's just a convention I picked up from other people's implementations of Getting Things Done. =)
Jiajian
2016-01-09T04:54:31ZThat confused me since the first time I read from the org-mode manual...
Ag ibragimov
2017-10-13T21:13:31ZThat is still unclear. What is a semantic difference between `:foo:` and `:@foo`? If there's none, why use @ at all?
upd: Oh, I've got it. This convention is to use tags as "GTD contexts". This article I think describes what they for:
https://simplicitybliss.com...
sriavr
2016-09-02T14:36:00ZThanks for the nice article. I have too many tags, ASCII characters get assigned as shortcut keys. How to work around this?
sachac
2016-09-03T05:45:47ZYou can manually specify the fast shortcut keys for your most common tags, and then use Helm or Ido as a completion interface for everything else by pressing TAB at the tag entry screen. Would something like that help?
Emmanuel Goldstein
2020-06-01T02:37:17ZDear Sacha, I don't know where to ask you this:
I have a piece of code to archive all DONE items. The line where it specifies that it is the DONE items is this:
(setq org-map-continue-from (outline-previous-heading)))
"/DONE" 'file))
How could I add also "CANCELLED" and "DELAYED" statuses there too? I wouldn't know the syntax. Would it be just adding them beside DONE like this?
(setq org-map-continue-from (outline-previous-heading)))
"/DONE" "/CANCELLED" "/DELAYED" 'file))
sachac
2020-06-02T03:39:08ZHello, Emmanuel! Here's the code I use in my Emacs config (https://sach.ac/dotemacs):
"|" means or, so you can extend it to be "TODO=\"DONE\"|TODO=\"CANCELLED\"|TODO=\"DELAYED\"" . Incidentally, if you want to learn more about the match syntax, you can check out the Org Mode manual section named "Matching tags and properties".
Would it be easier to post Org questions to either the Org Mode mailing list or to https://reddit.com/r/orgmode ? Then you don't have to look for related posts of mine, and you might get quicker answers from a wider range of people. =)
Emmanuel Goldstein
2020-06-02T14:26:23ZThanks a lot, and apologies for abusing :) Won't happen ever again.
The only thin I did not understand is
(or scope (if (org-before-first-heading-p) 'file 'tree))))
sachac
2020-06-02T14:45:24ZIt's cool, I'm honoured to be a starting point. I just don't want you to be constrained by my availability or limited experience. :)
The scope part is so that it will do all the done tasks if it's at the beginning of the file, or just the ones in the current subtree if you're in an outline.