init-org.el (12996B)
1 ;;; init-org.el --- org-mode config -*- lexical-binding: t -*- 2 3 ;;; Commentary: 4 5 ;;; Code: 6 7 (use-package org 8 :hook 9 (org-mode . org-indent-mode) 10 (org-mode . visual-line-mode) 11 (org-mode . electric-pair-local-mode) 12 13 :init 14 (setq org-directory 15 (cond 16 (*is-windows* "h:/emacs/my-org-note") 17 (*is-mac* "~/org/my-org-note") 18 (*is-linux* "~/org/my-org-note") 19 (*is-android* "~/storage/shared/my-org-note"))) 20 21 (defvar my-blog-directory 22 (cond 23 (*is-windows* "h:/emacs/blog/posts") 24 (*is-mac* "~/org/blog/posts/") 25 (*is-linux* "~/org/blog/posts/") 26 (*is-android* "~/org/blog/posts/"))) 27 28 :config 29 (defun my-org-tab-complete () 30 (cond ((or (save-excursion 31 (beginning-of-line) 32 (looking-at-p "[ \t]*#\\+")) 33 (looking-back "\\[\\[\\*" 3)) 34 (let ((completion-at-point-functions '(pcomplete-completions-at-point t))) 35 (completion-at-point))) 36 ((or (org-at-heading-p) 37 (org-in-src-block-p)) 38 nil) 39 ((or (save-excursion 40 (backward-sexp) 41 (looking-at-p "=")) 42 (save-excursion 43 (backward-sexp) 44 (looking-at-p "~"))) 45 (let ((completion-at-point-functions '(cape-elisp-symbol cape-file t))) 46 (completion-at-point))) 47 (t nil))) 48 (add-hook 'org-cycle-tab-first-hook #'my-org-tab-complete) 49 50 (defvar org-hide-space-keywords 51 '(("\\cc\\( \\)[*/_=~+]\\cc.*?[*/_=~+]" 52 (0 (prog1 () (add-text-properties (match-beginning 1) (match-end 1) '(invisible t))))) 53 ("[*/_=~+].*?\\cc[*/_=~+]\\( \\)\\cc" 54 (0 (prog1 () (add-text-properties (match-beginning 1) (match-end 1) '(invisible t))))))) 55 (font-lock-add-keywords 'org-mode org-hide-space-keywords 'append) 56 57 (mapc 58 (lambda (kv) 59 (setf (alist-get (car kv) org-src-lang-modes nil nil #'equal) (cdr kv))) 60 '(("yaml" . yaml-ts) 61 ("json" . json-ts) 62 ("toml" . toml-ts))) 63 64 ;; show inline images 65 (setq org-startup-with-inline-images 'inlineimages) 66 67 ;; hide drawer contents 68 (setq org-startup-folded 'showall) 69 70 ;; log in drawer 71 (setq org-log-done t 72 org-log-into-drawer t) 73 74 ;; don't set bookmark 75 (setq org-bookmark-names-plist nil) 76 77 ;; todo keywords 78 (setq org-todo-keywords 79 (quote ((sequence "TODO(t)" "SOMEDAY(S)" "STARTED(s)" "WAITING(w)" "|" "DONE(d!/!)" "CANCELLED(c@/!)") 80 (sequence "IDKY(i)" "|" "KNOWN(k)" "CANCELLED(c@/!)") 81 (sequence "GAME(g)" "|" "PLAYED(p)")))) 82 83 ;; agenda 84 (setq org-agenda-files 85 `(,(concat org-directory "/20260509T232442==agenda--all-my-todos.org") 86 ,(concat org-directory "/20260810T233455==agenda--all-about-game__game.org"))) 87 88 (setq org-agenda-span 'day) 89 (setq org-agenda-skip-function-global 90 '(org-agenda-skip-entry-if 'todo '("COMMENT")))) 91 92 ;; optimize line wrapping in tables 93 (use-package phscroll 94 :hook 95 (org-mode . org-phscroll-activate) 96 :init 97 (setq org-startup-truncated nil)) 98 99 ;; denote 100 (use-package denote 101 :hook 102 (after-init . denote-rename-buffer-mode) 103 (dired-mode . denote-dired-mode) 104 :init 105 (defun my-denote-find-file (&optional arg) 106 "Find file use denote-file-prompt." 107 (interactive "P") 108 (if arg 109 (find-file (denote-file-prompt)) 110 (let ((denote-excluded-files-regexp "=journal\\|=archive")) 111 (find-file (denote-file-prompt))))) 112 113 (defun my-denote-open-metanote () 114 "Open denote metanote in org directory" 115 (interactive) 116 (find-file 117 (concat org-directory "/20260508T220745==metanote--all-my-metanotes__org.org"))) 118 119 (defun my-denote-find-backlink-with-location () 120 "Like `denote-find-backlink-with-location' but with consult preview." 121 (interactive) 122 (when-let* ((current-file buffer-file-name) 123 (id (or (denote-retrieve-filename-identifier current-file) 124 (user-error "The current file does not have a Denote identifier"))) 125 (files (denote-directory-files nil :omit-current :text-only)) 126 (fetcher (lambda () (xref-matches-in-files id files)))) 127 (consult-xref fetcher nil))) 128 129 (defun my-denote-org-find-backlink-for-heading-with-location () 130 "Like `denote-org-backlinks-for-heading' but with consult preview." 131 (interactive) 132 (unless (featurep 'denote-org) 133 (require 'denote-org)) 134 (when-let* ((heading-id (or (denote-org--get-file-id-and-heading-id-or-context) 135 (user-error "The current file does not have a denote identifier"))) 136 (files (denote-directory-files nil :omit-current :text-only)) 137 (fetcher (lambda () (xref-matches-in-files heading-id files)))) 138 (consult-xref fetcher nil))) 139 140 (setq denote-directory org-directory) 141 (setq denote-org-store-link-to-heading 'context 142 denote-prompts '(title signature keywords)) 143 (setq denote-title-history nil 144 denote-signature-history 145 '("note" "project" "fun" "wisdom" "article" "data" "metanote" "agenda" "journal" "archive") 146 denote-known-keywords 147 '("emacs")) 148 (with-eval-after-load 'savehist 149 (add-to-list 'savehist-ignored-variables 'denote-title-history))) 150 151 ;; denote-org 152 (use-package denote-org) 153 154 ;; denote-lint 155 (use-package denote-lint 156 :straight 157 (denote-lint :type git 158 :repo "https://git.trogloxene.org/denote-lint.git") 159 :config 160 (setq org-link-elisp-confirm-function nil)) 161 162 ;; denote-journal 163 (use-package denote-journal 164 :hook 165 (calendar-mode . denote-journal-calendar-mode) 166 :init 167 (defun my-denote-journal-path-to-existing-entry (&optional date interval) 168 "Return the path of current denote journal if it exists, otherwise return nil." 169 (require 'denote-journal) 170 (let* ((internal-date 171 (denote-journal--date-in-interval-p (or date (current-time)) interval)) 172 (files (denote-journal--get-entry internal-date interval))) 173 (if files 174 (denote-journal-select-file-prompt files)))) 175 176 (defun my-denote-journal-open-entry () 177 "Open current denote-journal entry if it exists." 178 (interactive) 179 (if (my-denote-journal-path-to-existing-entry) 180 (find-file (my-denote-journal-path-to-existing-entry)) 181 (message "No journal for today yet"))) 182 183 (setq denote-journal-directory (expand-file-name "journal" denote-directory)) 184 (setq denote-journal-keyword nil) 185 (setq denote-journal-signature "journal") 186 (setq denote-journal-keyword "daily")) 187 188 ;; denote-explore 189 (use-package denote-explore) 190 191 ;; consult-denote 192 (use-package consult-denote 193 :hook 194 (after-init . consult-denote-mode)) 195 196 ;; org-download 197 (use-package org-download 198 :after org 199 :demand t 200 :config 201 (setq-default org-download-image-dir "./images/" 202 org-download-heading-lvl nil) 203 (setq org-download-dragndrop t 204 org-download-method 'directory 205 org-image-actual-width nil 206 org-download-image-html-width 600 207 org-return-follows-link t)) 208 209 ;; org-ql 210 (use-package org-ql) 211 212 ;; org-super-agenda 213 (use-package org-super-agenda 214 :config 215 (org-super-agenda-mode)) 216 217 ;; agenda 218 (use-package org-agenda 219 :straight nil 220 :hook 221 (org-agenda-finalize . disable-truncate-lines) 222 :config 223 (setq org-agenda-prefix-format '((agenda . " %?-12t% s") 224 (todo . " ") 225 (tags . " ") 226 (search . " "))) 227 228 (setq org-agenda-sorting-strategy 229 '((agenda time-up scheduled-up deadline-up priority-down category-keep) 230 (todo priority-down category-keep) 231 (tags priority-down category-keep) 232 (search category-keep))) 233 234 (setq org-agenda-custom-commands 235 '(("qd" "TODO entries sort by closed time" 236 ((org-ql-block '(closed) 237 ((org-ql-block-header "Closed TODOs") 238 (org-super-agenda-groups 239 '((:auto-ts t))))))) 240 ("qS" "SOMEDAYs" 241 ((org-ql-block '(todo "SOMEDAY") 242 ((org-ql-block-header "SOMEDAYs"))))) 243 ("qs" "STARTEDs" 244 ((org-ql-block '(todo "STARTED") 245 ((org-ql-block-header "STARTEDs"))))) 246 ("qg" "GAMEs" 247 ((org-ql-block '(todo "GAME") 248 ((org-ql-block-header "GAMEs"))))) 249 ("qp" "PLAYEDs" 250 ((org-ql-block '(todo "PLAYED") 251 ((org-ql-block-header "Closed TODOs") 252 (org-super-agenda-groups 253 '((:auto-ts t))))))) 254 ("qt" "TODOs sort by start time" 255 ((org-ql-block '(todo) 256 ((org-ql-block-header "TODOs") 257 (org-super-agenda-groups 258 '((:auto-ts t))))))) 259 ("qa" "all TODO entries" 260 ((org-ql-block '(and (not (done)) (todo)) 261 ((org-ql-block-header "all TODOs") 262 (org-super-agenda-groups 263 '((:name "started" :todo "STARTED") 264 (:name "waiting" :todo "WAITING") 265 (:name "priority = A" :priority "A") 266 (:name "priority = B" :priority "B") 267 (:name "priority = C" :priority "C") 268 (:name "other priority" :priority< "C") 269 (:name "someday" :todo "SOMEDAY") 270 (:name "I don't know yet" :todo "IDKY") 271 (:name "game" :todo "GAME")))))))))) 272 273 ;; capture 274 (use-package org-capture 275 :straight nil 276 :init 277 (setq my-org-capture-file (concat org-directory "/20260509T232442==agenda--all-my-todos.org")) 278 (setq my-org-capture-game-file (concat org-directory "/20260810T233455==agenda--all-about-game__game.org")) 279 :config 280 (setq org-capture-templates 281 `(("t" "TODO" entry 282 (file+headline ,my-org-capture-file "Something to do") 283 "* TODO %<%m-%d> %?\n%T" :empty-lines 1) 284 ("s" "STARTED" entry 285 (file+headline ,my-org-capture-file "Something to do") 286 "* STARTED %<%m-%d> %?\n%T" :empty-lines 1) 287 ("S" "SOMEDAY" entry 288 (file+headline ,my-org-capture-file "Something to do") 289 "* SOMEDAY %<%m-%d> %?\n%T" :empty-lines 1) 290 ("i" "IDKY" entry 291 (file+headline ,my-org-capture-file "Something to know") 292 "* IDKY %<%m-%d> %?\n%T" :empty-lines 1) 293 ("g" "GAME" entry 294 (file+headline ,my-org-capture-game-file "Games") 295 "* GAME %?\n%T" :empty-lines 1)))) 296 297 ;; presentation 298 (use-package org-tree-slide 299 :init 300 (defun my-org-tree-slide-start () 301 "Start `org-tree-slide'." 302 (interactive) 303 (when (eq major-mode 'org-mode) 304 (setq-local header-line-format nil 305 mode-line-format nil 306 cursor-type 'hbar 307 olivetti-body-width 100) 308 (blink-cursor-mode -1) 309 (cnfonts-increase-fontsize 5) 310 (hl-line-mode 'toggle) 311 (read-only-mode 1) 312 (jinx-mode -1) 313 (org-tree-slide-mode 1))) 314 315 (defun my-org-tree-slide-stop () 316 "Stop `org-tree-slide'." 317 (interactive) 318 (when (and (eq major-mode 'org-mode) (memq 'org-tree-slide-mode local-minor-modes)) 319 (org-mode-restart) 320 (blink-cursor-mode 1) 321 (cnfonts-decrease-fontsize 5) 322 (hl-line-mode 1) 323 (read-only-mode -1) 324 (jinx-mode 1) 325 (org-tree-slide-mode -1)))) 326 327 ;; Chinese calendar 328 (use-package cal-china-x 329 :after calendar 330 :autoload cal-china-x-setup 331 :init 332 (cal-china-x-setup) 333 :config 334 (setq calendar-mark-holidays-flag t 335 cal-china-x-important-holidays cal-china-x-chinese-holidays 336 cal-china-x-general-holidays '((holiday-lunar 1 15 "元宵节") 337 (holiday-lunar 7 7 "七夕节") 338 (holiday-fixed 3 8 "妇女节") 339 (holiday-fixed 3 12 "植树节") 340 (holiday-fixed 5 4 "青年节") 341 (holiday-fixed 6 1 "儿童节") 342 (holiday-fixed 9 10 "教师节")) 343 holiday-other-holidays '((holiday-fixed 2 14 "情人节") 344 (holiday-fixed 4 1 "愚人节") 345 (holiday-fixed 12 25 "圣诞节") 346 (holiday-fixed 6 7 "高考") 347 (holiday-float 5 0 2 "母亲节") 348 (holiday-float 6 0 3 "父亲节") 349 (holiday-float 11 4 4 "感恩节")) 350 calendar-holidays (append cal-china-x-important-holidays 351 cal-china-x-general-holidays 352 holiday-other-holidays))) 353 354 (provide 'init-org) 355 ;;; init-org.el ends here