diff options
| author | Craig Jennings <c@cjennings.net> | 2024-04-22 12:23:13 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2024-04-22 12:23:13 -0500 |
| commit | 2dd3aed6971fe74915c1fc09b4de20a6c64e817b (patch) | |
| tree | f9d896ebcfd0e6a2acb2684ff085a42324a9a638 /modules/org-agenda-config.el | |
| parent | 5d18558615a127640d6b4e634997ee35a5fe1b77 (diff) | |
New Custom Functions, Org Updates, Agenda Updates, &c.
=== Functions ===
- add function cj/dired-convert-image-to-jpeg
- add function cj/dired-copy-path-as-kill
- add function cj/export-org-to-md-on-save function
- add function cj/org-link-to-current-file
=== Agenda ===
- rework the f8 main agenda into custom agenda using Aaron Bieber's ideas
- agenda lists now use standard agenda functions
- updated packages to remove org-super-agenda and ts (a dependency)
- file commentary text updated to reflect the change
=== Org ===
- add grocery and shopping list capture items
- add missing tests for org-skip-subtree-if-habit
- add support for org-habits, including checkboxes
- fix issue with org-auto-export-to-md
- modularize org-agenda
- move todo settings to org-config
- reformat org-roam-config
=== &c. ===
- add day to sortable date
- add disablefastrenderer to hugo server flags
- add fill column indicator when emacs lisping
- add gpt buffers to the bury-alive-list
- add keybinding for fixup-whitespace
- add magit cloning settings
- finish automatically on "Link" capture
- fix company complaints about shutting up function
- fix em, e, ff, and f eshell aliases
- make fallback theme modus-vivendi
- prune the compilation cache when applicable
Diffstat (limited to 'modules/org-agenda-config.el')
| -rw-r--r-- | modules/org-agenda-config.el | 425 |
1 files changed, 182 insertions, 243 deletions
diff --git a/modules/org-agenda-config.el b/modules/org-agenda-config.el index 016fffcc..f15e5503 100644 --- a/modules/org-agenda-config.el +++ b/modules/org-agenda-config.el @@ -5,277 +5,216 @@ ;; Agenda views are tied to the F8 (fate) key. -;; f8 - DAILY SCHEDULE containing a events with a scheduled date or deadline of -;; the current day. This is followed by... -;; - TASK LIST containing tasks from all agenda sources. +;; f8 - MAIN AGENDA which organizes all tasks and events into: +;; - all unfinished priority A tasks +;; - the weekly schedule, including the habit consistency graph +;; - all priority B and C tasks -;; C-f8 - TASK LIST containing all tasks from all agenda sources +;; C-f8 - TASK LIST containing all tasks from all agenda targets. -;; M-f8 - TASK LIST containing all tasks from the current org-mode buffer. +;; M-f8 - TASK LIST containing all tasks from just the current org-mode buffer. ;; NOTE: ;; Files that contain information relevant to the agenda will be found in the ;; following places: the schedule-file, org-roam notes tagged as 'Projects' and ;; project todo.org files found in project-dir and code-dir. -;; How the agenda is created: -;; The inbox and schedule files are always included first. However, in order to -;; stay current, the files containing agenda information are queried before -;; calling the functions in the section org-agenda functions to display the -;; data. This way, any newly created events from project todo.org files, or -;; org-roam Project files will be included. - ;;; Code: -(with-eval-after-load 'org-roam - - ;; ----------------------------- Org TODO Settings --------------------------- - - (setq org-todo-keywords '((sequence "TODO(t)" "PROJECT(p)" "DOING(i)" - "WAITING(w)" "VERIFY(v)" "STALLED(s)" - "DELEGATED(x)" "|" - "FAILED(f)" "DONE(d)" "CANCELLED(c)"))) - - (setq org-todo-keyword-faces - '(("TODO" . "green") - ("PROJECT" . "blue") - ("DOING" . "yellow") - ("WAITING" . "white") - ("VERIFY" . "orange") - ("STALLED" . "light blue") - ("DELEGATED" . "green") - ("FAILED" . "red") - ("DONE" . "dark grey") - ("CANCELLED" . "dark grey"))) - - (setq org-highest-priority ?A) - (setq org-lowest-priority ?D) - (setq org-default-priority ?D) - (setq org-priority-faces '((?A . (:foreground "Cyan" :weight bold)) - (?B . (:foreground "Yellow")) - (?C . (:foreground "Green")) - (?D . (:foreground "Grey")))) - - (setq org-enforce-todo-dependencies t) - (setq org-enforce-todo-checkbox-dependencies t) - (setq org-deadline-warning-days 7) ;; warn me w/in a week of deadlines - (setq org-log-done nil) ;; don't log when tasks was done - - ;; inherit parents properties (no schedules or deadlines) - (setq org-use-property-inheritance t) - - ;; ------------------ Org TODO Next/Previous Set Keybindings ----------------- - - (add-hook 'org-agenda-mode-hook (lambda () - (local-set-key (kbd "s-<right>") #'org-agenda-todo-nextset) - (local-set-key (kbd "s-<left>") #'org-agenda-todo-previousset))) - - ;; ------------------------------ Org Super Agenda ----------------------------- - - (use-package org-super-agenda - :config (org-super-agenda-mode)) - -;;;; ORG AGENDA VIEW DEFINITIONS - (defun cj/agenda-today-view() - "This agenda from all tasks that are scheduled or have a deadline." - (setq org-super-agenda-groups - '((:log t) ; Automatically named "Log" - (:name "SCHEDULED AND DUE" - :time-grid t - :deadline past - :deadline today - :scheduled past - :scheduled today) - (:habit t) - (:name "DUE SOON" - :deadline future) - (:name "LESS IMPORTANT" - :scheduled future - :order 100) - (:discard (:anything t))))) - - (defun cj/agenda-all-view() - "This agenda is built from all tasks." - (setq org-super-agenda-groups - '( - (:name "Ready To Go" - :todo "STAGED" - :todo "READY" - :order 5) - (:name "Due Today" - :deadline past - :deadline today - :order 2) - (:name "Empty Projects" - :todo "PROJECT" - :order 85) - (:name "Delegated" - :todo "DELEGATED" - :order 50) - (:name "Scheduled Later" - :scheduled future - :order 75) - (:name "Scheduled Today" - :scheduled today - :scheduled past - :order 4) - (:name "In Progress" - :todo "DOING" - :order 7) - (:name "High Priority" - :priority "A" - :order 10) - (:name "Waiting" - :todo "WAITING" - :order 60) - (:name "Upcoming" - :deadline future - :order 30) - (:name "Next Priority" - :priority "B" - :order 70) - (:name "Everything Else" - :anything t - :order 90)))) - - ;; ------------------------------ Add Agenda Time ------------------------------ - - (defun cj/add-agenda-time (s) - "Add an event with time S to appear underneath the line-at-point. -This allows a line to show in an agenda without being scheduled or a deadline." - (interactive "sTime: ") - (defvar cj/timeformat "%Y-%m-%d %a") - (org-end-of-line) - (save-excursion - (open-line 1) - (forward-line 1) - (insert (concat "<" (format-time-string cj/timeformat (current-time)) " " s ">" )))) - - (global-set-key (kbd "M-t") #'cj/add-agenda-time) - - ;; ---------------------------- Org Agenda Settings ---------------------------- - +(use-package org-agenda + :ensure nil ;; built-in + :after (org org-roam) + :config (setq org-agenda-prefix-format '((agenda . " %i %-25:c%?-12t% s") (timeline . " % s") - (todo . " %i %-25:c") - (tags . " %i %-12:c") - (search . " %i %-12:c"))) + (todo . " %i %-25:c") + (tags . " %i %-12:c") + (search . " %i %-12:c"))) (setq org-agenda-dim-blocked-tasks 'invisible) (setq org-agenda-skip-scheduled-if-done nil) - (setq org-agenda-skip-include-deadlines t) (setq org-agenda-remove-tags t) (setq org-agenda-compact-blocks t) - ;; ------------------------ Add Files To Org Agenda List ----------------------- - ;; finds files named 'todo.org' (case insensitive) and adds them to - ;; org-agenda-files list. + ;; display the agenda from the bottom + (add-to-list 'display-buffer-alist + '("\\*Org Agenda\\*" + (display-buffer-reuse-mode-window display-buffer-below-selected) + (dedicated . t) + (window-height . fit-window-to-buffer))) - (defun cj/add-files-to-org-agenda-files (directory) - "Recursively searches for files named 'todo.org', - Searches in DIRECTORY and adds them to org-project-files." - (interactive "D") - (setq org-agenda-files - (append (directory-files-recursively directory - "^[Tt][Oo][Dd][Oo]\\.[Oo][Rr][Gg]$" t) - org-agenda-files))) + ;; reset s-left/right each time org-agenda is enabled + (add-hook 'org-agenda-mode-hook (lambda () + (local-set-key (kbd "s-<right>") #'org-agenda-todo-nextset) + (local-set-key (kbd "s-<left>") + #'org-agenda-todo-previousset))) + ;; build org-agenda-list for the first time after emacs init completes. + (add-hook 'emacs-startup-hook #'cj/build-org-agenda-list)) - ;; NOTE: the following functions require org-roam functionality - (with-eval-after-load 'org-roam-config - ;; ---------------------------- Rebuild Org Agenda --------------------------- +;; ------------------------ Add Files To Org Agenda List ----------------------- +;; finds files named 'todo.org' (case insensitive) and adds them to +;; org-agenda-files list. - (defun cj/build-org-agenda-list () - "Rebuilds the org agenda list. -Begins with the inbox-file and schedule-file, then searches for org-roam -Projects and adds all todo.org files from code and project directories." - (interactive) - ;; reset org-agenda-files to inbox-file - (setq org-agenda-files (list inbox-file schedule-file)) - (let ((new-files - (append - (cj/org-roam-list-notes-by-tag "Project")))) - (dolist (file new-files) - (unless (member file org-agenda-files) - (setq org-agenda-files (cons file org-agenda-files))))) +(defun cj/add-files-to-org-agenda-files-list (directory) + "Search for files named \\='todo.org\\=' add them to org-project-files. +DIRECTORY is a string of the path to begin the search." + (interactive "D") + (setq org-agenda-files + (append (directory-files-recursively directory + "^[Tt][Oo][Dd][Oo]\\.[Oo][Rr][Gg]$" t) + org-agenda-files))) - (cj/add-files-to-org-agenda-files projects-dir) - (cj/add-files-to-org-agenda-files code-dir)) +;; ---------------------------- Rebuild Org Agenda --------------------------- +;; builds the org agenda list from all agenda targets. +;; agenda targets is the schedule, project todos, inbox, and org roam projects. - ;; build org-agenda-list for the first time once emacs init is complete. - (add-hook 'emacs-startup-hook 'cj/build-org-agenda-list) - - ;; ------------------------ Org Agenda Display Functions ----------------------- - - (defun cj/agenda-all-agenda-files-day () - "Display an \'org-agenda\' schedule with tasks covering today. +(defun cj/build-org-agenda-list () + "Rebuilds the org agenda list. +Begins with the inbox-file and schedule-file, then searches for org-roam +Projects and adds all todo.org files from code and project directories." + (interactive) + ;; reset org-agenda-files to inbox-file + (setq org-agenda-files (list inbox-file schedule-file)) + (let ((new-files + (append + (cj/org-roam-list-notes-by-tag "Project")))) + (dolist (file new-files) + (unless (member file org-agenda-files) + (setq org-agenda-files (cons file org-agenda-files))))) + + (cj/add-files-to-org-agenda-files-list projects-dir) + (cj/add-files-to-org-agenda-files-list code-dir)) + +;; ------------------------------ Agenda List All ------------------------------ +;; an agenda listing tasks from all available agenda targets. + +(defun cj/todo-list-all-agenda-files () + "Displays an \\='org-agenda\\=' todo list. The contents of the agenda will be built from org-project-files and org-roam files that have project in their filetag." - (interactive) - (cj/build-org-agenda-list) - (setq org-agenda-span 'day) - (cj/agenda-today-view) - (org-agenda "a" "a")) - (global-set-key (kbd "<f8>") #'cj/agenda-all-agenda-files-day) + (interactive) + (cj/build-org-agenda-list) + (org-agenda "a" "t")) +(global-set-key (kbd "C-<f8>") #'cj/todo-list-all-agenda-files) + +;; ------------------------- Agenda List Current Buffer ------------------------ +;; an agenda listing tasks from just the current buffer. + +(defun cj/todo-list-from-this-buffer () + "Displays an \\='org-agenda\\=' todo list built from the current buffer. +If the current buffer isn't an org buffer, inform the user." + (interactive) + (if (eq major-mode 'org-mode) + (let ((org-agenda-files (list buffer-file-name))) + (org-agenda "a" "t")) + (message (concat "Your org agenda request based on '" (buffer-name (current-buffer)) + "' failed because it's not an org buffer.")))) +(global-set-key (kbd "M-<f8>") #'cj/todo-list-from-this-buffer) + +;; -------------------------------- Main Agenda -------------------------------- +;; my custom agenda command from all available agenda targets. adapted from: +;; https://blog.aaronbieber.com/2016/09/24/an-agenda-for-life-with-org-mode.html + +(defvar cj/main-agenda-hipri-title "\nHIGH PRIORITY UNRESOLVED TASKS\n" + "String to announce the high priority section of the main agenda.") + +(defvar cj/main-agenda-schedule-title "\nSCHEDULE\n" + "String to announce the schedule section of the main agenda.") + +(defvar cj/main-agenda-tasks-title "\nPRIORITY B AND C\n" + "String to announce the schedule section of the main agenda.") + +(defun cj/org-skip-subtree-if-habit () + "Skip an agenda entry if it has a STYLE property equal to \"habit\"." + (let ((subtree-end (save-excursion (org-end-of-subtree t)))) + (if (string= (org-entry-get nil "STYLE") "habit") + subtree-end + nil))) + +(defun cj/org-skip-subtree-if-priority (priority) + "Skip an agenda subtree if it has a priority of PRIORITY. +PRIORITY may be one of the characters ?A, ?B, or ?C." + (let ((subtree-end (save-excursion (org-end-of-subtree t))) + (pri-value (* 1000 (- org-lowest-priority priority))) + (pri-current (org-get-priority (thing-at-point 'line t)))) + (if (= pri-value pri-current) + subtree-end + nil))) + +(defun cj/org-skip-subtree-if-keyword (keywords) + "Skip an agenda subtree if it has a TODO keyword in KEYWORDS. +KEYWORDS must be a list of strings." + (let ((subtree-end (save-excursion (org-end-of-subtree t)))) + (if (member (org-get-todo-state) keywords) + subtree-end + nil))) + +(setq org-agenda-custom-commands + '(("d" "Daily Agenda with Tasks" + ((tags "PRIORITY=\"A\"" + ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) + (org-agenda-overriding-header cj/main-agenda-hipri-title))) + (agenda "" ((org-agenda-ndays 1) + (org-agenda-overriding-header cj/main-agenda-schedule-title))) + (alltodo "" + ((org-agenda-skip-function '(or (cj/org-skip-subtree-if-habit) + (cj/org-skip-subtree-if-priority ?A) + (cj/org-skip-subtree-if-priority ?D) + (cj/org-skip-subtree-if-keyword '("PROJECT")) + (org-agenda-skip-if nil '(scheduled deadline)))) + (org-agenda-overriding-header cj/main-agenda-tasks-title)))) + ((org-agenda-compact-blocks nil))))) + + + (defun cj/main-agenda-display () + "Display the main \'org-agenda\' display. +This uses all org-agenda targes and presents three sections: +- all unfinished priority A tasks +- the weekly schedule, including the habit consistency graph +- all priority B and C tasks" + (interactive) + (cj/build-org-agenda-list) + (org-agenda "a" "d")) +(global-set-key (kbd "<f8>") #'cj/main-agenda-display) +;; ------------------------- Add Timestamp To Org Entry ------------------------ +;; simply adds a timestamp to put the org entry on an agenda - (defun cj/agenda-all-agenda-files-week () - "Display an 'org-agenda' schedule with tasks covering this week. -The contents of the agenda will be built from org-project-files and org-roam -files that have project in their filetag." - (interactive) - (cj/build-org-agenda-list) - (setq org-agenda-span 'week) - (cj/agenda-today-view) - (org-agenda "a" "a")) - (global-set-key (kbd "s-<f8>") #'cj/agenda-all-agenda-files-week) - - (defun cj/todo-list-all-agenda-files () - "Displays an 'org-agenda' todo list. -The contents of the agenda will be built from org-project-files and org-roam -files that have project in their filetag." - (interactive) - (cj/build-org-agenda-list) - (cj/agenda-all-view) - (org-agenda "a" "t")) - (global-set-key (kbd "C-<f8>") #'cj/todo-list-all-agenda-files) - - (defun cj/todo-list-from-this-buffer () - "Displays an 'org-agenda' todo list built from the current buffer. - If the current buffer isn't an org buffer, inform the user." - (interactive) - (if (eq major-mode 'org-mode) - (let ((org-agenda-files (list buffer-file-name))) - (cj/agenda-all-view) - (org-agenda "a" "t")) - (message (concat "Your org agenda request based on '" (buffer-name (current-buffer)) - "' failed because it's not an org buffer.")))) - (global-set-key (kbd "M-<f8>") #'cj/todo-list-from-this-buffer) - - ;; --------------------------- Notifications / Alerts -------------------------- - ;; send libnotify notifications about agenda items - - (use-package alert - :defer .5 - :config - (setq alert-fade-time 10) ;; secs to vanish alert - (setq alert-default-style 'libnotify)) ;; work with dunst - - (use-package org-alert - :defer .5 - :bind - ("C-c A" . org-alert-check) - :config - (setq alert-default-style 'libnotify) ;; work with dunst - (setq org-alert-interval 300) ;; seconds checks agenda is checked (300 = 5 mins) - (setq org-alert-notify-cutoff 5) ;; minutes before a deadline to send alert - (setq org-alert-notify-after-event-cutoff 10) ;; mins post deadline to stop alerts - (setq org-alert-notification-title "Reminder") - (org-alert-enable)) - - - ) ;; end with-eval-after-load 'org-roam-config - ) ;; end with-eval-after-load 'org-roam +(defun cj/add-timestamp-to-org-entry (s) + "Add an event with time S to appear underneath the line-at-point. +This allows a line to show in an agenda without being scheduled or a deadline." + (interactive "sTime: ") + (defvar cj/timeformat "%Y-%m-%d %a") + (org-end-of-line) + (save-excursion + (open-line 1) + (forward-line 1) + (insert (concat "<" (format-time-string cj/timeformat (current-time)) " " s ">" )))) +(global-set-key (kbd "M-t") #'cj/add-timestamp-to-org-entry) + +;; --------------------------- Notifications / Alerts -------------------------- +;; send libnotify notifications about agenda items + +(use-package alert + :defer .5 + :after org-agenda + :config + (setq alert-fade-time 10) ;; secs to vanish alert + (setq alert-default-style 'libnotify)) ;; work with dunst + +(use-package org-alert + :defer .5 + :after alert + :bind + ("C-c A" . org-alert-check) + :config + (setq alert-default-style 'libnotify) ;; work with dunst + (setq org-alert-interval 180) ;; seconds between agenda checks (180 = 3 mins) + (setq org-alert-notify-cutoff 5) ;; minutes before a deadline to send alert + (setq org-alert-notify-after-event-cutoff 10) ;; mins post deadline to stop alerts + (setq org-alert-notification-title "Reminder") + (org-alert-enable)) (provide 'org-agenda-config) ;;; org-agenda-config.el ends here |
