summaryrefslogtreecommitdiff
path: root/modules/org-config.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-10-12 11:47:26 -0500
committerCraig Jennings <c@cjennings.net>2025-10-12 11:47:26 -0500
commit092304d9e0ccc37cc0ddaa9b136457e56a1cac20 (patch)
treeea81999b8442246c978b364dd90e8c752af50db5 /modules/org-config.el
changing repositories
Diffstat (limited to 'modules/org-config.el')
-rw-r--r--modules/org-config.el267
1 files changed, 267 insertions, 0 deletions
diff --git a/modules/org-config.el b/modules/org-config.el
new file mode 100644
index 00000000..524ff290
--- /dev/null
+++ b/modules/org-config.el
@@ -0,0 +1,267 @@
+;;; org-config --- Settings and Enhancements to Org Mode -*- lexical-binding: t; coding: utf-8; -*-
+;; author Craig Jennings <c@cjennings.net>
+;;; Commentary:
+
+;; Setting org-modules to org-protocol, ol-eww, ol-w3m, and ol-info removes
+;; several modules that org would otherwise load automatically.
+
+;;; Code:
+
+;; ------------------------------- Org Constants -------------------------------
+
+;; note: some constants used here are defined in init.el
+(defvar org-archive-location
+ (concat sync-dir "/archives/archive.org::datetree/")
+ "Location of the archive file.
+
+The archive file is where org entries that are archived via
+org-archive-subtree-default are placed.")
+
+;; ---------------------------- Org General Settings ---------------------------
+
+(defun cj/org-general-settings ()
+ "All general \='org-mode\=' settings are grouped and set in this function."
+
+ ;; Unbind org-cycle-agenda-files keys for use elsewhere
+ (unbind-key "C-'" org-mode-map)
+ (unbind-key "C-," org-mode-map)
+
+ ;; ORG-MODULES
+ ;; enable recognition of org-protocol:// as a parameter
+ ;; add org-habits
+ (require 'org-protocol)
+ (setq org-modules '(org-protocol ol-eww ol-w3m ol-info org-habit))
+
+ ;; GENERAL
+ (setq org-startup-folded t) ;; all org files should start in the folded state
+ (setq org-cycle-open-archived-trees t) ;; re-enable opening headings with archive tags with TAB
+ (setq org-outline-path-complete-in-steps nil)
+ (setq org-return-follows-link t) ;; hit return to follow an org-link
+ (setq org-list-allow-alphabetical t) ;; allow alpha ordered lists (i.e., a), A), a., etc.)
+
+ ;; INDENTATION
+ (setq org-startup-indented t) ;; load org files indented
+ (setq org-adapt-indentation t) ;; adapt indentation to outline node level
+ (setq org-indent-indentation-per-level 2) ;; indent two character-widths per level
+ (setq tab-width 8) ;; org-mode complains when tabs aren't @ 8
+
+ ;; IMAGES / MEDIA
+ (setq org-startup-with-inline-images t) ;; preview images by default
+ (setq org-image-actual-width '(500)) ;; keep image sizes in check
+ (setq org-yank-image-save-method 'attach) ;; attach images; save to data directory
+
+
+ (setq org-bookmark-names-plist nil) ;; don't set org-capture bookmarks
+
+ ;; force pdfs exported from org to open in emacs
+ (add-to-list 'org-file-apps '("\\.pdf\\'" . emacs)))
+
+;; -------------------------- Org Appearance Settings --------------------------
+
+(defun cj/org-appearance-settings()
+ "Set foreground, background, and font styles for org mode."
+ (interactive)
+ ;; org-hide should use fix-pitch to align indents for proportional fonts
+ (set-face-attribute 'org-hide nil :inherit 'fixed-pitch)
+ (set-face-attribute 'org-meta-line nil :inherit 'shadow)
+
+ ;; Remove foreground and background from block faces
+ (set-face-attribute 'org-block nil :foreground 'unspecified :background 'unspecified)
+ (set-face-attribute 'org-block-begin-line nil :foreground 'unspecified :background 'unspecified)
+ (set-face-attribute 'org-block-end-line nil :foreground 'unspecified :background 'unspecified)
+
+ ;; Get rid of the background on column views
+ (set-face-attribute 'org-column nil :background 'unspecified)
+ (set-face-attribute 'org-column-title nil :background 'unspecified)
+
+ ;; make sure org-links are underlined
+ (set-face-attribute 'org-link nil :underline t)
+
+ (setq org-ellipsis " ▾") ;; change ellipses to down arrow
+ (setq org-hide-emphasis-markers t) ;; remove emphasis markers to keep the screen clean
+ (setq org-hide-leading-stars t) ;; hide leading stars, just show one per line
+ (setq org-pretty-entities t) ;; render special symbols
+ (setq org-pretty-entities-include-sub-superscripts nil) ;; ...except superscripts and subscripts
+ (setq org-fontify-emphasized-text nil) ;; ...and don't render bold and italic markup
+ (setq org-fontify-whole-heading-line t) ;; fontify the whole line for headings (for face-backgrounds)
+ (add-hook 'org-mode-hook 'prettify-symbols-mode))
+
+;; ----------------------------- Org TODO Settings ---------------------------
+
+(defun cj/org-todo-settings ()
+ "All org-todo related settings are grouped and set in this function."
+
+ ;; logging task creation, task start, and task resolved states
+ (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-treat-insert-todo-heading-as-state-change nil) ;; log task creation
+ (setq org-log-into-drawer nil) ;; log into the drawer
+ (setq org-log-done nil) ;; don't log completions
+ (setq org-habit-graph-column 75) ;; allow space for task name
+
+ ;; inherit parents properties (sadly not schedules or deadlines)
+ (setq org-use-property-inheritance t))
+
+;; ---------------------------------- Org Mode ---------------------------------
+
+(use-package org
+ :defer .5
+ :ensure nil ;; use the built-in package
+ :pin manual ;; never upgrade from the version built-into Emacs
+ :preface
+ ;; create an org-table-map so we can use C-c t as prefix
+ (define-prefix-command 'org-table-map)
+ (global-set-key (kbd "C-c T") 'org-table-map)
+ :bind
+ ("C-c c" . org-capture)
+ ("C-c a" . org-agenda)
+ (:map org-mode-map
+ ("C-c I" . org-table-field-info) ;; was C-c ?
+ ("C-\\" . org-match-sparse-tree)
+ ("C-c t" . org-set-tags-command)
+ ("C-c l" . org-store-link)
+ ("C-c C-l" . org-insert-link)
+ ("s-<up>" . org-priority-up)
+ ("s-<down>" . org-priority-down)
+ ("C-c N" . org-narrow-to-subtree)
+ ("C-c >" . cj/org-narrow-forward)
+ ("C-c <" . cj/org-narrow-backwards)
+ ("<f5>" . org-reveal)
+ ("C-c <ESC>" . widen))
+ (:map org-table-map
+ ("r i" . org-table-insert-row)
+ ("r d" . org-table-kill-row)
+ ("c i" . org-table-insert-column)
+ ("c d" . org-table-delete-column))
+
+ ;; backward and forward day are ',' and '.'
+ ;; shift & meta moves by week or year
+ ;; C-. jumps to today
+ ;; original keybindings blocked by windmove keys
+ ;; these are consistent with plain-old calendar mode
+ (:map org-read-date-minibuffer-local-map
+ ("," . (lambda () (interactive)
+ (org-eval-in-calendar '(calendar-backward-day 1))))
+ ("." . (lambda () (interactive)
+ (org-eval-in-calendar '(calendar-forward-day 1))))
+ ("<" . (lambda () (interactive)
+ (org-eval-in-calendar '(calendar-backward-month 1))))
+ (">" . (lambda () (interactive)
+ (org-eval-in-calendar '(calendar-forward-month 1))))
+ ("M-," . (lambda () (interactive)
+ (org-eval-in-calendar '(calendar-backward-year 1))))
+ ("M-." . (lambda () (interactive)
+ (org-eval-in-calendar '(calendar-forward-year 1)))))
+
+ :init
+ ;; windmove's keybindings conflict with org-agenda-todo-nextset/previousset keybindings
+ ;; solution: map the super key so that
+ ;; - super up/down increases and decreases the priority
+ ;; - super left/right changes the todo state
+ (setq org-replace-disputed-keys t)
+ (custom-set-variables
+ '(org-disputed-keys
+ '(([(shift left)] . [(super left)])
+ ([(shift right)] . [(super right)])
+ ([(shift up)] . [(super up)])
+ ([(shift down)] . [(super down)])
+ ([(control shift right)] . [(meta shift +)])
+ ([(control shift left)] . [(meta shift -)]))))
+
+ (defun cj/org-narrow-forward ()
+ "Narrow to the next subtree at the same level."
+ (interactive)
+ (widen)
+ (org-forward-heading-same-level 1)
+ (org-narrow-to-subtree))
+
+ (defun cj/org-narrow-backwards ()
+ "Narrow to the previous subtree at the same level."
+ (interactive)
+ (widen)
+ (org-backward-heading-same-level 1)
+ (org-narrow-to-subtree))
+
+ :hook
+ (org-mode . flyspell-mode)
+ (org-mode . turn-on-visual-line-mode)
+ (org-mode . org-indent-mode)
+
+ :config
+ ;; bug workaround for org-element--get-category: Invalid function: org-element-with-disabled-cache
+ ;; https://github.com/doomemacs/doomemacs/issues/7347
+ ;;(load-library "org-element.el")
+
+ (cj/org-general-settings)
+ (cj/org-appearance-settings)
+ (cj/org-todo-settings))
+
+
+;; ------------------------------- Org Superstar -------------------------------
+
+;; nicer bullets than simple asterisks.
+(use-package org-superstar
+ :after org
+ :config
+ (org-superstar-configure-like-org-bullets)
+ (setq org-superstar-leading-bullet ?\s)
+ (add-hook 'org-mode-hook (lambda () (org-superstar-mode 1))))
+
+;; ------------------------------- Org-Checklist -------------------------------
+;; needed for org-habits to reset checklists once task is complete
+;; this was a part of org-contrib which was deprecated
+
+(use-package org-checklist
+ :ensure nil ;; in custom folder
+ :after org
+ :load-path "custom/org-checklist.el")
+
+;; -------------------------- Org Link To Current File -------------------------
+;; get a link to the file the current buffer is associated with.
+
+(defun cj/org-link-to-current-buffer-file ()
+ "Create an Org mode link to the current file and copy it to the clipboard.
+
+The link is formatted as [[file:<file-path>][<file-name>]],
+where <file-path> is the full path to the current file and <file-name>
+is the name of the current file without any directory information.
+
+If the current buffer is not associated with a file, the function will throw an
+error."
+ (interactive)
+ (if (buffer-file-name)
+ (let* ((filename (buffer-file-name))
+ (description (file-name-nondirectory filename))
+ (link (format "[[file:%s][%s]]" filename description)))
+ (kill-new link)
+ (message "Copied Org link to current file to clipboard: %s" link))
+ (user-error "Buffer isn't associated with a file, so no link sent to clipboard")))
+
+(provide 'org-config)
+;;; org-config.el ends here