Пользовательский поиск с использованием меток времени в ЖУРНАЛЕ в организационном режиме

Я хотел бы создать настраиваемый поиск по повестке дня, который будет находить элементы TODO на основе записей времени в ЖУРНАЛЕ. В частности, я хотел бы найти элементы, помеченные как WAITING, на основе метки времени, которая отметила вход в состояние ожидания. Эти записи выглядят так:

:LOGBOOK:
- State "WAITING"     from "TODO"    [2011-11-02 Wed 15:10] \\
  Emailed so-and-so about such-and-such.
:END:

Могу ли я сделать это с информацией в бортовом журнале? Я использую версию 7.5, но при необходимости могу обновить.

Спасибо!

Изменить: одним из вариантов использования может быть поиск задач WAITING, которые находились в состоянии ожидания более недели. (Что обычно означает, что мне нужно снова кого-то прослушать.)


person Mike B    schedule 07.11.2011    source источник
comment
Есть ли какая-то конкретная причина, по которой вы хотите это, основываясь на бортовом журнале? Если элементы в настоящее время ОЖИДАЮТ, вы сможете просто выполнить пользовательский поиск на основе этого. Я подозреваю, что что-то можно адаптировать из метода архивирования здесь: doc. norang.ca/org-mode.html#sec-12-2 . Просто настройте соответствующий параметр, чтобы он соответствовал состоянию \WAITING\. Хотя я не уверен, как его сортировать исключительно на основе этих временных меток, а не на других, которые включены.   -  person Jonathan Leech-Pepin    schedule 08.11.2011
comment
Один из вариантов использования — поиск элементов WAITING, которые перешли в состояние ожидания более недели назад. Поскольку моя настройка todo уже записывает время, когда она перешла в состояние WAITING, в журнале регистрации, это казалось местом для начала. Хотя я открыт для других подходов.   -  person Mike B    schedule 16.11.2011
comment
Будет ли запись времени в ЖУРНАЛЕ, которую вы хотите сопоставить, всегда самой последней? Это должна быть либо самая последняя запись в журнале, либо она должна совпадать со всеми записями в журнале для этого заголовка (независимо от обновлений с тех пор). Я подозреваю, что вы хотите, чтобы он соответствовал только самой последней записи LOGBOOK, иначе он не соответствовал бы вашему варианту использования.   -  person Jonathan Leech-Pepin    schedule 18.11.2011


Ответы (2)


Следующее должно делать то, что вам нужно. Вам просто нужно настроить команды Custom Agenda в соответствии с вашим вариантом использования. (При тестировании и настройке я использовал свои ключевые слова TODO). Возможно, одна часть этого кода дублирует работу встроенной организационной функции, особенно потому, что она напоминает подход/просрочку по расписанию и сроку выполнения, но я не нашел какой-либо конкретной функции, которую можно было бы использовать повторно.

Фактическая функция для использования в пользовательской команде приведена ниже.

(defun zin/since-state (since todo-state &optional done all)
  "List Agenda items that are older than SINCE.

TODO-STATE is a regexp for matching to TODO states.  It is provided to
`zin/find-state' to match inactive timestamps.
SINCE is compared to the result of `zin/org-date-diff'.  If
`zin/org-date-diff' is greater than SINCE, the entry is shown in the
Agenda. 
Optional argument DONE allows for done and not-done headlines to be
evaluated.  If DONE is non-nil, match completed tasks.
Optional argument ALL is passed to `zin/find-state' to specify whether
to search for any possible match of STATE, or only in the most recent
log entry."
  (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
    ;; If DONE is non-nil, look for done keywords, if nil look for not-done
    (if (member (org-get-todo-state)
                (if done
                    org-done-keywords
                  org-not-done-keywords))
        (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
               (subtree-valid (save-excursion
                               (forward-line 1)
                               (if (and (< (point) subtree-end)
                                        ;; Find the timestamp to test
                                        (zin/find-state todo-state subtree-end all))
                                   (let ((startpoint (point)))
                                     (forward-word 3)
                                     ;; Convert timestamp into days difference from today
                                     (zin/org-date-diff startpoint (point)))))))
          (if (or (not subtree-valid)
                  (<= subtree-valid since))
              next-headline
            nil))
      (or next-headline (point-max)))))

