在组织模式下对标题的混合列表进行排序

时间:2014-03-06 17:16:50

标签: emacs org-mode

我在org-mode中有很多标题:

* Tasks [/]
** TODO Foo
** TODO Bar
** DONE World
** DONE Abba

我想按如下方式排序:

* Tasks [/]
** TODO Bar
** TODO Foo
** DONE Abba
** DONE World

使用org-sort-entries我可以获得

* Tasks [/]
** DONE Abba
** TODO Bar
** TODO Foo
** DONE World

(即字母顺序),或

* Tasks [/]
** TODO Foo
** TODO Bar
** DONE World
** DONE Abba

(即根据状况分组)。

换句话说,我想按字母顺序对TODODONE项进行排序,但要将它们分成两个块。我怎么能实现它?我想将整个标题保留在同一个子树中!

编辑:

我没有设法利用以下建议。因此,我尝试使用下面提供的提示来提出我需要的解决方案。这是我的代码:

(defun drorata-sort-TODO-DONE-headings ()
  (interactive)
  (save-excursion
    ;; Sort according to the TODO/DONE keywords
    (org-sort-entries t ?o)
    ;; Now there is a block of TODO's and a block of DONE's
    ;; Mark the TODO's
    (next-line)
    (beginning-of-line)
    (set-mark-command nil)
    (search-forward-regexp "[*].* DONE" nil t)
    (beginning-of-line)
    ;; Sort the marked region (of TODO's) alphabetically
    (org-sort-entries t ?a)
    ;; Now its time to sort the DONE's
    (search-forward "[*].* DONE" nil t)
    (beginning-of-line)
    (set-mark-command nil)
    ;; How can I find all headings labeled with DONE in the current level?
    )
)

我的想法是标记由TODO标记的标题,并按字母顺序对其进行排序,然后对DONE标题执行相同的操作。到目前为止,我认为它仅适用于TODO ...

4 个答案:

答案 0 :(得分:12)

简短的回答

  • 第1步:将光标放在父母身上。

  • 第2步M-x org-sort-entries RET a RET

  • 第3步M-x org-sort-entries RET o RET

  • 第4步:打开你最喜欢的饮料,喝一杯。


长篇大论

为了扩展@pmr的答案(即,对所选区域进行排序),还可以考虑对主标题进行操作以组织子标题。例如,我喜欢执行多重排序 - 首先按字母顺序排列,然后按顺序排序,按第三顺序排列,按优先顺序排在第三位,按时间排在第四位。对于不包含截止日期且仅包含一种待办事项状态的副标题,我的需求仅按字母排序就足够了。下面给出的是一个示例函数,用于对包含各种主标题和子标题的整个缓冲区进行排序。以下是org-sort-entries的备忘单:

Sort: [a]lpha  [n]umeric  [p]riority  p[r]operty  todo[o]rder  [f]unc
               [t]ime [s]cheduled  [d]eadline  [c]reated
               A/N/P/R/O/F/T/S/D/C means reversed.

注意org-sort-entries在根据时间戳排序条目时使用current-time(如果条目不包含时间戳)。使用current-time的结果是,在使用选项tcs或{进行排序时,将在包含时间戳的未来任务之前对未注明日期的条目进行排序{1}}。要对未注明日期的条目进行加权,以便在日期条目之后对它们进行排序,可以使用比d更晚的日期。相关的 let-bound 变量定义为current-time,其在函数中的用法写为(now (current-time))。这可以通过许多不同的方式来处理 - 例如,修改包含(org-float-time now)的代码,其中包含远在未来的人工日期 - 例如(org-float-time now)

  
(org-time-string-to-seconds "<2030-12-31 Tue>")

以下是如何对包含主标题和子标题的整个缓冲区进行排序和重组的示例。如果用户希望使用(defun lawlist-sort () (when (save-excursion (goto-char (point-max)) (re-search-backward "^\\* CONTACTS" nil t) (re-search-forward "^\\*\\* \\(Planning\\)" nil t)) (goto-char (point-max)) (re-search-backward "^\\* CONTACTS" nil t) (org-sort-entries t ?a) ) (when (save-excursion (goto-char (point-max)) (re-search-backward "^\\* DONE" nil t) (re-search-forward "^\\*\\* \\(None\\)" nil t)) (goto-char (point-max)) (re-search-backward "^\\* DONE" nil t) (org-sort-entries t ?a) ) (when (save-excursion (goto-char (point-max)) (re-search-backward "^\\* UNDATED" nil t) (re-search-forward "^\\*\\* \\(Someday\\)" nil t)) (goto-char (point-max)) (re-search-backward "^\\* UNDATED" nil t) (org-sort-entries t ?a) ) (when (save-excursion (goto-char (point-max)) (re-search-backward "^\\* EVENTS" nil t) (re-search-forward "^\\*\\* \\(Reference\\|Delegated\\|Postponed\\|Waiting\\)" nil t)) (goto-char (point-max)) (re-search-backward "^\\* EVENTS" nil t) (org-sort-entries t ?a) (org-sort-entries t ?o) (org-sort-entries t ?p) (org-sort-entries t ?t) ) (when (save-excursion (goto-char (point-max)) (re-search-backward "^\\* TASKS" nil t) (re-search-forward "^\\*\\* \\(Active\\|Next Action\\|Hold\\|Canceled\\)" nil t)) (goto-char (point-max)) (re-search-backward "^\\* TASKS" nil t) (org-sort-entries t ?a) (org-sort-entries t ?o) (org-sort-entries t ?p) (org-sort-entries t ?t) ) ) 库与Toodledo服务器同步,这将特别有用:https://github.com/christopherjwhite/org-toodledo为了在重新组织包含数百个子标题的缓冲区时加快进程,用户可能希望考虑禁止消息通过修改负责的功能 - 但是,这超出了这个答案的范围。

  
org-toodledo

这是一个样本清理函数,用于在条目之间放置适当的间距并删除缓冲区末尾的任何空行 - 正则表达式假定标题和子标题都是向左齐全的:

  
(setq org-todo-keywords '(
  (sequence
  "Active(a)"
  "Next Action(n)"
  "Canceled(c)"
  "Hold(h)"
  "Reference(r)"
  "Delegated(d)"
  "Waiting(w)"
  "Postponed(P)"
  "Someday(s)"
  "Planning(p)"
  "|"
  "None(N)") ))

