23

I often have a list like this:

* Main heading
** TODO [#A] Make world better
** TODO [#B] Make Emacs better 
** TODO [#B] Customize emacs 
** DONE [#C] some task
** TODO [#A] Launch rocket to mars

I would like to sort it according to the 'TODO' taskword first. Then the items inside the sorted TODO I would like to sort by priority. (it would then be nice to further sort by "Effort").

And I mean currently I can click on the main heading and sort the children already by either priority or by todo keyword, but not both.

Is sorting by both possible like sort-strategy?


Currently I have two headings

* Tasks
** TODO [#A] meh
** TODO [#B] meh2
* Completed.
** DONE [#B] meh3.

But the problem with this approach is that I have to constantly shuffle tasks around when I complete them.

[EDIT]
This is kinda similar to this except that I couldn't make sense of his answer to transfer it to my needs?

  • The function org-sort-entries will either act on a main heading for all subheadings, or it can sort what is in a selected region. There are interactive options for you to choose from. You can programmatically use it also, and several sorts are possible -- I often use a, o, p, t (one after the next to accomplish 4 levels of sorting criteria). For example, you can sort everything first by alphabetic, then by todo keywords, then by priority, and then by time. – lawlist Feb 25 '15 at 22:14
  • Hello, I'm aware of the org-sort-entries option to sort child tasks. I have updated the question so as to better reflect that. Thank you for your comment. – Leo Ufimtsev Feb 25 '15 at 22:16
  • Here is a link to a detailed approach for sorting an org-mode buffer programmatically: stackoverflow.com/a/22232709/2112489 – lawlist Feb 25 '15 at 22:27
  • I have this link in my question already. The above is kinda tailored to someone's specific needs. Is there a more general purpose/easier approach? – Leo Ufimtsev Feb 25 '15 at 22:29
  • 1
    @LeoUfimtsev Try setting org-refile-targets to something like (setq org-refile-targets '((nil . (:maxlevel . 6)))). That will make org-mode show headings up to a depth of 6 when refiling. You can check the documentation for org-refile-targets for more information. – itsjeyd Feb 25 '15 at 23:16
17

It would be great if there was something like org-agenda-sorting-stratagy that worked with org-sort-entries, but there doesn't seem to be. We can fake it since org-sort-entries can take an argument specifying a function assigning a (string or number) key to each heading, which will be used to sort the entries when the ?f sorting type is given. All we have to do is get a string for the TODO and PRIORITY properties. The trick is that we want to sort the TODO property by its position in org-todo-keywords, not alphabetically.

(require 'cl)
(require 'dash)

(defun todo-to-int (todo)
    (first (-non-nil
            (mapcar (lambda (keywords)
                      (let ((todo-seq
                             (-map (lambda (x) (first (split-string  x "(")))
                                   (rest keywords)))) 
                        (cl-position-if (lambda (x) (string= x todo)) todo-seq)))
                    org-todo-keywords))))

(defun my/org-sort-key ()
  (let* ((todo-max (apply #'max (mapcar #'length org-todo-keywords)))
         (todo (org-entry-get (point) "TODO"))
         (todo-int (if todo (todo-to-int todo) todo-max))
         (priority (org-entry-get (point) "PRIORITY"))
         (priority-int (if priority (string-to-char priority) org-default-priority)))
    (format "%03d %03d" todo-int priority-int)
    ))

(defun my/org-sort-entries ()
  (interactive)
  (org-sort-entries nil ?f #'my/org-sort-key))

M-x my/org-sort-entries will sort by the TODO keyword and break ties with PRIORITY (using org-default-priority when no priority is given). This will break if you have more than 1000 TODO keywords, which is a good reason not to do that.

  • Omg, thank you for script. An issue: I installed dash. Then tried the script, but I'm getting an error: Symbol definition is void: todo-to-int. I'm gonna guess you have that function somewhere in your .emacs file but forgot include in the above? or maybe some typo? – Leo Ufimtsev Feb 26 '15 at 2:02
  • I changed the function that converts a keyword to an int to todo-to-int after I had pasted into my answer. It's fixed now. – erikstokes Feb 26 '15 at 2:06
  • 1
    Now all works. Dude, thank you for all your effort, very highly appreciated :-D. – Leo Ufimtsev Feb 26 '15 at 2:08
  • 1
    NB: It is no longer recommended to use cl according to docs. – cammil Jan 2 '17 at 11:09
1

Add the following to your file:

#+ARCHIVE: :: * Completed.

And shuffling becomes archiving

Rather than sort the entries, how about a sorted view?

(setq org-agenda-custom-commands
      '(("cx" "TODOs sorted by state, priority, effort"
         todo "*"
         ((org-agenda-overriding-header "\nTODOs sorted by state, priority, effort")
          (org-agenda-sorting-strategy '(todo-state-down priority-down effort-up))))))

Restrict it to the current file with <. You can mark DONE and archive from the sorted view.

1

You can also define a org-agenda-cmp-user-defined function and add it to org-agenda-sorting-strategy. This is the one I created as an example.

(setq org-todo-sort-order '("WAIT" "TODO" "DOING" "CANCELED" "DONE"))

(defun my:user-todo-sort (a b)
  "Sort todo based on which I want to see first"
  (when-let ((state-a (get-text-property 14 'todo-state a))
             (state-b (get-text-property 14 'todo-state b))
             (cmp (--map (cl-position-if (lambda (x)
                                           (equal x it))
                                         org-todo-sort-order)
                         (list state-a state-b))))
    (cond ((apply '> cmp) 1)
          ((apply '< cmp) -1)
          (t nil))))
(setq org-agenda-cmp-user-defined 'my:user-todo-sort)
1

You can use this library made by me: https://github.com/felipelalli/org-sort-tasks

It uses Merge Sort algo by asking the user if a task A is more important than B, and then builds a sorted list.

  • Can you add some description of what this does, and in particular how it differs from the other answers. – Andrew Swann May 10 at 6:01
  • It uses Merge Sort algo by asking the user if a task A is more important than B, and then build a sorted list. – Felipe May 10 at 23:27

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.