;;; 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 "" #'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 "" #'org-clock-convenience-timestamp-up "" #'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))