312 lines
12 KiB
EmacsLisp
Executable File
312 lines
12 KiB
EmacsLisp
Executable File
;;; syd-org.el -*- lexical-binding: t; -*-
|
|
|
|
(require 'syd-prose)
|
|
|
|
(defun syd-org--init-hacks-h ()
|
|
;; Open file links in current window, rather than new ones
|
|
(setf (alist-get 'file org-link-frame-setup) #'find-file)
|
|
;; Open directory links in dired
|
|
(add-to-list 'org-file-apps '(directory . emacs))
|
|
(add-to-list 'org-file-apps '(remote . emacs))
|
|
|
|
(defun syd-org--restart-mode-h ()
|
|
"Restart `org-mode', but only once."
|
|
(syd-quietly (org-mode-restart))
|
|
(setq org-agenda-new-buffers
|
|
(delq (current-buffer)
|
|
org-agenda-new-buffers))
|
|
(run-hooks 'find-file-hook))
|
|
|
|
(syd-add-hook 'org-agenda-finalize-hook
|
|
(defun syd-org-exclude-agenda-buffers-from-workspace-h ()
|
|
"Don't associate temporary agenda buffers with current workspace."
|
|
(when (and org-agenda-new-buffers
|
|
(bound-and-true-p persp-mode)
|
|
(not org-agenda-sticky))
|
|
(let (persp-autokill-buffer-on-remove)
|
|
(persp-remove-buffer org-agenda-new-buffers
|
|
(get-current-persp)
|
|
nil)))))
|
|
|
|
(syd-defadvice syd-org--restart-mode-before-indirect-buffer-a (&optional buffer _)
|
|
"Restart `org-mode' in buffers in which the mode has been deferred (see
|
|
`syd-org-defer-mode-in-agenda-buffers-h') before they become the base buffer for an
|
|
indirect org-cpature buffer. This ensures that the buffer is fully functional
|
|
not only when the *user* visits it, but also when org-capture interacts with it
|
|
via an indirect buffer."
|
|
:before #'org-capture-get-indirect-buffer
|
|
(with-current-buffer (or buffer (current-buffer))
|
|
(when (memq #'syd-org--restart-mode-h on-switch-buffer-hook)
|
|
(syd-org--restart-mode-h))))
|
|
|
|
(defvar recentf-exclude)
|
|
|
|
(syd-defadvice syd-org--optimize-backgrounded-agenda-buffers-a (fn file)
|
|
"Disable `org-mode's startup processes for temporary agenda buffers.
|
|
|
|
Prevents recentf pollution as well. However, if the user tries to visit one of
|
|
these buffers they'll see a gimped, half-broken org buffer, so to avoid that,
|
|
install a hook to restart `org-mode' when they're switched to so they can grow
|
|
up to be fully-fledged org-mode buffers."
|
|
:around #'org-get-agenda-file-buffer
|
|
(if-let* ((buf (org-find-base-buffer-visiting file)))
|
|
buf
|
|
(let ((recentf-exclude '(always))
|
|
;; (doom-inhibit-large-file-detection t)
|
|
;; (doom-inhibit-local-var-hooks t)
|
|
(org-inhibit-startup t)
|
|
vc-handled-backends
|
|
enable-local-variables
|
|
find-file-hook)
|
|
(when-let ((buf (delay-mode-hooks (funcall fn file))))
|
|
(with-current-buffer buf
|
|
(add-hook 'on-switch-buffer-hook #'syd-org--restart-mode-h
|
|
nil 'local))
|
|
buf))))
|
|
|
|
(syd-defadvice syd-org--fix-inconsistent-uuidgen-case-a (uuid)
|
|
"Ensure uuidgen is always lowercase (consistent) regardless of system.
|
|
See https://lists.gnu.org/archive/html/emacs-orgmode/2019-07/msg00081.html."
|
|
:filter-return #'org-id-new
|
|
(if (eq org-id-method 'uuid)
|
|
(downcase uuid)
|
|
uuid)))
|
|
|
|
(defun syd-org-init-theme ()
|
|
(require 'syd-kanagawa)
|
|
(let* ((hl `(:weight bold))
|
|
(fg (lambda (c) `(:foreground ,(syd-kanagawa-get c))))
|
|
(bg (lambda (c) `(:background ,(syd-kanagawa-get c))))
|
|
(block-delim `(:foreground unspecified
|
|
:inherit font-lock-comment-face
|
|
:extend t
|
|
,@(funcall bg 'sumi-ink-0)
|
|
:height 0.75))
|
|
(keyword '(:background unspecified :foreground unspecified
|
|
:inherit (fixed-pitch font-lock-comment-face)
|
|
:height 0.9)))
|
|
(setq org-src-block-faces
|
|
`(("jupyter-apl" syd-apl)))
|
|
(custom-theme-set-faces
|
|
'user
|
|
`(org-document-title ((t (,@hl :height 1.60))))
|
|
`(org-document-info ((t (,@hl :height 1.0))))
|
|
`(org-document-info-keyword ((t ,keyword)))
|
|
`(org-meta-line ((t ,keyword)))
|
|
`(org-level-1 ((t (,@hl :height 1.40 ,@(funcall fg 'oni-violet)))))
|
|
`(org-level-2 ((t (,@hl :height 1.35 ,@(funcall fg 'crystal-blue)))))
|
|
`(org-level-3 ((t (,@hl :height 1.30 ,@(funcall fg 'spring-violet-2)))))
|
|
`(org-level-4 ((t (,@hl :height 1.25 ,@(funcall fg 'light-blue)))))
|
|
`(org-level-5 ((t (,@hl :height 1.20 ,@(funcall fg 'wave-aqua-2)))))
|
|
`(org-level-6 ((t (,@hl :height 1.15 ,@(funcall fg 'spring-green)))))
|
|
`(org-level-7 ((t (,@hl :height 1.10 ,@(funcall fg 'boat-yellow-1)))))
|
|
`(org-level-8 ((t (,@hl :height 1.05 ,@(funcall fg 'boat-yellow-2)))))
|
|
`(org-block-begin-line ((t ,block-delim)))
|
|
`(org-block-end-line ((t ,block-delim)))
|
|
'(org-ellipsis ((t (:height 1.0))))
|
|
;; It is important that the `org-indent' face uses a fixed-pitch font, lest
|
|
;; e.g. multi-line bullets appear misaligned.
|
|
'(org-indent ((t (:inherit (org-hide syd-alt-fixed-pitch)))))
|
|
;; Must be fixed-pitch; `[ ]` and `[X]' should be the same width.
|
|
'(org-checkbox ((t (:inherit fixed-pitch))))
|
|
`(org-drawer ((t ,block-delim)))
|
|
'(org-property-value ((t (:inherit fixed-pitch))))
|
|
'(org-special-keyword ((t (:inherit (font-lock-comment-face fixed-pitch)))))
|
|
`(org-block ((t (:inherit fixed-pitch
|
|
,@(funcall bg 'sumi-ink-2)))))
|
|
'(org-code ((t (:inherit (shadow fixed-pitch))))))))
|
|
|
|
(evil-define-command syd-org-yank-link (register)
|
|
(interactive "<x>")
|
|
(if-let* ((url (thing-at-point 'url)))
|
|
(progn (evil-set-register (or register ?\") url)
|
|
(message "Yanked link: %s" url))
|
|
(message "No URL at point")))
|
|
|
|
(defun syd-org-init-keybinds ()
|
|
(general-def
|
|
:keymaps 'org-mode-map
|
|
:states '(insert emacs)
|
|
[tab] #'org-cycle
|
|
[C-M-return] #'org-insert-subheading)
|
|
(general-def
|
|
:prefix-map 'syd-org-mode-links-map
|
|
"l" #'org-insert-link
|
|
"y" #'syd-org-yank-link)
|
|
(general-define-key
|
|
:keymaps 'org-mode-map
|
|
:states '(normal visual motion emacs insert)
|
|
:major-modes t
|
|
:prefix syd-localleader-key
|
|
:non-normal-prefix syd-alt-localleader-key
|
|
"." #'consult-org-heading
|
|
"/" #'consult-org-agenda
|
|
"@" #'org-cite-insert
|
|
"e" #'org-export-dispatch
|
|
"f" #'org-footnote-action
|
|
"h" #'org-toggle-heading
|
|
"i" #'org-toggle-item
|
|
"I" #'org-id-get-create
|
|
"k" #'org-babel-remove-result
|
|
"l" `("Links" . ,syd-org-mode-links-map)
|
|
"t" #'org-todo))
|
|
|
|
(use-package org
|
|
:defer-incrementally
|
|
calendar find-func format-spec org-macs org-compat org-faces org-entities
|
|
org-list org-pcomplete org-src org-footnote org-macro ob org org-agenda
|
|
org-capture
|
|
:init
|
|
;; HACK: Face specs fed directly to `org-todo-keyword-faces' don't respect
|
|
;; underlying faces like the `org-todo' face does, so we define our own
|
|
;; intermediary faces that extend from org-todo.
|
|
(with-no-warnings
|
|
(custom-declare-face 'syd-org-todo-active
|
|
'((t (:inherit (bold font-lock-constant-face org-todo)))) "")
|
|
(custom-declare-face 'syd-org-todo-project
|
|
'((t (:inherit (bold font-lock-doc-face org-todo)))) "")
|
|
(custom-declare-face 'syd-org-todo-onhold
|
|
'((t (:inherit (bold warning org-todo)))) "")
|
|
(custom-declare-face 'syd-org-todo-cancel
|
|
'((t (:inherit (bold error org-todo)))) ""))
|
|
:custom ((org-startup-folded 'content)
|
|
(org-directory "~/org")
|
|
;; Stay out of my config dir!
|
|
(org-id-locations-file (file-name-concat syd-cache-dir
|
|
"org-id-locations"))
|
|
;; New headings should be inserted /after/ the heading's contents.
|
|
(org-insert-heading-respect-content t)
|
|
;; Hide markup syntax and leave the markup.
|
|
(org-hide-emphasis-markers t)
|
|
(org-ellipsis " […]")
|
|
(org-todo-keywords
|
|
'((sequence
|
|
"TODO(t)" ; A task that needs doing & is ready to do
|
|
"PROJ(p)" ; A project, which usually contains other tasks
|
|
"STRT(s)" ; A task that is in progress
|
|
"WAIT(w)" ; Something external is holding up this task
|
|
"HOLD(h)" ; This task is paused/on hold because of me
|
|
"IDEA(i)" ; An unconfirmed and unapproved task or notion
|
|
"|"
|
|
"DONE(d)" ; Task successfully completed
|
|
"KILL(k)"))) ; Task was cancelled, aborted, or is no longer
|
|
; applicable
|
|
(org-todo-keyword-faces
|
|
'(("[-]" . syd-org-todo-active)
|
|
("STRT" . syd-org-todo-active)
|
|
("WAIT" . syd-org-todo-onhold)
|
|
("HOLD" . syd-org-todo-onhold)
|
|
("PROJ" . syd-org-todo-project)
|
|
("KILL" . syd-org-todo-cancel))))
|
|
:preface
|
|
;; Speed up initialisation by disabling modules we don't need.
|
|
(defvar org-modules
|
|
'(;; ol-w3m
|
|
;; ol-bbdb
|
|
ol-bibtex
|
|
;; ol-docview
|
|
;; ol-gnus
|
|
;; ol-info
|
|
;; ol-irc
|
|
;; ol-mhe
|
|
;; ol-rmail
|
|
;; ol-eww
|
|
))
|
|
:config
|
|
(syd-add-hook 'org-mode-hook
|
|
#'org-indent-mode
|
|
#'syd-prose-mode)
|
|
(syd-org-init-theme)
|
|
(syd-org-init-keybinds))
|
|
|
|
(use-package org-appear
|
|
:hook (org-mode . org-appear-mode)
|
|
:custom (org-appear-autoemphasis t))
|
|
|
|
;; Unlike those appearing in `syd-org--init-roam-keybinds', these should be
|
|
;; available even outside of Org-mode.
|
|
(general-def
|
|
:prefix-map 'syd-leader-notes-roam-map
|
|
"f" #'org-roam-node-find)
|
|
|
|
(defun syd-org--init-roam-keybinds ()
|
|
(general-def
|
|
:prefix-map 'syd-org-roam-mode-map)
|
|
(general-def
|
|
:prefix-map 'syd-leader-notes-map
|
|
"r" `("Org-roam" . ,syd-leader-notes-roam-map))
|
|
(general-define-key
|
|
:keymaps 'org-mode-map
|
|
:states '(normal visual motion emacs insert)
|
|
:major-modes t
|
|
:prefix syd-localleader-key
|
|
:non-normal-prefix syd-alt-localleader-key
|
|
"m" `("Org-roam" . ,syd-org-roam-mode-map)))
|
|
|
|
(use-package org-roam
|
|
:hook (org-load . syd-org-init-roam-h)
|
|
:commands (org-roam-buffer-toggle-display
|
|
org-roam-dailies-find-date
|
|
org-roam-dailies-find-today
|
|
org-roam-dailies-find-tomorrow
|
|
org-roam-dailies-find-yesterday)
|
|
:init (progn (syd-org--init-roam-keybinds)
|
|
(syd-load-packages-incrementally
|
|
'(ansi-color dash f rx seq magit-section emacsql)))
|
|
:custom ((org-roam-directory org-directory)
|
|
(org-roam-db-location (file-name-concat syd-data-dir
|
|
"org-roam.db"))
|
|
;; Make org-roam buffer sticky; i.e. don't replace it when opening a
|
|
;; file with an *-other-window command.
|
|
(org-roam-buffer-window-parameters '((no-delete-other-windows . t)))
|
|
(org-roam-completion-everywhere t))
|
|
:config
|
|
(defun syd-org-init-roam-h ()
|
|
"Setup `org-roam' but don't immediately initialize its database. Instead,
|
|
initialize it when it will be actually needed."
|
|
(cl-letf (((symbol-function #'org-roam-db-sync) #'ignore))
|
|
(org-roam-db-autosync-enable)))
|
|
|
|
(syd-org--init-roam-keybinds)
|
|
|
|
(syd-defadvice syd-org-roam-try-init-db-a (&rest _)
|
|
"Try to initialize org-roam database at the last possible safe moment.
|
|
In case of failure, fail gracefully."
|
|
:before #'org-roam-db-query
|
|
(message "Initializing org-roam database...")
|
|
(advice-remove 'org-roam-db-query #'syd-org-roam-try-init-db-a)
|
|
(org-roam-db-sync)))
|
|
|
|
(use-package evil-org
|
|
:hook ((org-mode . evil-org-mode)
|
|
(org-capture-mode . evil-insert-state))
|
|
:init
|
|
(defvar evil-org-retain-visual-state-on-shift t)
|
|
(defvar evil-org-special-o/O '(table-row))
|
|
(defvar evil-org-use-additional-insert t))
|
|
|
|
;; (use-package evil-org-agenda
|
|
;; :hook (org-agenda-mode . evil-org-agenda-mode)
|
|
;; :config
|
|
;; (evil-org-agenda-set-keys)
|
|
;; ;; Stay away from my leader key!
|
|
;; (evil-define-key* 'motion evil-org-agenda-mode-map
|
|
;; (kbd syd-leader-key) nil))
|
|
|
|
(use-package hide-mode-line
|
|
:hook (org-mode . hide-mode-line-mode))
|
|
|
|
(use-package org-superstar
|
|
:hook (org-mode . org-superstar-mode)
|
|
:custom ((org-superstar-headline-bullets-list '(9675))
|
|
(org-superstar-item-bullet-alist '((?- . ?•)
|
|
(?+ . ?➤)
|
|
(?* . ?⋆))))
|
|
:config
|
|
(custom-theme-set-faces
|
|
'user
|
|
`(org-superstar-header-bullet ((t (:font ,syd-alt-fixed-pitch-font))))))
|
|
|
|
(provide 'syd-org)
|
|
;;; syd-org.el ends here
|