;;; gtd.el -*- lexical-binding: t; -*- (after! org (setq org-return-follows-link t org-complete-tags-always-offer-all-agenda-tags t org-agenda-files (mapcar (lambda (filename) (expand-file-name filename org-directory)) '("gtd/inbox.org" "gtd/tasks.org" "gtd/journal.org" "gtd/calendar.org"))) ;; (file-expand-wildcards (concat org-directory "gtd/*.org")))) ;; 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 ,(funcall #'gtd-get-current-journal)) ("l" "Link" entry (file "gtd/inbox.org") ,(concat "* Process %:annotation\n" ":PROPERTIES:\n:CREATED: %U\n:END:") :prepend t) ("j" "Journal" entry (file+datetree "gtd/journal.org") ,(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)) (,(expand-file-name "gtd/someday.org" org-directory) . (:maxlevel . 1))))) ;; Getting the following on capture: ;; ;; Greedy org-protocol handler. Killing client. ;; No server buffers remain to edit ;; ;; See https://github.com/alphapapa/org-protocol-capture-html/issues/40 ;; (use-package! org-protocol-capture-html ;; :after org-protocol ;; :config ;; (add-to-list 'org-capture-templates ;; '("w" "Website" entry (file "") ;; "* %a :website:\n\n%U %?\n\n%:initial")) (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 p" #'gtd-capture-email) ;; Insert CREATED property timestamps for non-captured headlines (use-package! org-expiry :after org :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 :after org :config (org-edna-mode) (setq org-edna-use-inheritance t)) (use-package! org-super-agenda :after org :config (org-super-agenda-mode) (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))) ;; TODO combine the two queries into one (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 ;; Source: 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")) ;; TODO: use org-after-refile-insert-hook ?? (defun gtd-update-statistics-cookies () "Save `org-agenda-files' buffers without user confirmation. See also `org-save-all-org-buffers'" (interactive) (message "Updating cookies in org-agenda-files buffers...") (save-some-buffers t (lambda () (when (member (buffer-file-name) org-agenda-files) t))) (message "Updating cookies in org-agenda-files buffers... done")) (after! org ;; (advice-add 'org-refile :after (lambda (&rest _) (org-update-statistics-cookies t))) (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)))) (defun gtd-agenda () (interactive) (org-agenda nil "g")) (map! :map 'override "" #'gtd-agenda) ;; ;;; Archiving ;; Store archived entries in .org_archive in a datetree (after! org (setq org-archive-location "%s_archive::datetree/")) ;; ;;; Calendar (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 :after org :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-format "* {title} {cancelled} :{calendar}:\n\ :PROPERTIES:\n:CALENDAR: {calendar}\n\ :LOCATION: {location}\n\ :ID: {uid}\n\ :END:\n\ <{start-date-long} {start-time}>--<{end-date-long} {end-time}>\n\ {description}\n\ [[elisp:(khalel-edit-calendar-event)][Edit this event]]\ [[elisp:(progn (khalel-run-vdirsyncer) (khalel-import-events))]\ [Sync and update all]]\n" 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")) (after! org (khalel-add-capture-template)) (defun gtd-capture-event () (interactive) (org-capture nil "e")) (map! "C-c e" #'gtd-capture-event) (after! org (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)) ;; ;;; Reference system (load! "roam")