Следующая функция находит записи в журнале с помощью повторного поиска.

(defun zin/find-state (state &optional end all)
  "Used to search through the logbook of subtrees.

Tests to see if the first line of the logbook is a change of todo
status to status STATE
- Status \"STATE\" from ...
The search brings the point to the start of YYYY-MM-DD in inactive timestamps.

Optional argument END defines the point at which to stop searching.
Optional argument ALL when non-nil specifies to look for any occurence
of STATE in the subtree, not just in the most recent entry."
  (let ((drawer (if all "" ":.*:\\W")))
    (re-search-forward (concat drawer ".*State \\\"" state "\\\"\\W+from.*\\[") end t)))

Последняя функция определяет разницу в количестве дней между сегодняшним днем ​​и отметкой времени, найденной вышеприведенной функцией.

(defun zin/org-date-diff (start end &optional compare)
  "Calculate difference between  selected timestamp to current date.

The difference between the dates is calculated in days.
START and END define the region within which the timestamp is found.
Optional argument COMPARE allows for comparison to a specific date rather than to current date."
  (let* ((start-date (if compare compare (calendar-current-date))))
    (- (calendar-absolute-from-gregorian start-date) (org-time-string-to-absolute (buffer-substring-no-properties start end)))
    ))

Два примера пользовательских команд повестки дня, использующих вышеуказанные функции. Первое соответствует вашему варианту использования, вам просто нужно изменить «PEND» на «WAITING», чтобы оно соответствовало правильному ключевому слову. Второй ищет ключевые слова DONE, которые были завершены более 30 дней назад (в отличие от поиска временных меток, у которых месяц соответствует этому/последнему месяцу, как это сделано в примере, который я связал в своем первом комментарии).

(setq org-agenda-custom-commands
      (quote (("T" "Tasks that have been pending more than 7 days." tags "-REFILE/"
               ((org-agenda-overriding-header "Pending tasks")
                (org-agenda-skip-function '(zin/since-state 7 "PEND"))))
              ("A" "Tasks that were completed more than 30 days ago." tags "-REFILE/"
               ((org-agenda-overriding-header "Archivable tasks")
                (org-agenda-skip-function '(zin/since-state 30 "\\\(DONE\\\|CANC\\\)" t))))
              )))
person Jonathan Leech-Pepin    schedule 18.11.2011
comment
Спасибо! Это похоже именно то, что мне нужно. Жаль, что некоторые из встроенных модулей не были более полезными, так как это кажется распространенным вариантом использования. Кроме того, в zin/find-state передается дополнительный аргумент all. Удаление этого заставило код работать правильно. - person Mike B; 07.12.2011
comment
К сожалению, на самом деле это t, которое лишнее в вызове zin/find-state из zin/since-state. Предполагается, что по умолчанию он равен нулю, и необходимо передать t из самой команды повестки дня (если ВСЕ равно t, он найдет любое вхождение, а не только самое последнее в журнале, что должно генерировать ложные срабатывания). Я исправлю значение в своем ответе. - person Jonathan Leech-Pepin; 07.12.2011

В дополнение к ответу Джонатана Лич-Пепина, если вы хотите посмотреть на ящик CLOSED:, добавленный конфигурацией (setq org-log-done 'time), вы можете улучшить функцию zin/find-state следующим образом:

(defun zin/find-state (state &optional end all)
  (let ((drawer (if all "" ":.*:\\W" "CLOSED:")))
    (or (re-search-forward (concat drawer ".*State \\\"" state "\\\"\\W+from.*\\[") end t)
        (re-search-forward (concat drawer ".*\\[") end t))))

PS: это просто улучшение ответа, правильный ответ - ответ Джонатана.

person squiter    schedule 30.08.2016