(defun lawlist-reorganize ()
(interactive)
  (with-current-buffer (get-buffer "test.org")
    (setq buffer-read-only nil)
    (lawlist-refile-tasks)
    (lawlist-refile-events)
    (lawlist-refile-undated)
    (lawlist-refile-contacts)
    (lawlist-refile-done)
    (lawlist-sort)
    (goto-char (point-min))
    (save-buffer)
    (setq buffer-read-only t)))

(defun lawlist-refile-tasks ()
(interactive)
  (let* (
      (org-archive-location "/Users/HOME/Desktop/test.org::* TASKS")
      (org-archive-save-context-info nil))
    (goto-char (point-min))
    (unless (re-search-forward "^\\* TASKS" nil t)
      (goto-char (point-max))
      (insert "* TASKS\n\n"))
    (goto-char (point-max))
    (while
        (re-search-backward
          "^\\*\\* \\(Active\\|Next Action\\|Hold\\|Canceled\\)" nil t)
      (org-archive-subtree))))

(defun lawlist-refile-events ()
  (let* (
      (org-archive-location "/Users/HOME/Desktop/test.org::* EVENTS")
      (org-archive-save-context-info nil))
    (goto-char (point-min))
    (unless (re-search-forward "^\\* EVENTS" nil t)
      (goto-char (point-max))
      (insert "* EVENTS\n\n"))
    (goto-char (point-max))
    (while
        (re-search-backward
          "^\\*\\* \\(Reference\\|Delegated\\|Postponed\\|Waiting\\)" nil t)
      (org-archive-subtree))))

(defun lawlist-refile-undated ()
  (let* (
      (org-archive-location "/Users/HOME/Desktop/test.org::* UNDATED")
      (org-archive-save-context-info nil))
    (goto-char (point-min))
    (unless (re-search-forward "^\\* UNDATED" nil t)
      (goto-char (point-max))
      (insert "* UNDATED\n\n"))
    (goto-char (point-max))
    (while
        (re-search-backward
          "^\\*\\* \\(Someday\\)" nil t)
      (org-archive-subtree))))

