From fb767b39948483fceb8fe83698933f13f79f1a93 Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Tue, 14 Mar 2023 01:34:09 -0700 Subject: [PATCH] [oni-org] Add new commands to manage my GTD inbox and tickler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These function help me make sure that I'm properly going through both files. The command ‘oni-org-run-through-inbox’ will first dump any items in the tickler file that are relevant for today and then it goes through each item in my inbox and asks me to take an action on them. This helps me both go through my inbox more easily, but also helps me keep track of the items in my tickler file, which has been something I keep forgetting to look at. The ‘oni-org-dump-tickler’ command should be idempotent, so calling it multiple times per day shouldn't mess with the different dates in the file. If it discovers that the current day isn't the same as today it keeps going through the tickler file, dumping any tasks it finds into the inbox, until it finds the right day number. It's not aware of any of the months, so it'll happily move to the next month if your tickler file is in the wrong state. Also if your tickler file hasn't been updated in more than a month it also doesn't understand that it needs to keep going and will keep presenting you with old tasks. --- oni-org/oni-org.el | 102 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/oni-org/oni-org.el b/oni-org/oni-org.el index 1416060..24df0d0 100644 --- a/oni-org/oni-org.el +++ b/oni-org/oni-org.el @@ -4,7 +4,7 @@ ;; Author: Tom Willemse ;; Keywords: local -;; Version: 2023.0224.232539 +;; Version: 2023.0314.013950 ;; Package-Requires: (oni-yasnippet oni-alert oni-hydra org org-contrib org-bullets org-edna diminish all-the-icons olivetti form-feed) ;; This program is free software; you can redistribute it and/or modify @@ -1052,5 +1052,105 @@ placed above TARGET. Otherwise it will be placed below it." (org-archive-subtree)) (reverse (org-map-entries #'point match 'agenda))))) +;;; Inbox management + +(defun oni-org-should-dump-tickler-p () + (with-current-buffer (find-file-noselect "~/documents/gtd/tickler.org") + (goto-char (point-min)) + (search-forward "#+last-dumped: ") + (let ((dumped-date (org-timestamp-to-time (org-timestamp-from-string (buffer-substring-no-properties (point) (line-end-position))))) + (current-date (org-timestamp-to-time (org-timestamp-from-string (format-time-string "[%Y-%m-%d]"))))) + (time-less-p dumped-date current-date)))) + +(defun oni-org-update-tickler-dumped-date () + (with-current-buffer (find-file-noselect "~/documents/gtd/tickler.org") + (goto-char (point-min)) + (search-forward "#+last-dumped: ") + (delete-region (point) (line-end-position)) + (insert (format-time-string "[%Y-%m-%d]")))) + +(defun oni-org-dump-tickler-1 () + (with-current-buffer (find-file-noselect "~/documents/gtd/tickler.org") + (save-excursion + (goto-char (point-min)) + (org-forward-heading-same-level 1) + (let* ((element (org-element-at-point-no-context)) + (element-data (when element (cadr element))) + (element-title (when element-data (map-elt element-data :raw-value))) + (contents-begin (when element-data (map-elt element-data :contents-begin))) + (contents-end (when element-data (map-elt element-data :contents-end)))) + (when contents-begin + (let ((text (buffer-substring-no-properties contents-begin contents-end))) + (delete-region contents-begin contents-end) + (with-temp-buffer + (insert text) + (org-mode) + (org-map-entries 'org-promote-subtree) + (setq text (buffer-substring-no-properties (point-min) (point-max)))) + (with-current-buffer (find-file-noselect "~/documents/gtd/inbox.org") + (save-excursion + (let ((max-point (point-max))) + (goto-char max-point) + (insert text) + (goto-char max-point)))))) + (if (string-match-p (rx (one-or-more digit)) element-title) + (progn + (dotimes (_ 31) + (org-move-subtree-down)) + (unless (string= element-title (format-time-string "%d")) + (oni-org-dump-tickler-1))) + (dotimes (_ 41) + (org-move-subtree-down)) + (oni-org-dump-tickler-1)))))) + +(defun oni-org-dump-tickler () + (interactive) + (when (oni-org-should-dump-tickler-p) + (oni-org-dump-tickler-1) + (oni-org-update-tickler-dumped-date))) + +(defun oni-org-run-through-inbox () + (interactive) + (oni-org-dump-tickler) + (catch 'done + (while t + (find-file "~/documents/gtd/inbox.org") + (goto-char (point-min)) + (org-forward-heading-same-level 1) + (when (not (org-at-heading-p)) + (throw 'done t)) + (org-fold-save-outline-visibility nil + (outline-show-entry) + (org-narrow-to-subtree) + (unwind-protect + (catch 'continue + (while t + (let ((choice (read-multiple-choice + "Which action: " + '((?r "Refile" "Refile heading to a different place") + (?R "Refile to top" "Refile heading to a different place, placing the note at the top of the heading") + (?a "Archive" "Archive heading") + (?d "Remind me later" "Move it into the tickler file") + (?t "Todo" "Change todo keyword") + (?T "Tag" "Change tags") + (?q "Quit" "Stop going through"))))) + (condition-case nil + (cl-case (car choice) + (?r (org-refile) + (throw 'continue t)) + (?R (let ((org-reverse-note-order t)) + (org-refile)) + (throw 'continue t)) + (?a (org-archive-subtree-default) + (throw 'continue t)) + (?d (let ((org-refile-targets '(("~/documents/gtd/tickler.org" :maxlevel . 10)))) + (org-refile)) + (throw 'continue t)) + (?t (org-todo)) + (?T (org-set-tags-command)) + (?q (throw 'done t))) + (quit nil))))) + (widen)))))) + (provide 'oni-org) ;;; oni-org.el ends here