doom-config/gtd.el

197 lines
7.4 KiB
EmacsLisp

;;; gtd.el -*- lexical-binding: t; -*-
(require 'org)
(setq org-return-follows-link t
org-complete-tags-always-offer-all-agenda-tags t
org-agenda-files (append (mapcar 'file-truename
(file-expand-wildcards (concat org-directory "gtd/*.org")))
(list (expand-file-name (funcall #'gtd-get-current-journal) org-directory))))
(setq org-capture-templates
`(("i" "Inbox" entry (file "gtd/inbox.org")
,(concat "* %?\n"
":PROPERTIES:\n:CREATED: %U\n:END:") :prepend t)
("j" "Journal" entry (file+datetree ,(gtd-get-current-journal))
,(concat "* %?\n"
":PROPERTIES:\n:CREATED: %U\n:END:"))
("@" "Inbox [mu4e]" entry (file "gtd/inbox.org")
;; "* Process [[mu4e:msgid:%:message-id][%:fromname - %:subject]] :email:\n%U\n"))
,(concat "* Process %a %?\n"
":PROPERTIES:\n:CREATED: %U\n:END:") :prepend t)))
(setq org-refile-allow-creating-parent-nodes 'confirm
org-refile-target-verify-function (lambda (&rest _) (null (org-get-todo-state)))
;; org-refile-target-verify-function nil
;; org-refile-targets '(("tasks.org" . (:maxlevel . 2))))
org-refile-targets '(("tasks.org" . (:maxlevel . 2))
("someday.org" . (:level . 0))))
(defun gtd-capture-inbox ()
(interactive)
(org-capture nil "i"))
(map! "C-c i" #'gtd-capture-inbox)
(defun gtd-capture-journal ()
(interactive)
(org-capture nil "j"))
(map! "C-c j" #'gtd-capture-journal)
(defun gtd-capture-email ()
(interactive)
(call-interactively 'org-store-link)
(org-capture nil "@"))
(map! :after mu4e
:map (mu4e-headers-mode-map mu4e-view-mode-map)
:vne "C-c i" #'gtd-capture-email)
;; Insert CREATED property timestamps for non-captured headlines
(use-package! org-expiry
:config
(map! :map org-mode-map
"C-c c" #'org-expiry-insert-created)
(setq org-expiry-inactive-timestamps t))
;; Automatically trigger state changes in projects
(use-package! org-edna
:config
(setq org-edna-use-inheritance t)
(org-edna-mode))
(use-package! org-super-agenda
:after org
:config
(setq org-agenda-window-setup 'current-window
org-agenda-restore-windows-after-quit t
org-agenda-block-separator nil
org-agenda-compact-blocks t
org-agenda-start-with-log-mode t
org-agenda-hide-tags-regexp "."
org-super-agenda-header-map (make-sparse-keymap)
org-agenda-custom-commands
'(("g" "Get Things Done (GTD)"
((agenda ""
((org-agenda-skip-function
'(org-agenda-skip-entry-if 'deadline))
(org-deadline-warning-days 0)))
(tags "inbox" ((org-agenda-overriding-header "")
(org-agenda-prefix-format " %?-14t% s")
(org-super-agenda-groups
'((:name "Inbox"
:anything t)))))
(alltodo "" ((org-agenda-overriding-header "")
(org-agenda-prefix-format " %i %-14:c ")
(org-agenda-sorting-strategy '(category-up))
(org-agenda-skip-function
'(org-agenda-skip-entry-if 'scheduled))
(org-super-agenda-groups
'((:name "Deadlines"
:deadline t)
(:name "Tasks"
:todo "NEXT")
(:name "Blocked/Delegated"
:todo "WAIT")
(:name "Completed today"
:log 'closed)
(:discard (:anything t)))))))))))
;; Automatically save gtd files after some actions on them
;; Taken from: https://www.labri.fr/perso/nrougier/GTD/index.html
(defun gtd-save-org-buffers ()
"Save `org-agenda-files' buffers without user confirmation.
See also `org-save-all-org-buffers'"
(interactive)
(message "Saving org-agenda-files buffers...")
(save-some-buffers t (lambda ()
(when (member (buffer-file-name) org-agenda-files)
t)))
(message "Saving org-agenda-files buffers... done"))
(advice-add 'org-refile :after (lambda (&rest _) (gtd-save-org-buffers)))
(advice-add 'org-todo :after (lambda (&rest _) (gtd-save-org-buffers)))
(advice-add 'org-add-note :after (lambda (&rest _) (gtd-save-org-buffers)))
(advice-add 'org-clock-in :after (lambda (&rest _) (gtd-save-org-buffers)))
(map! :map 'override
"<f1>" #'gtd-agenda)
(defun gtd-agenda ()
(interactive)
(org-agenda nil "g"))
;; (defun gtd-archive-subtree ()
;; "Archive the current subtree to a yearly journal."
;; (when (not (equal "DONE" (org-get-todo-state)))
;; (org-todo "DONE"))
;; Archiving
(defun gtd-get-current-journal ()
"Returns journal file as a string for the current year."
(let ((year (number-to-string (caddr (calendar-current-date)))))
(concat "journal/" year ".org")))
(setq org-archive-location (concat (funcall #'gtd-get-current-journal) "::datetree/"))
(defun max/khalel--insert-import-file-header (sdate edate)
"Insert imported events file header information into current buffer.
SDATE and EDATE denote the start and end dates, respectively, of
the current import date range."
(when khalel-import-org-file-read-only
(insert "# -*- buffer-read-only: 1; -*-\n"))
(insert khalel-import-org-file-header)
(insert (format "*Events scheduled between %s and %s*:\n" sdate edate)))
(use-package! khalel
:commands (khalel-export-org-subtree-to-calendar
khalel-import-events
khalel-edit-calender-event
khalel-add-capture-template)
:init
(khalel-add-capture-template)
:config
(advice-add #'khalel--insert-import-file-header :override #'max/khalel--insert-import-file-header)
(advice-add #'khalel-import-events :around #'doom-shut-up-a)
(setq khalel-default-calendar "personal"
khalel-import-org-file-confirm-overwrite nil
khalel-import-start-date "-15d"
khalel-import-end-date "+30d"
khalel-import-org-file (expand-file-name "gtd/calendar.org" org-directory)
khalel-import-org-file-header "#+TITLE: Calendar\n\n\
*NOTE*: this file has been generated by \
[[elisp:(khalel-import-events)][khalel-import-events]] \
and /any changes to this document will be lost on the next import/!
Instead, use =khalel-edit-calendar-event= or =khal edit= to edit the \
underlying calendar entries, then re-import them here.
You can use [[elisp:(khalel-run-vdirsyncer)][khalel-run-vdirsyncer]] \
to synchronize with remote calendars.
Consider adding this file to your list of agenda files so that events \
show up there.\n\n"))
(setq org-clock-persist t
;; Useful when clocking in on a waiting task
org-clock-in-switch-to-state "NEXT"
org-clock-out-when-done '("DONE" "CNCL" "WAIT")
org-clock-persist-query-resume nil)
(use-package! org-clock-convenience
:after org
:config
;; Fix for macos: https://github.com/dfeich/org-clock-convenience/issues/9#issuecomment-646842338
(when IS-MAC (load "org-clock-convenience"))
(map! :map org-agenda-mode-map
"<S-up>" #'org-clock-convenience-timestamp-up
"<S-down>" #'org-clock-convenience-timestamp-down
"o" #'org-clock-convenience-fill-gap
"e" #'org-clock-convenience-fill-gap-both))
(after! org-pomodoro
(setq org-pomodoro-length 25
org-pomodoro-short-break-length 5
org-pomodoro-long-break-length 20))