org-sort multi:日期/时间 (?d ?t) | 优先级 (?p) | 标题 (?a)

org-sort multi:日期/时间 (?d ?t) | 优先级 (?p) | 标题 (?a)

是否有人知道org-sort可以重新归档/组织一组 TODO 的功能/修改,以便它按照三个 (3) 标准对它们进行排序:第一按截止日期排序,第二按优先级排序,第三按任务标题排序?


编辑:我认为org-sortby deadline ( ?d) 有一个错误,无法正确处理未注明日期的任务。我正在研究一种解决方法(即在截止日期 ( ?d) 排序发生之前将未注明日期的待办事项移至不同的标题),但也许最好的办法是尝试修复原始排序功能。可以在以下线程中找到解决方法的开发(即一举将未注明日期的任务移至不同的标题): 如何自动化 org-refile 以处理多个待办事项


编辑:以下代码看起来很有希望,但需要一些 TLC 和针对未注明日期的待办事项错误的解决方法:

;; multiple sort
(defun org-sort-multi (&rest sort-types)
  "Multiple sorts on a certain level of an outline tree, or plain list items.

SORT-TYPES is a list where each entry is either a character or a
cons pair (BOOL . CHAR), where BOOL is whether or not to sort
case-sensitively, and CHAR is one of the characters defined in
`org-sort-entries-or-items'.  Entries are applied in back to
front order.

Example:  To sort first by TODO status, then by priority, then by
date, then alphabetically (case-sensitive) use the following
call:

  (org-sort-multi '(?d ?p ?t (t . ?a)))"

(interactive)
  (dolist (x (nreverse sort-types))
    (when (char-valid-p x)
      (setq x (cons nil x)))
    (condition-case nil
        (org-sort-entries (car x) (cdr x))
      (error nil))))


;; sort current level
(defun lawlist-sort (&rest sort-types)
  "Sort the current org level.

SORT-TYPES is a list where each entry is either a character or a
cons pair (BOOL . CHAR), where BOOL is whether or not to sort
case-sensitively, and CHAR is one of the characters defined in
`org-sort-entries-or-items'.  Entries are applied in back to
front order.

Defaults to \"?o ?p\" which is sorted by TODO status, then by
priority"
  (interactive)
  (when (equal mode-name "Org")
    (let ((sort-types (or sort-types
                          (if (or (org-entry-get nil "TODO")
                                  (org-entry-get nil "PRIORITY"))
                              '(?d ?t ?p) ;; date, time, priority
                            '((nil . ?a))))))
      (save-excursion
        (outline-up-heading 1)
        (let ((start (point))
              end)
          (while (and (not (bobp)) (not (eobp)) (<= (point) start))
            (condition-case nil
                (outline-forward-same-level 1)
              (error (outline-up-heading 1))))
          (unless (> (point) start)
            (goto-char (point-max)))
          (setq end (point))
          (goto-char start)
          (apply 'org-sort-multi sort-types)
          (goto-char end)
          (when (eobp)
            (forward-line -1))
          (when (looking-at "^\\s-*$")
          (kill-whole-line)
)
          (goto-char start)
;;          (dotimes (x ) (org-cycle))
          )))))

编辑:此功能也显示出前景,我将在完成更多测试后报告。

(defun org-sort-all ()
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward "^\* " nil t)
      (goto-char (match-beginning 0))
      (condition-case err
          (progn
            (org-sort-entries t ?a)
            (org-sort-entries t ?p)
            (org-sort-entries t ?o)
            (forward-line))
        (error nil)))
    (goto-char (point-min))
    (while (re-search-forward "\* PROJECT " nil t)
      (goto-char (line-beginning-position))
      (ignore-errors
        (org-sort-entries t ?a)
        (org-sort-entries t ?p)
        (org-sort-entries t ?o))
      (forward-line))))

编辑:对于那些有兴趣修复截止日期排序的冒险者来说(?d),以便将未注明日期的待办事项移至大纲的底部,而不是与注明日期的待办事项混在一起,这里是当前org.el包含在 Emacs Trunk 中的摘录(截至 2013 年 7 月 1 日):

(defun org-sort (with-case)
  "Call `org-sort-entries', `org-table-sort-lines' or `org-sort-list'.
Optional argument WITH-CASE means sort case-sensitively."
  (interactive "P")
  (cond
   ((org-at-table-p) (org-call-with-arg 'org-table-sort-lines with-case))
   ((org-at-item-p) (org-call-with-arg 'org-sort-list with-case))
   (t
    (org-call-with-arg 'org-sort-entries with-case))))

(defun org-sort-remove-invisible (s)
  (remove-text-properties 0 (length s) org-rm-props s)
  (while (string-match org-bracket-link-regexp s)
    (setq s (replace-match (if (match-end 2)
                   (match-string 3 s)
                 (match-string 1 s)) t t s)))
  s)

(defvar org-priority-regexp) ; defined later in the file

(defvar org-after-sorting-entries-or-items-hook nil
  "Hook that is run after a bunch of entries or items have been sorted.
When children are sorted, the cursor is in the parent line when this
hook gets called.  When a region or a plain list is sorted, the cursor
will be in the first entry of the sorted region/list.")

(defun org-sort-entries
  (&optional with-case sorting-type getkey-func compare-func property)
  "Sort entries on a certain level of an outline tree.
If there is an active region, the entries in the region are sorted.
Else, if the cursor is before the first entry, sort the top-level items.
Else, the children of the entry at point are sorted.

Sorting can be alphabetically, numerically, by date/time as given by
a time stamp, by a property or by priority.

The command prompts for the sorting type unless it has been given to the
function through the SORTING-TYPE argument, which needs to be a character,
\(?n ?N ?a ?A ?t ?T ?s ?S ?d ?D ?p ?P ?o ?O ?r ?R ?f ?F).  Here is the
precise meaning of each character:

n   Numerically, by converting the beginning of the entry/item to a number.
a   Alphabetically, ignoring the TODO keyword and the priority, if any.
o   By order of TODO keywords.
t   By date/time, either the first active time stamp in the entry, or, if
    none exist, by the first inactive one.
s   By the scheduled date/time.
d   By deadline date/time.
c   By creation time, which is assumed to be the first inactive time stamp
    at the beginning of a line.
p   By priority according to the cookie.
r   By the value of a property.

Capital letters will reverse the sort order.

If the SORTING-TYPE is ?f or ?F, then GETKEY-FUNC specifies a function to be
called with point at the beginning of the record.  It must return either
a string or a number that should serve as the sorting key for that record.

Comparing entries ignores case by default.  However, with an optional argument
WITH-CASE, the sorting considers case as well."
  (interactive "P")
  (let ((case-func (if with-case 'identity 'downcase))
    (cmstr
     ;; The clock marker is lost when using `sort-subr', let's
     ;; store the clocking string.
     (when (equal (marker-buffer org-clock-marker) (current-buffer))
       (save-excursion
         (goto-char org-clock-marker)
         (looking-back "^.*") (match-string-no-properties 0))))
        start beg end stars re re2
        txt what tmp)
    ;; Find beginning and end of region to sort
    (cond
     ((org-region-active-p)
      ;; we will sort the region
      (setq end (region-end)
            what "region")
      (goto-char (region-beginning))
      (if (not (org-at-heading-p)) (outline-next-heading))
      (setq start (point)))
     ((or (org-at-heading-p)
          (condition-case nil (progn (org-back-to-heading) t) (error nil)))
      ;; we will sort the children of the current headline
      (org-back-to-heading)
      (setq start (point)
        end (progn (org-end-of-subtree t t)
               (or (bolp) (insert "\n"))
               (org-back-over-empty-lines)
               (point))
        what "children")
      (goto-char start)
      (show-subtree)
      (outline-next-heading))
     (t
      ;; we will sort the top-level entries in this file
      (goto-char (point-min))
      (or (org-at-heading-p) (outline-next-heading))
      (setq start (point))
      (goto-char (point-max))
      (beginning-of-line 1)
      (when (looking-at ".*?\\S-")
    ;; File ends in a non-white line
    (end-of-line 1)
    (insert "\n"))
      (setq end (point-max))
      (setq what "top-level")
      (goto-char start)
      (show-all)))

    (setq beg (point))
    (if (>= beg end) (error "Nothing to sort"))

    (looking-at "\\(\\*+\\)")
    (setq stars (match-string 1)
      re (concat "^" (regexp-quote stars) " +")
      re2 (concat "^" (regexp-quote (substring stars 0 -1)) "[ \t\n]")
      txt (buffer-substring beg end))
    (if (not (equal (substring txt -1) "\n")) (setq txt (concat txt "\n")))
    (if (and (not (equal stars "*")) (string-match re2 txt))
    (error "Region to sort contains a level above the first entry"))

    (unless sorting-type
      (message
       "Sort %s: [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:"
       what)
      (setq sorting-type (read-char-exclusive))

      (and (= (downcase sorting-type) ?f)
           (setq getkey-func
                 (org-icompleting-read "Sort using function: "
                       obarray 'fboundp t nil nil))
           (setq getkey-func (intern getkey-func)))

      (and (= (downcase sorting-type) ?r)
           (setq property
                 (org-icompleting-read "Property: "
                       (mapcar 'list (org-buffer-property-keys t))
                       nil t))))

    (message "Sorting entries...")

    (save-restriction
      (narrow-to-region start end)
      (let ((dcst (downcase sorting-type))
        (case-fold-search nil)
            (now (current-time)))
        (sort-subr
         (/= dcst sorting-type)
         ;; This function moves to the beginning character of the "record" to
         ;; be sorted.
     (lambda nil
       (if (re-search-forward re nil t)
           (goto-char (match-beginning 0))
         (goto-char (point-max))))
         ;; This function moves to the last character of the "record" being
         ;; sorted.
     (lambda nil
       (save-match-data
         (condition-case nil
         (outline-forward-same-level 1)
           (error
        (goto-char (point-max))))))
         ;; This function returns the value that gets sorted against.
     (lambda nil
       (cond
        ((= dcst ?n)
         (if (looking-at org-complex-heading-regexp)
         (string-to-number (match-string 4))
           nil))
        ((= dcst ?a)
         (if (looking-at org-complex-heading-regexp)
         (funcall case-func (match-string 4))
           nil))
        ((= dcst ?t)
         (let ((end (save-excursion (outline-next-heading) (point))))
           (if (or (re-search-forward org-ts-regexp end t)
               (re-search-forward org-ts-regexp-both end t))
           (org-time-string-to-seconds (match-string 0))
         (org-float-time now))))
        ((= dcst ?c)
         (let ((end (save-excursion (outline-next-heading) (point))))
           (if (re-search-forward
            (concat "^[ \t]*\\[" org-ts-regexp1 "\\]")
            end t)
           (org-time-string-to-seconds (match-string 0))
         (org-float-time now))))
        ((= dcst ?s)
         (let ((end (save-excursion (outline-next-heading) (point))))
           (if (re-search-forward org-scheduled-time-regexp end t)
           (org-time-string-to-seconds (match-string 1))
         (org-float-time now))))
        ((= dcst ?d)
         (let ((end (save-excursion (outline-next-heading) (point))))
           (if (re-search-forward org-deadline-time-regexp end t)
           (org-time-string-to-seconds (match-string 1))
         (org-float-time now))))
        ((= dcst ?p)
         (if (re-search-forward org-priority-regexp (point-at-eol) t)
         (string-to-char (match-string 2))
           org-default-priority))
        ((= dcst ?r)
         (or (org-entry-get nil property) ""))
        ((= dcst ?o)
         (if (looking-at org-complex-heading-regexp)
         (- 9999 (length (member (match-string 2)
                     org-todo-keywords-1)))))
        ((= dcst ?f)
         (if getkey-func
         (progn
           (setq tmp (funcall getkey-func))
           (if (stringp tmp) (setq tmp (funcall case-func tmp)))
           tmp)
           (error "Invalid key function `%s'" getkey-func)))
        (t (error "Invalid sorting type `%c'" sorting-type))))
         nil
         (cond
          ((= dcst ?a) 'string<)
          ((= dcst ?f) compare-func)
          ((member dcst '(?p ?t ?s ?d ?c)) '<)))))
    (run-hooks 'org-after-sorting-entries-or-items-hook)
    ;; Reset the clock marker if needed
    (when cmstr
      (save-excursion
    (goto-char start)
    (search-forward cmstr nil t)
    (move-marker org-clock-marker (point))))
    (message "Sorting entries...done")))

(defun org-do-sort (table what &optional with-case sorting-type)
  "Sort TABLE of WHAT according to SORTING-TYPE.
The user will be prompted for the SORTING-TYPE if the call to this
function does not specify it.  WHAT is only for the prompt, to indicate
what is being sorted.  The sorting key will be extracted from
the car of the elements of the table.
If WITH-CASE is non-nil, the sorting will be case-sensitive."
  (unless sorting-type
    (message
     "Sort %s: [a]lphabetic, [n]umeric, [t]ime.  A/N/T means reversed:"
     what)
    (setq sorting-type (read-char-exclusive)))
  (let ((dcst (downcase sorting-type))
    extractfun comparefun)
    ;; Define the appropriate functions
    (cond
     ((= dcst ?n)
      (setq extractfun 'string-to-number
        comparefun (if (= dcst sorting-type) '< '>)))
     ((= dcst ?a)
      (setq extractfun (if with-case (lambda(x) (org-sort-remove-invisible x))
             (lambda(x) (downcase (org-sort-remove-invisible x))))
        comparefun (if (= dcst sorting-type)
               'string<
             (lambda (a b) (and (not (string< a b))
                        (not (string= a b)))))))
     ((= dcst ?t)
      (setq extractfun
        (lambda (x)
          (if (or (string-match org-ts-regexp x)
              (string-match org-ts-regexp-both x))
          (org-float-time
           (org-time-string-to-time (match-string 0 x)))
        0))
        comparefun (if (= dcst sorting-type) '< '>)))
     (t (error "Invalid sorting type `%c'" sorting-type)))

    (sort (mapcar (lambda (x) (cons (funcall extractfun (car x)) (cdr x)))
          table)
      (lambda (a b) (funcall comparefun (car a) (car b))))))

答案1

编辑(2014 年 3 月 7 日):另请参阅以下相关主题:

https://stackoverflow.com/a/22232709/2112489

编辑(2014 年 1 月 13 日):关于职能org-sort-entries,与时间 / 安排 / 截止期限 / 创建对于不包含与正则表达式匹配的日期的待办事项,使用(org-float-time now)aka 。因此,没有日期的任务将被加权为相等——这会导致它们排在具有即将到来的日期的任务之前。要对没有日期的任务进行加权,以便它们排在具有日期的任务之后,可以给它们一个遥远的未来日期,以便它们排在有日期的任务之后——例如,将值设置为 2030 年,如下所示: 。当然,这需要创建一个替代函数或。所以看似错误的东西实际上是设计所致,但是,我更希望没有日期的任务不要被加权为相等(org-float-time (current-time))today(org-time-string-to-seconds "<2030-12-31 Tue>")defalias今天

对于那些正在与org-tags-vieworg-scan-tagsorg-agenda-listorg-agenda-get-deadlines和其他相关功能作斗争的人来说,如果你看一下与相关的部分org-add-props txt props,你会看到组织团队有不是提供了足够的文本属性来对 todo 任务进行排序,其中包含列出的所有各种选项defcustom org-agenda-sorting-strategy——因此,在疯狂地试图弄清楚为什么所有排序选项都不起作用之前,请先查看是否分配了文本属性来处理这些排序选项——如果没有,那么如果您希望这些选项可用,则需要花时间进行修改。请参阅以下线程,获取可用于隔离 todo 任务各部分的综合正则表达式的示例: https://stackoverflow.com/a/20960301/2112489

编辑(2013 年 7 月 11 日):第一个工作草案。注意:未注明日期的任务需要在其他地方重新提交(错误解决方法),以避免按截止日期对包含已注明日期和未注明日期的任务的组进行排序。请参阅以下链接作为示例,以完成上述截止日期排序错误解决方法: 如何自动化 org-refile 以处理多个待办事项

(defun lawlist-sort ()
    (interactive)
    (goto-char (point-min))
    (while
    (re-search-forward "^\* " nil t) ;; sorts the whole kitten caboodle
        (goto-char (match-beginning 0))
        (condition-case err
            (progn
                (org-sort-entries t ?a)
                (org-sort-entries t ?o)
                (org-sort-entries t ?p)
                (org-sort-entries t ?t)
                (forward-line))
            (error nil)
        )
    )
    (goto-char (point-min))
    (while
        (re-search-forward "^\* ARCHIVES" nil t)
        (goto-char (match-beginning 0))
        (condition-case err
           (progn
                (org-sort-entries t ?a)
                (org-sort-entries t ?o)
                (org-sort-entries t ?p)
                (forward-line))
        (error nil)
        )
    ) )

相关内容