(defun lawlist-refile-done ()
  (let* (
      (org-archive-location "/Users/HOME/Desktop/test.org::* DONE")
      (org-archive-save-context-info nil))
    (goto-char (point-min))
    (unless (re-search-forward "^\\* DONE" nil t)
      (goto-char (point-max))
      (insert "* DONE\n\n"))
    (goto-char (point-max))
    (while
        (re-search-backward
          "^\\*\\* \\(None\\)" nil t)
      (org-archive-subtree))))

(defun lawlist-refile-contacts ()
  (let* (
      (org-archive-location "/Users/HOME/Desktop/test.org::* CONTACTS")
      (org-archive-save-context-info nil))
    (goto-char (point-min))
    (unless (re-search-forward "^\\* CONTACTS" nil t)
      (goto-char (point-max))
      (insert "* CONTACTS\n\n"))
    (goto-char (point-max))
    (while
        (re-search-backward
          "^\\*\\* \\(Planning\\)" nil t)
      (org-archive-subtree))))

该解决方案不依赖于选择区域,而是依赖于每个主标题并组织该主标题下的所有内容 - 即,所有子标题都是有组织的。此答案中的代码将通过在正确的主标题下重新填充条目来重新组合条目。例如 - 如果任务已完成,则已完成的子标题为(defun lawlist-cleanup () (interactive) (let ((query-replace-lazy-highlight nil)) (replace-regexp "\n+\\*\\* " "\n\n** " nil (point-min) (point-max)) (replace-regexp "\n+\\* " "\n\n\n* " nil (point-min) (point-max)) (goto-char (point-max)) (delete-blank-lines) (let ((trailnewlines (abs (skip-chars-backward "\n\t")))) (if (> trailnewlines 0) (delete-char trailnewlines))) )) - 代码将查找** None的所有子标题,并将其移至** None的主标题,然后按字母顺序对它们进行排序。

主要标题是:* DONE; * TASKS; * EVENTS; * SOMEDAY; * CONTACTS

选择了以下小标题,因为它们是“完成任务”的方法,而Toodledo服务器使用相同的方法:* DONE; ** Active; ** Next Action; ** Hold; ** Canceled; ** Reference; ** Delegated; ** Postponed; ** Waiting; ** Someday; ** Planning

** None

答案 1 :(得分:1)

顶级互动功能org-sort将(在您的情况下)调用org-sort-entries,该outline-get-next-sibling作用于某个区域。您只需要确保您的区域不包含其他区块。

要以编程方式在一个TODO关键字块上扩展该区域,您可以将org-heading-components与{{1}}和一个活动区域合并。

答案 2 :(得分:0)

我尝试用普通的替换和排序功能来解决。我认为这没用。但这是一个可能的答案。

(字符“@”必须是唯一的字符串。)

  1. M-x fundamental-mode
  2. Mx replace-string RET Cq Cj RET {{ 1}}
  3. C-x C-x
  4. Mx @ RET replace-regexp RET Cq Cj < / kbd> @[*][ ] space RET
  5. C-x C-x
  6. M-&GT;
  7. M-x *
  8. C-x C-x
  9. Mx sort-lines RET replace-string RET Cq Cj < / KBD>
  10. 输入:

    @

    输出:

    * TODO Foo
    ** TODO1
    todo1
    
    * TODO Bar
    ** TODO2
    todo2
    
    * DONE World
    ** DONE1
    done1
    
    * DONE Abba
    ** DONE2
    done2
    

答案 3 :(得分:0)

基于lawlist的简短回答,这是一个互动功能,可按TODO关键字进行分组,并按字母顺序排序。这通过以下方式实现:

  1. 按字母顺序排序
  2. 然后按TODO关键字
  3. 排序

    请注意这是有效的,因为TODO - org-sort-entries中的排序会保留初始的字母排序。

    (defun apl-org-sort-entries-todo-alphabetical ()
      "Group Org-mode entries by TODO keyword and sort alphabetically.
    
    This function achieves this by first sorting alphabetically and
    then sorting by TODO keyword. This works because the TODO-sort in
    `org-sort-entries' preserves the initial alphabetical sort."
      (interactive)
      ;; First sort alphabetically
      (org-sort-entries t ?a)
      ;; Then sort by TODO keyword
      (org-sort-entries t ?o)
      ;; Rotate subtree to show children
      (org-cycle)               ; SUBTREE -> FOLDED
      (org-cycle)               ; FOLDED -> CHILDREN
      )