.emacs.d

the most bloated Emacs config on this planet
git clone https://git.trogloxene.org/.emacs.d.git
Log | Files | Refs

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