dotfiles/dot_config/emacs/lisp/init-org.el

519 lines
19 KiB
EmacsLisp
Raw Normal View History

;;; org-mode.el --- org-mode customizations -*- lexical-binding: t -*-
;; Author: Andrew Scott <git at andyscott dot me>
;; Keywords: org, convenience, tools
;; URL: https://codeberg.org/andyscott/dotfiles
;; This file is not part of GNU Emacs
;; Copyright (c) 2024 Andrew Scott
;; MIT No Attribution
;; Permission is hereby granted, free of charge, to any person obtaining a copy of this
;; software and associated documentation files (the "Software"), to deal in the Software
;; without restriction, including without limitation the rights to use, copy, modify,
;; merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
;; permit persons to whom the Software is furnished to do so.
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
;; INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
;; PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
;;; Commentary:
;; My org-mode customizations.
;;; Code:
(use-package citar
:after (oc)
:config
(setopt citar-bibliography org-cite-global-bibliography
citar-library-paths '("~/Nextcloud/Library/"))
;; (when (elpaca-installed-p 'citar-embark)
;; (setopt citar-at-point-function 'embark-act))
:hook (org-mode . citar-capf-setup))
(use-package citar-embark
:after (citar embark)
:config (citar-embark-mode))
(use-package citar-org-roam
:after (citar org-roam)
:config
(setopt citar-org-roam-capture-template-key "r"
citar-org-roam-note-title-template "${title} - ${author}"
citar-org-roam-subdir "references")
(citar-org-roam-mode))
(use-package citeproc
:after (oc))
(use-feature oc
:after (org)
:config
(setopt org-cite-export-processors '((latex biblatex)
(t csl))
org-cite-global-bibliography '("~/Nextcloud/Library/bib/library.bib"))
(when (elpaca-installed-p 'citar)
(setopt org-cite-activate-processor 'citar
org-cite-follow-processor 'citar
org-cite-insert-processor 'citar)))
(use-feature oc-csl
:after (citeproc oc)
:config
(let ((zotero_styles (expand-file-name
"Zotero/styles/" (or (getenv "XDG_DATA_HOME") "~/.local/share/"))))
(if (file-directory-p zotero_styles)
(setopt org-cite-csl-styles-dir zotero_styles))))
(use-package org
:bind
(:map global-map
("C-c a" . org-agenda)
("C-c c" . org-capture)
("C-c l" . org-store-link))
:config
;; General options TODO: Comment various options more descriptively
(setopt org-agenda-block-separator nil
;; org-agenda-files (list org-directory)
org-agenda-files (directory-files-recursively org-directory "org$")
org-agenda-skip-deadline-if-done nil
org-agenda-skip-scheduled-if-deadline-is-shown t
org-agenda-skip-scheduled-if-done nil
org-agenda-start-on-weekday nil
org-agenda-tags-column 0
org-archive-location (expand-file-name "archive/%s_archive.org::" org-directory)
org-blank-before-new-entry '((heading . auto)
(plain-list-item . auto))
org-deadline-warning-days 5
org-enforce-todo-dependencies t
org-fold-catch-invisible-edits 'show-and-error
org-fontify-done-headline t
org-fontify-quote-and-verse-blocks t
org-fontify-todo-headline t
org-goto-interface 'outline-path-completion
org-hide-emphasis-markers t
org-insert-heading-respect-content t
org-log-done 'time
org-log-into-drawer t
org-log-redeadline 'time
org-log-refile 'note
org-log-reschedule 'time
org-outline-path-complete-in-steps nil
org-pretty-entities t
org-refile-allow-creating-parent-nodes 'confirm
org-refile-targets '((nil :maxlevel . 3)
(org-agenda-files :maxlevel . 2))
org-refile-use-outline-path 'file
org-return-follows-link t
org-reverse-note-order t ; Add/refile notes at the beginning of an entry
org-special-ctrl-a/e t
org-src-preserve-indentation t
org-startup-folded 'fold
org-tags-column 0
org-todo-keywords '((sequence "TODO(t)"
"NEXT(n)"
"PROG(p)"
"|"
"DONE(d!)"
"WONT(w@/!)")
(sequence "IDEA(i)" "|"))
org-todo-keyword-faces '(("TODO" . (dired-mark))
("PROG" . (success))
("NEXT" . (dired-special))
("WONT" . (org-done)))
org-todo-repeat-to-state "TODO")
(setq org-capture-templates
`(
("i" "Inbox" entry (file "roam/inbox.org")
"* %?"
:empty-lines 1
)
("j" "Log Entry"
entry (file+datetree "log.org")
"** %?"
:empty-lines 1)
("n" "Note"
entry (file+headline "inbox.org" "Notes")
"** %?
:PROPERTIES:
:CREATED: %U
:END:"
:empty-lines 1)
("t" "Todo" entry (file+headline "inbox.org" "Tasks")
"** TODO [#B] %?
:PROPERTIES:
:CREATED: %U
:END:
%i\n%a
Notes: "
:empty-lines 1)
)
)
;; Headline appearance
(custom-set-faces
'(org-level-1 ((t (:inherit outline-1 :height 1.5))))
'(org-level-2 ((t (:inherit outline-2 :height 1.4))))
'(org-level-3 ((t (:inherit outline-3 :height 1.3))))
'(org-level-4 ((t (:inherit outline-4 :height 1.2))))
'(org-level-5 ((t (:inherit outline-5 :height 1.1)))))
:hook (org-mode . org-indent-mode)
:init
(setopt org-directory "~/Nextcloud/Documents/org")
(bind-keys :prefix-map as/org-prefix-map
:prefix "C-c o"
("n" . org-metadown)
("p" . org-metaup)
("f" . org-shiftmetaright)
("b" . org-shiftmetaleft)
("v" . org-tags-view)
("y" . org-todo-yesterday)
("l" . org-toggle-link-display)
("C-n" . org-priority-down)
("C-p" . org-priority-up)))
(use-feature org-agenda
:after (org)
:bind
(:map org-agenda-mode-map
("C-c C-r" . as/org-agenda-reconcile-inbox-item))
:config (setopt org-agenda-start-with-log-mode '(clock closed state))
:init
(defun as/org-agenda-reconcile-inbox-item ()
"Process and refile an org-agenda item"
(interactive)
(org-with-wide-buffer
(org-agenda-set-tags)
(org-agenda-priority)
(if (y-or-n-p "Schedule item?")
(org-agenda-schedule nil nil))
(org-agenda-refile nil nil t))))
(use-package org-appear
:config
(setopt org-appear-autoentities t
org-appear-autolinks nil
org-appear-autosubmarkers t
org-appear-trigger 'on-change)
:hook (org-mode . org-appear-mode))
(use-feature org-clock
:after (org)
:config
(setopt org-clock-in-resume t
org-clock-in-switch-to-state "PROG"
org-clock-persist t
org-clock-rounding-minutes 5))
(use-package org-edna
:config (setopt org-edna-finder-use-cache t)
:hook (org-mode . org-edna-mode))
(use-feature org-habit
:after (org)
;; REVIEW: do I need to add to modules if it loads after org anyway?
:init (add-to-list 'org-modules 'org-habit t))
(use-feature org-id
:after (org)
:config
(setopt org-id-link-to-org-use-id t
org-id-locations-file (locate-user-emacs-file "org-id-locations")
org-id-method 'ts
org-id-ts-format "%Y%m%dT%H%M%S.%2N%z")
;; REVIEW: do I need to add to modules if it loads after org anyway?
:init (add-to-list 'org-modules 'org-id t))
(use-package org-modern
:disabled t
:config
(setopt org-modern-block-name nil
org-modern-priority nil
org-modern-symbol "DejaVu Sans"
org-modern-todo nil
org-modern-tag nil
org-modern-timestamp nil)
:hook
(org-mode . org-modern-mode)
(org-agenda-finalize . org-modern-agenda))
(use-package org-noter
:after (org)
:config
(setopt org-noter-notes-search-path (list (concat org-directory "/roam")))
(org-noter-enable-org-roam-integration))
(use-package org-pomodoro
:after (org-clock)
:commands (org-pomodoro)
:config
;; (defun as/org-pomodoro-started-todo-update ()
;; "Update todo state when starting a pomodoro"
;; (when (or (string= org-state "NEXT")
;; (string= org-state "TODO"))
;; (org-todo "PROG")))
;; (defun as/org-todo-state-maybe-update-pomodoro ()
;; "Update or start a pomodoro when changing todo state
;; REVIEW: This could be updated to always trigger a pomodoro change, like when
;; changing state to PROG. This has the added benefit of making the above function
;; redundent, as I could just use `org-todo' as a single start and end point for
;; all pomodoros"
;; (when (and (or (string= org-state "TODO")
;; (string= org-state "DONE"))
;; (org-pomodoro-active-p))
;; (org-pomodoro-kill)))
;; (add-to-list 'org-after-todo-state-change-hook #'as/org-todo-state-change-maybe-kill-pomodoro)
;; (add-to-list 'org-pomodoro-started-hook #'as/org-pomodoro-started-todo-update)
(setopt alert-user-configuration ; Send mesages to libnotify
'((((:category . "org-pomodoro")) libnotify nil))
org-pomodoro-audio-player (executable-find "pw-cat")
org-pomodoro-keep-killed-pomodoro-time t
org-pomodoro-length 50
org-pomodoro-short-break-length 10
org-pomodoro-manual-break t)
:init
;; (defun as/org-pomodoro-todo-state-trigger ()
;; "Starts or stops a pomodoro when todo state changes"
;; (cond
;; ((when (string= org-state "PROG")
;; (if (org-pomodoro-active-p)
;; ((org-pomodoro-kill)
;; (org-pomodoro nil))
;; (org-pomodoro nil)))
;; ((when (and (or (string= org-state "DONE") (string= org-state "TODO"))
;; (org-pomodoro-active-p))
;; (org-pomodoro-kill))))))
;; (with-eval-after-load 'org-clock
;; (add-to-list 'org-after-todo-state-change-hook #'as/org-pomodoro-todo-state-trigger))
)
(use-package org-roam
:after (org)
:bind
(:map as/org-prefix-map
("r i" . org-roam-node-insert)
("r f" . org-roam-node-find)
("r c" . org-roam-capture)
;; REVIEW: Not sure if I really need these?
;; ("r b" . org-roam-buffer-toggle)
;; ("r d" . org-roam-buffer-display-dedicated)
;; ("r a a" . org-roam-alias-add)
;; ("r a r" . org-roam-alias-remove)
;; ("r r a" . org-roam-ref-add)
;; ("r r r" . org-roam-ref-remove)
)
:config
(setopt org-roam-database-connector 'sqlite-builtin)
(setq org-roam-db-gc-threshold most-positive-fixnum) ; doesn't like the new `setopt'
(add-to-list 'display-buffer-alist
'("\\*org-roam\\*"
(display-buffer-in-direction)
(direction . right)
(window-width . 0.33)
(window-height . fit-window-to-buffer)))
(add-to-list 'org-roam-capture-templates
'("r" "reference" plain
"%?"
:target
(file+head "references/${citar-citekey}.org"
"#+title: Notes on: ${note-title}\n")
:empty-lines 1
:unnarrowed t
))
(add-to-list 'org-roam-capture-templates
`("p" "project" plain (file ,(concat org-roam-directory
"/templates/projects.org"))
:target
(file+head "projects/%<%Y%m%d%H%M%S>-${slug}.org"
"#+title: ${title}\n#+filetags: projects")
:empty-lines 1
:unnarrowed t))
(org-roam-db-autosync-mode)
:ensure (org-roam :files (:defaults "extensions/*"))
:init
(setopt org-roam-directory (file-name-as-directory (expand-file-name "roam" org-directory))))
(use-package org-super-agenda
:hook (org-agenda-mode . org-super-agenda-mode)
:init
(setq org-agenda-custom-commands
'(("w" "Work agenda"
((agenda "" ((org-agenda-prefix-format " %?-12t %s")
(org-agenda-remove-tags t)
(org-agenda-skip-function '(org-agenda-skip-entry-if
'todo '("WONT")))
(org-agenda-span 'day)
(org-habit-show-habits nil)))
(alltodo "" ((org-agenda-overriding-header "")
(org-agenda-prefix-format " %?-12t %s")
(org-agenda-remove-tags t)
(org-super-agenda-groups
'((:discard
(:deadline future
:scheduled future
:category ("house" "me" "notes")))
(:name "Done"
:log state
:todo "DONE"
:order 90)
(:name "Overdue"
:deadline past
:scheduled past
:order 1)
(:name "Inbox"
:category ("inbox" "phone_inbox")
:order 9)
(:name "Important"
:priority "A"
:order 0)
(:name "In-Progress"
:todo "PROG"
:order 2)
(:name "Next"
:todo "NEXT"
:order 3)
(:name "Today"
:deadline today
:scheduled today
:time-grid t
:order 4)
(:name "Research"
:tag "research"
:order 7)
(:name "Project Backlog"
:and (:todo "TODO" :tag "projects")
:order 5)
(:name "General Backlog"
:and (:todo "TODO" :priority "B")
:order 8)
(:name "Less Important"
:priority<= "C"
:order 80)
))))))
("y" "My agenda"
((agenda "" ((org-agenda-prefix-format " %?-12t %s")
(org-agenda-remove-tags t)
(org-agenda-skip-function '(org-agenda-skip-entry-if
'todo '("WONT") 'regexp '("job")))
(org-agenda-span 3)))
(alltodo "" ((org-agenda-overriding-header "")
(org-agenda-prefix-format " %?-12t %s")
(org-agenda-remove-tags t)
(org-super-agenda-groups
'((:discard
(:not
(:category ("house" "me" "notes"))))
;; (:discard
;; (:deadline future :scheduled future))
(:name "Overdue"
:deadline past
:scheduled past
:order 1)
(:name "Upcoming"
:deadline future
:scheduled future
:order 99)
(:name "Inbox"
:category ("inbox" "phone_inbox")
:order 8)
(:name "Done"
:todo "DONE"
:order 99)
(:name "Important"
:priority "A"
:order 0)
(:name "In-Progress"
:todo "PROG"
:order 2)
(:name "Next"
:todo "NEXT"
:order 3)
(:name "Household"
:tag "chores"
:order 6)
(:name "Routine"
:and (:habit t :not (:tag "chores"))
:order 5)
(:name "Today"
:deadline today
:scheduled today
:time-grid t
:order 4)
;; (:name "Personal projects"
;; :categery "me"
;; :order 9)
(:name "Research"
:tag "research"
:order 7)
(:name "General Backlog"
:and (:todo "TODO" :priority "B")
:order 50)
(:name "Less Important"
:priority<= "C"
:order 85)
)))))))))
(use-package org-superstar
;; :disabled t
:config
(setopt org-indent-mode-turns-on-hiding-stars nil
org-superstar-headline-bullets-list '("" "🞛" "" "")
org-superstar-leading-bullet ?\s
org-superstar-special-todo-items t)
:hook (org-mode . org-superstar-mode))
(use-package org-timeblock
:bind
(:map as/org-prefix-map
("t" . org-timeblock))
:config
(setopt org-timeblock-new-task-time 'pick
org-timeblock-show-future-repeats 'next
org-timeblock-scale-options (cons 7 20)
org-timeblock-span 3))
(provide 'init-org)
;;; org-mode.el ends here