698 lines
24 KiB
EmacsLisp
698 lines
24 KiB
EmacsLisp
;;; org-custom.el --- Org-mode configuration -*- lexical-binding: t -*-
|
||
|
||
;; This file is not part of GNU Emacs
|
||
|
||
;; This program is free software: you can redistribute it and/or modify
|
||
;; it under the terms of the GNU General Public License as published by
|
||
;; the Free Software Foundation, either version 3 of the License, or
|
||
;; (at your option) any later version.
|
||
|
||
;; This program is distributed in the hope that it will be useful,
|
||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
;; GNU General Public License for more details.
|
||
|
||
;; You should have received a copy of the GNU General Public License
|
||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
||
|
||
;;; Commentary:
|
||
|
||
;; commentary
|
||
|
||
;;; Code:
|
||
|
||
(require 'org)
|
||
(require 'org-agenda)
|
||
(require 'org-attach)
|
||
(require 'transient)
|
||
(require 'subr-x)
|
||
|
||
(defun org-mode-init ()
|
||
"This is called through `org-mode-hook', so that I don't need to `add-hook' 20 million times."
|
||
;; I want org to display pictures inline.
|
||
(org-display-inline-images)
|
||
;; I don't want monospace text by default.
|
||
(variable-pitch-mode)
|
||
)
|
||
|
||
(add-hook 'org-mode-hook #'org-mode-init)
|
||
|
||
(defcustom theurgy-org-directory "~/.org/"
|
||
"The directory for all theurgy org-mode files."
|
||
:type 'string
|
||
:group 'theurgy
|
||
:group 'theurgy-org)
|
||
|
||
;; Change a bunch of default org-mode variables.
|
||
(setq org-log-done nil ;; I want to keep track of the time tasks are completed.
|
||
org-return-follows-link t ;; I want to be able to follow links easily.
|
||
org-hide-emphasis-markers t ;; This is a big one: hide markup syntax like ** and //.
|
||
org-pretty-entities t ;; These two variables together render latex entities as UTF8, which means that Greek letters, subscript, and superscript are all rendered correctly.
|
||
org-pretty-entities-include-sub-superscripts t
|
||
org-enforce-todo-dependencies t ;; Prevent changing a parent to DONE if the children aren't
|
||
org-enforce-todo-checkbox-dependencies t
|
||
org-agenda-skip-scheduled-if-done t ;; Don't show done stuff in the agenda view
|
||
org-agenda-skip-deadline-if-done t
|
||
org-agenda-skip-timestamp-if-done t
|
||
|
||
org-todo-keywords '((sequence "TODO(t)" "WIP(w)" "DELEGATED(p)" "WAITING(?)" "|" "CANCELLED(x)" "DONE(d)")) ;; Some extra keywords in addition to TODO and DONE
|
||
org-use-fast-todo-selection t ;; Always use fast selection
|
||
org-refile-targets '((org-agenda-files :maxlevel . 2)) ;; Allow any agenda files to be refile targets.
|
||
|
||
org-agenda-files (append (apply 'append (mapcar
|
||
(lambda (dir)
|
||
(directory-files-recursively dir org-agenda-file-regexp))
|
||
`(,(concat theurgy-org-directory "tasks"))))
|
||
`(,(concat theurgy-org-directory "inbox.org"))) ;; Agenda files location - gathered recursively
|
||
org-cite-global-bibliography `(,(concat theurgy-org-directory "global.bib")) ;; Global bibliography location
|
||
|
||
org-startup-indented t ;; Start indented - this fixed org-indent mode
|
||
|
||
org-attach-id-dir (concat theurgy-org-directory "lore/assets")
|
||
|
||
org-M-RET-may-split-line '((item . nil)) ;; https://irreal.org/blog/?p=6297
|
||
)
|
||
|
||
;; Org modern and other interface enhancements
|
||
(use-package org-modern
|
||
:hook ((org-mode . org-modern-mode)
|
||
(org-agenda-finalize . org-modern-agenda)))
|
||
|
||
(use-package org-modern-indent
|
||
:straight (org-modern-indent :type git :host github :repo "jdtsmith/org-modern-indent")
|
||
:hook ((org-mode . org-modern-indent-mode)))
|
||
|
||
(use-package wc-mode
|
||
:hook ((org-mode . wc-mode))
|
||
:config (setq wc-modeline-format "WC[%tw]"))
|
||
|
||
(use-package org-appear :ensure t
|
||
:init
|
||
(setq org-appear-delay 0.2)
|
||
:hook
|
||
org-mode)
|
||
|
||
;; Side tree
|
||
(use-package org-side-tree
|
||
:hook ((org-modern-mode . org-side-tree)))
|
||
|
||
;; Advice to display org-side-tree where we want it
|
||
(defun theurgy-org-side-tree ()
|
||
"Create or pop to Org-Side-Tree buffer."
|
||
(interactive)
|
||
(when (org-side-tree-buffer-p)
|
||
(error "Don't tree a tree"))
|
||
(unless (or (derived-mode-p 'org-mode)
|
||
(derived-mode-p 'outline-mode)
|
||
outline-minor-mode)
|
||
(error "Not an outline buffer"))
|
||
(let* ((tree-name (if (default-value 'org-side-tree-persistent)
|
||
"*Org-Side-Tree*"
|
||
(format "<tree>%s" (buffer-name))))
|
||
(tree-buffer (get-buffer tree-name))
|
||
(heading (org-side-tree-heading-number))
|
||
(dd default-directory)
|
||
(inv-spec buffer-invisibility-spec))
|
||
(unless (buffer-live-p tree-buffer)
|
||
(save-restriction
|
||
(widen)
|
||
(jit-lock-mode 1)
|
||
(jit-lock-fontify-now))
|
||
(setq tree-buffer (generate-new-buffer tree-name))
|
||
(add-hook 'kill-buffer-hook #'org-side-tree-cleanup nil t)
|
||
(let* ((headings (org-side-tree-get-headings))
|
||
(tree-head-line (or (cadar (org-collect-keywords
|
||
'("title")))
|
||
"Org-Side-Tree"))
|
||
(tree-mode-line (format "Org-Side-Tree - %s"
|
||
(buffer-name))))
|
||
(when (default-value 'org-side-tree-enable-folding)
|
||
(setq-local org-side-tree-enable-folding t))
|
||
(with-current-buffer tree-buffer
|
||
(setq-local default-directory dd)
|
||
(org-side-tree-mode)
|
||
(setq tabulated-list-entries headings)
|
||
(tabulated-list-print t t)
|
||
(when (default-value 'org-side-tree-enable-folding)
|
||
(setq-local org-side-tree-enable-folding t)
|
||
;; preserve org font-locking
|
||
(setq-local outline-minor-mode-highlight nil)
|
||
(outline-minor-mode 1))
|
||
(setq buffer-invisibility-spec inv-spec)
|
||
(setq header-line-format tree-head-line)
|
||
(setq mode-line-format tree-mode-line))))
|
||
(org-side-tree-set-timer)
|
||
(switch-to-buffer (buffer-name))
|
||
(display-buffer-in-side-window
|
||
tree-buffer
|
||
`((side . ,org-side-tree-display-side)
|
||
(slot . 1)
|
||
(window-width . ,org-side-tree-width)))
|
||
(when (default-value 'org-side-tree-persistent)
|
||
(setq-local org-side-tree-persistent
|
||
(buffer-name))
|
||
(org-side-tree-update))
|
||
(when org-side-tree-select
|
||
(pop-to-buffer tree-buffer))
|
||
(setq window-size-fixed (when org-side-tree-width 'width))
|
||
(pulse-momentary-highlight-one-line)
|
||
(org-side-tree-go-to-heading heading)))
|
||
|
||
(advice-add 'org-side-tree :override #'theurgy-org-side-tree)
|
||
|
||
;; Helper functions for the side tree
|
||
(defun theurgy-toggle-org-side-tree ()
|
||
(interactive)
|
||
(if (get-buffer-window (concat "<tree>" (file-name-nondirectory (buffer-file-name))))
|
||
(delete-window (get-buffer-window (concat "<tree>" (file-name-nondirectory (buffer-file-name)))))
|
||
(org-side-tree)))
|
||
|
||
(add-to-list 'display-buffer-alist
|
||
'("<tree>.+\.org"
|
||
(display-buffer-in-side-window)
|
||
(side . left)
|
||
(slot . 1)
|
||
(window-height . 0.2)))
|
||
|
||
(define-key org-mode-map (kbd "C-<f8>") #'theurgy-toggle-org-side-tree)
|
||
|
||
;; https://chrismaiorana.com/summer-productivity-reset-emacs-functions/
|
||
(defun csm/replace-punctuation-at-point ()
|
||
"Replace punctuation at point (., !, ?) with the character typed by the user."
|
||
(interactive)
|
||
(let ((char (this-command-keys))) ;; Get the key pressed by the user
|
||
(if (and (member (char-after) '(?. ?! ?? ?,)) ;; Check if current char is ., !, or ?
|
||
(member (string-to-char char) '(?. ?! ??))) ;; Check if typed char is ., !, or ?
|
||
(progn
|
||
(delete-char 1) ;; Delete existing punctuation
|
||
(insert char)) ;; Insert new punctuation
|
||
(self-insert-command 1)))) ;; Default behavior: insert character
|
||
|
||
;; Bind this function to punctuation keys
|
||
(define-key global-map "." 'csm/replace-punctuation-at-point)
|
||
(define-key global-map "," 'csm/replace-punctuation-at-point)
|
||
(define-key global-map "!" 'csm/replace-punctuation-at-point)
|
||
(define-key global-map "?" 'csm/replace-punctuation-at-point)
|
||
|
||
;; Windmove bindings since org overwrites them otherwise
|
||
(define-key org-mode-map (kbd "C-c <left>") 'windmove-left)
|
||
(define-key org-mode-map (kbd "C-c <right>") 'windmove-right)
|
||
(define-key org-mode-map (kbd "C-c <up>") 'windmove-up)
|
||
(define-key org-mode-map (kbd "C-c <down>") 'windmove-down)
|
||
|
||
;; Same with scrolling
|
||
(define-key org-mode-map (kbd "C-S-<down>") '(lambda () (interactive) (scroll-up-line 10)))
|
||
(define-key org-mode-map (kbd "C-S-<up>") '(lambda () (interactive) (scroll-down-line 10)))
|
||
|
||
;; Sentence and word navigation and marking
|
||
(setq sentence-end-double-space nil) ;; Otherwise, M-e is broken in normal writing.
|
||
|
||
;;; Generally useful things
|
||
;; Mark word and sentence
|
||
(defun mark-whole-word ()
|
||
"Mark the whole word underneath the cursor."
|
||
(interactive)
|
||
(forward-word)
|
||
(set-mark-command nil)
|
||
(backward-word))
|
||
|
||
(defun mark-sentence ()
|
||
"Mark the entire sentence underneath the cursor."
|
||
(interactive)
|
||
(forward-sentence)
|
||
(set-mark-command nil)
|
||
(backward-sentence))
|
||
|
||
(define-key org-mode-map (kbd "C-@") #'mark-whole-word)
|
||
(define-key org-mode-map (kbd "M-@") #'mark-sentence)
|
||
|
||
(transient-define-prefix mark-menu-transient ()
|
||
"Transient menu for marking units of text."
|
||
["Mark" ("w" "Word" mark-whole-word)
|
||
("s" "Sentence" mark-sentence)
|
||
("p" "Paragraph" mark-paragraph)
|
||
("b" "Buffer" mark-whole-buffer)])
|
||
|
||
(define-key org-mode-map (kbd "C-c o SPC") #'mark-menu-transient)
|
||
|
||
;; Section navigation and reordering
|
||
(defun move-sentence-right (&optional arg)
|
||
"Move the whole sentence to the right of the next sentence, `ARG' times."
|
||
(interactive "^p")
|
||
(or arg (setq arg 1))
|
||
(while (> arg 0)
|
||
(forward-sentence)
|
||
(backward-sentence)
|
||
(left-char) ;; Capture previous space
|
||
(kill-sentence)
|
||
(forward-sentence)
|
||
(yank)
|
||
(backward-sentence)
|
||
(setq arg (1- arg))))
|
||
|
||
(defun move-sentence-left (&optional arg)
|
||
"Move the whole sentence to the left of the previous sentence, `ARG' times."
|
||
(interactive "^p")
|
||
(or arg (setq arg 1))
|
||
(while (> arg 0)
|
||
(forward-sentence)
|
||
(backward-sentence)
|
||
(left-char) ;; Capture previous space
|
||
(kill-sentence)
|
||
(backward-sentence)
|
||
(left-char) ;; Capture previous space
|
||
(yank)
|
||
(backward-sentence)
|
||
(setq arg (1- arg))))
|
||
|
||
(defun move-paragraph-up (&optional arg)
|
||
"Move the whole paragraph above the previous paragraph, `ARG' times."
|
||
(interactive "^p")
|
||
(or arg (setq arg 1))
|
||
(while (> arg 0)
|
||
(forward-paragraph)
|
||
(backward-paragraph)
|
||
(kill-paragraph nil)
|
||
(backward-paragraph)
|
||
(yank)
|
||
(backward-paragraph)
|
||
(setq arg (1- arg))))
|
||
|
||
(defun move-paragraph-down (&optional arg)
|
||
"Move the whole paragraph above the previous paragraph, `ARG' times."
|
||
(interactive "^p")
|
||
(or arg (setq arg 1))
|
||
(while (> arg 0)
|
||
(forward-paragraph)
|
||
(backward-paragraph)
|
||
(kill-paragraph nil)
|
||
(forward-paragraph)
|
||
(yank)
|
||
(backward-paragraph)
|
||
(setq arg (1- arg))))
|
||
|
||
(define-key org-mode-map (kbd "C-M-<left>") #'move-sentence-left)
|
||
(define-key org-mode-map (kbd "C-M-<right>") #'move-sentence-right)
|
||
(define-key org-mode-map (kbd "C-M-<up>") #'move-paragraph-up)
|
||
(define-key org-mode-map (kbd "C-M-<down>") #'move-paragraph-down)
|
||
|
||
(transient-define-prefix reorder-transient ()
|
||
"Transient menu for text re-ordering commands."
|
||
["Move sentence..." ("l" "Left" move-sentence-left)
|
||
("r" "Right" move-sentence-right)]
|
||
["Move paragraph..." ("u" "Up" move-paragraph-up)
|
||
("d" "Down" move-paragraph-down)])
|
||
|
||
(define-key org-mode-map (kbd "C-c o r") #'reorder-transient)
|
||
|
||
;; Focused rewriting
|
||
(defun break-out-sentence ()
|
||
"Breaks a sentence out into it's own buffer for editing."
|
||
(interactive)
|
||
(backward-sentence)
|
||
(kill-sentence)
|
||
(switch-to-buffer-other-window "*break-out*")
|
||
(erase-buffer)
|
||
(yank))
|
||
|
||
(defun break-out-choose-sentence ()
|
||
"Chooses a sentence from the break-out buffer."
|
||
(interactive)
|
||
(backward-sentence)
|
||
(kill-sentence)
|
||
(other-window -1)
|
||
(kill-buffer "*break-out*")
|
||
(yank))
|
||
|
||
(defun break-out-dwim ()
|
||
"Either break-out or choose sentency depending on buffer name."
|
||
(interactive)
|
||
(if (equal (buffer-name) "*break-out*")
|
||
(break-out-choose-sentence)
|
||
(break-out-sentence)))
|
||
|
||
(define-key org-mode-map (kbd "C-c o b") #'break-out-dwim)
|
||
|
||
;; Powerthesaurus
|
||
(use-package powerthesaurus
|
||
:bind ("C-x t" . powerthesaurus-transient))
|
||
|
||
;; Harper
|
||
(when (and (not (equal system-type 'windows-nt)) (locate-file "harper-ls" exec-path))
|
||
(with-eval-after-load 'eglot
|
||
(add-to-list 'eglot-server-programs
|
||
'(org-mode . ("harper-ls" "--stdio"))))
|
||
|
||
(setq-default eglot-workspace-configuration
|
||
'(:harper-ls (:dialect "Australian")))
|
||
|
||
(add-hook 'org-mode-hook 'eglot-ensure))
|
||
|
||
;;; Exobrain
|
||
;;; Task management
|
||
;; Maintenance and project file creation shortcuts
|
||
(defun new-maintenance-file (maintenance-area)
|
||
"Create a new maintenance file for a given `MAINTENANCE-AREA'."
|
||
(interactive "sMaintenance area is: ")
|
||
(find-file (concat "~/.org/tasks/maintenance/" maintenance-area ".org"))
|
||
(insert "\n\n* Calendar\n\n* TO-DO\n\n* Routines\n\n* Archive\n")
|
||
(goto-char (point-min)))
|
||
|
||
(defun new-project-file (project-name acceptance-criteria)
|
||
"Create a new project file for a given `PROJECT-NAME', with some `ACCEPTANCE-CRITERIA'."
|
||
(find-file (concat "~/.org/tasks/projects/" project-name ".org"))
|
||
(insert (concat "\n\n* Acceptance Criteria\n\n" acceptance-criteria "\n\n* Ideas\n\n* TODO Work\n\n** Calendar\n\n** TO-DO\n\n** Routines\n\n** Archive\n"))
|
||
(goto-char (point-min)))
|
||
|
||
(defun new-generic-project (project-name acceptance-criteria)
|
||
"Interactive wrapper for `new-project-file', for generic projects."
|
||
(interactive "sProject name is: \nsAcceptance criteria is: ")
|
||
(new-project-file project-name acceptance-criteria))
|
||
|
||
(defun new-career-project (project-name acceptance-criteria)
|
||
"Interactive wrapper for `new-project-file', for career projects."
|
||
(interactive "sProject name is: \nsAcceptance criteria is: ")
|
||
(new-project-file (concat "career/" project-name) acceptance-criteria))
|
||
|
||
;; Captures
|
||
(defun select-task-area (location headline)
|
||
"Prompt for a file in ~/.org/tasks/maintenance/ to insert the capture."
|
||
(let* ((files (directory-files (concat "~/.org/tasks/" location) t "\\.org$"))
|
||
(choices (mapcar
|
||
(lambda (x) (string-remove-suffix ".org" x))
|
||
(mapcar #'file-name-nondirectory files)))
|
||
(selected (completing-read "Choose a file: " choices nil t)))
|
||
(set-buffer (org-capture-target-buffer (concat "~/.org/tasks/" location selected ".org")))
|
||
(org-capture-put-target-region-and-position)
|
||
(widen)
|
||
(goto-char (point-min))
|
||
(setq headline (org-capture-expand-headline headline))
|
||
(re-search-forward (format org-complex-heading-regexp-format
|
||
(regexp-quote headline))
|
||
nil t)
|
||
(forward-line 0)))
|
||
|
||
(defun select-maintenance-area (headline)
|
||
(select-task-area "maintenance/" headline))
|
||
|
||
(defun select-project (headline)
|
||
(select-task-area "projects/" headline))
|
||
|
||
(defun select-career-project (headline)
|
||
(select-task-area "projects/career/" headline))
|
||
|
||
(setq org-capture-templates
|
||
'(("i" "Idea")
|
||
("ii" "Generic" entry
|
||
(file "~/.org/inbox.org")
|
||
"* %^{TITLE} :idea: \n\n%?"
|
||
:empty-lines 1)
|
||
("ip" "Project" entry
|
||
(function (lambda () (select-project "Ideas")))
|
||
"* %^{TITLE} \n\n%?"
|
||
:empty-lines 1)
|
||
("ic" "Career" entry
|
||
(function (lambda () (select-career-project "Ideas")))
|
||
"* %^{TITLE} \n\n%?"
|
||
:empty-lines 1)
|
||
|
||
("t" "Task")
|
||
("tt" "Generic")
|
||
("ttt" "Raw" entry
|
||
(file "~/.org/inbox.org")
|
||
"* TODO [%^{priority|#A|#B|#C|#D}] %^{TITLE} :task:\n\n%?"
|
||
:empty-lines 1)
|
||
("ttm" "Maintenance" entry
|
||
(function (lambda () (select-maintenance-area "TO-DO")))
|
||
"* TODO [%^{priority|#A|#B|#C|#D}] %^{TITLE}\n\n%?"
|
||
:empty-lines 1)
|
||
("ttp" "Project" entry
|
||
(function (lambda () (select-project "TO-DO")))
|
||
"* TODO [%^{priority|#A|#B|#C|#D}] %^{TITLE}\n\n%?"
|
||
:empty-lines 1)
|
||
("ttc" "Career" entry
|
||
(function (lambda () (select-career-project "TO-DO")))
|
||
"* TODO [%^{priority|#A|#B|#C|#D}] %^{TITLE}\n\n%?"
|
||
:empty-lines 1)
|
||
("ts" "Scheduled")
|
||
("tss" "Raw" entry
|
||
(file "~/.org/inbox.org")
|
||
"* TODO [%^{priority|#A|#B|#C|#D}] %^{TITLE} :scheduled:\n:SCHEDULED: %^T\n%?"
|
||
:empty-lines 1
|
||
:time-prompt t)
|
||
("tsm" "Maintenance" entry
|
||
(function (lambda () (select-maintenance-area "Calendar")))
|
||
"* TODO [%^{priority|#A|#B|#C|#D}] %^{TITLE} \n:SCHEDULED: %^T\n%?"
|
||
:empty-lines 1
|
||
:time-prompt t)
|
||
("tsp" "Project" entry
|
||
(function (lambda () (select-project "Calendar")))
|
||
"* TODO [%^{priority|#A|#B|#C|#D}] %^{TITLE} \n:SCHEDULED: %^T\n%?"
|
||
:empty-lines 1
|
||
:time-prompt t)
|
||
("tsc" "Career" entry
|
||
(function (lambda () (select-career-project "Calendar")))
|
||
"* TODO [%^{priority|#A|#B|#C|#D}] %^{TITLE} \n:SCHEDULED: %^T\n%?"
|
||
:empty-lines 1
|
||
:time-prompt t)
|
||
|
||
("n" "Note")
|
||
("nn" "Raw" entry
|
||
(file "~/.org/inbox.org")
|
||
"* %^{TITLE} :note: \n\n%?"
|
||
:empty-lines 1)
|
||
("nm" "Meeting")
|
||
("nmm" "Raw" entry
|
||
(file "~/.org/inbox.org")
|
||
"* %^{TITLE} :meeting: \n\n%?"
|
||
:clock-in t
|
||
:clock-resume t)
|
||
("nmc" "Career" entry
|
||
(function (lambda () (select-career-project "Calendar")))
|
||
"* %^{TITLE} \n\n%?"
|
||
:empty-lines 1
|
||
:clock-in t
|
||
:clock-resume t)))
|
||
|
||
(defun open-inbox ()
|
||
"Opens `~/.org/inbox.org'"
|
||
(interactive)
|
||
(find-file "~/.org/inbox.org"))
|
||
|
||
(defun open-maintenance ()
|
||
"Opens `~/.org/tasks/maintenance/'"
|
||
(interactive)
|
||
(find-file "~/.org/tasks/maintenance/"))
|
||
|
||
(defun open-projects ()
|
||
"Opens `~/.org/tasks/projects/'"
|
||
(interactive)
|
||
(find-file "~/.org/tasks/projects/"))
|
||
|
||
(defun open-career ()
|
||
"Opens `~/.org/tasks/projects/career/'"
|
||
(interactive)
|
||
(find-file "~/.org/tasks/projects/career/"))
|
||
|
||
(transient-define-prefix task-management-menu ()
|
||
"Transient menu for task management shortcuts."
|
||
["Go To" ("i" "Inbox" open-inbox)
|
||
("m" "Maintenance Directory" open-maintenance)
|
||
("p" "Projects Directory" open-projects)
|
||
("c" "Career Directory" open-career)]
|
||
["Create New" ("M" "Maintenance File" new-maintenance-file)
|
||
("P" "Project" new-generic-project)
|
||
("C" "Career Project" new-career-project)])
|
||
|
||
(define-key global-map (kbd "C-c o t") #'task-management-menu)
|
||
(define-key global-map (kbd "C-c a") #'org-agenda)
|
||
(define-key global-map (kbd "C-c c") #'org-capture)
|
||
|
||
(add-to-list 'display-buffer-alist
|
||
'("\\*Org Agenda\\*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(slot . 3)
|
||
(window-width . 0.2)))
|
||
|
||
(add-to-list 'display-buffer-alist
|
||
'("\\*capture\\*\\|CAPTURE-"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(slot . 2)
|
||
(window-width . 0.2)))
|
||
|
||
;; Org roam
|
||
(use-package org-roam
|
||
:straight nil
|
||
:ensure t
|
||
:init
|
||
(setq org-roam-v2-ack t)
|
||
:custom
|
||
(org-roam-directory (file-truename "~/.org/lore/"))
|
||
(org-roam-dailies-directory (file-truename "~/.org/lore/refined/journal/"))
|
||
(org-roam-file-exclude-regexp "\\.git/.*\\|logseq/.*$")
|
||
(org-roam-completion-everywhere)
|
||
(org-roam-capture-templates
|
||
'(("r" "Raw")
|
||
("rr" "Note" plain
|
||
"%?"
|
||
:target (file+head "raw/${slug}.org" "#+title: ${title}\n")
|
||
:unnarrowed t)
|
||
("rq" "Question" plain
|
||
"%?"
|
||
:target (file+head "raw/${slug}.org" "#+title: ${title}\n#+filetags: :question:")
|
||
:unnarrowed t)
|
||
("i" "Index" plain
|
||
"%?"
|
||
:target (file+head "raw/${slug}.org" "#+title: ${title} - Index\n#+filetags: :index:")
|
||
:unnarrowed t)
|
||
("R" "Refined")
|
||
("Rm" "Mini-essay" plain
|
||
"%?"
|
||
:target (file+head "refined/wiki/${slug}.org" "#+title: ${title}\n#+author: Jakub Nowak\n#+filetags: :mini-essay:")
|
||
:unnarrowed t)
|
||
("Re" "Essay" plain
|
||
"%?"
|
||
:target (file+head "refined/wiki/${slug}.org" "#+title: ${title}\n#+author: Jakub Nowak\n#+filetags: :essay:")
|
||
:unnarrowed t)))
|
||
(org-roam-dailies-capture-templates
|
||
'(("d" "default" entry
|
||
"* %?"
|
||
:target (file+head "%<%Y-%m-%d>.org" ;; format matches Logseq
|
||
"#+title: %<%Y-%m-%d>\n"))))
|
||
:bind (("C-c n l" . org-roam-buffer-toggle)
|
||
("C-c n f" . org-roam-node-find)
|
||
("C-c n g" . org-roam-graph)
|
||
("C-c n i" . org-roam-node-insert)
|
||
("C-c n c" . org-roam-capture)
|
||
:map org-roam-dailies-map
|
||
("Y" . org-roam-dailies-capture-yesterday)
|
||
("T" . org-roam-dailies-capture-tomorrow))
|
||
:bind-keymap ("C-c n d" . org-roam-dailies-map)
|
||
:config
|
||
(require 'org-roam-dailies) ;; Ensure the keymap is available
|
||
(org-roam-db-autosync-mode))
|
||
|
||
(defun org-roam-create-node-from-headline ()
|
||
"Create an Org-roam note from the current headline and jump to it.
|
||
|
||
Normally, insert the headline’s title using the ’#title:’ file-level property
|
||
and delete the Org-mode headline. However, if the current headline has a
|
||
Org-mode properties drawer already, keep the headline and don’t insert
|
||
‘#+title:'. Org-roam can extract the title from both kinds of notes, but using
|
||
‘#+title:’ is a bit cleaner for a short note, which Org-roam encourages."
|
||
(interactive)
|
||
(let ((title (nth 4 (org-heading-components)))
|
||
(has-properties (org-get-property-block)))
|
||
(org-cut-subtree)
|
||
(org-roam-find-file title nil nil 'no-confirm)
|
||
(org-paste-subtree)
|
||
(unless has-properties
|
||
(kill-line)
|
||
(while (outline-next-heading)
|
||
(org-promote)))
|
||
(goto-char (point-min))
|
||
(when has-properties
|
||
(kill-line)
|
||
(kill-line))))
|
||
|
||
(use-package logseq-org-roam
|
||
:straight (:host github
|
||
:repo "sbougerel/logseq-org-roam"
|
||
:files ("*.el")))
|
||
|
||
(transient-define-prefix org-roam-menu ()
|
||
"Transient menu for task management shortcuts."
|
||
["Node" ("c" "Capture" org-roam-node-find)
|
||
("i" "Insert" org-roam-node-insert)
|
||
("r" "Refile" org-roam-create-node-from-headline)
|
||
("f" "Find" org-roam-node-find) ]
|
||
["Dailies" ("t" "Today" org-roam-dailies-capture-today)
|
||
("y" "Yesterday" org-roam-dailies-capture-yesterday)
|
||
("n" "Tomorrow" org-roam-dailies-capture-tomorrow)]
|
||
["Logseq" ("R" "Fix links" logseq-org-roam)]
|
||
["Org Roam UI" ("U" "Enable org-roam-ui-mode" org-roam-ui-mode)])
|
||
|
||
(define-key global-map (kbd "C-c o n") #'org-roam-menu)
|
||
|
||
(use-package org-roam-ui
|
||
:straight
|
||
(:host github :repo "org-roam/org-roam-ui" :branch "main" :files ("*.el" "out"))
|
||
:after org-roam
|
||
;; normally we'd recommend hooking orui after org-roam, but since org-roam does not have
|
||
;; a hookable mode anymore, you're advised to pick something yourself
|
||
;; if you don't care about startup time, use
|
||
:hook (after-init . org-roam-ui-mode)
|
||
:config
|
||
(setq org-roam-ui-sync-theme t
|
||
org-roam-ui-follow t
|
||
org-roam-ui-update-on-save t
|
||
org-roam-ui-open-on-start t))
|
||
|
||
;; Bibliography stuff
|
||
(setq bibtex-dialect 'biblatex) ;; Use biblatex instead of bibtex.
|
||
|
||
(use-package biblio)
|
||
|
||
(defun bibtex-online-entry ()
|
||
(interactive)
|
||
(bibtex-entry "Online"))
|
||
|
||
(defun bibtex-misc-entry ()
|
||
(interactive)
|
||
(bibtex-entry "Misc"))
|
||
|
||
(defun bibtex-software-entry ()
|
||
(interactive)
|
||
(bibtex-entry "Software"))
|
||
|
||
(transient-define-prefix bibtex-transient-menu ()
|
||
"Transient menu for task management shortcuts."
|
||
["Biblio" ("d" "doi.org" doi-insert-bibtex)
|
||
("x" "arXiv" arxiv-lookup)]
|
||
["Templates" ("o" "Online Resource" bibtex-online-entry)
|
||
("m" "Misc" bibtex-misc-entry)
|
||
("s" "Software" bibtex-software-entry)])
|
||
|
||
(define-key bibtex-mode-map (kbd "C-c r") #'bibtex-transient-menu)
|
||
|
||
;;; Literate Programming
|
||
;; Racket
|
||
(use-package ob-racket
|
||
:after org
|
||
:config
|
||
(add-hook 'ob-racket-pre-runtime-library-load-hook
|
||
#'ob-racket-raco-make-runtime-library)
|
||
:straight (ob-racket
|
||
:type git :host github :repo "hasu/emacs-ob-racket"
|
||
:files ("*.el" "*.rkt")))
|
||
|
||
(org-babel-do-load-languages
|
||
'org-babel-load-languages
|
||
'((emacs-lisp . t)
|
||
(racket . t)
|
||
))
|
||
|
||
;;; LaTeX configuration
|
||
(require 'ox-latex)
|
||
|
||
(setq org-latex-pdf-process
|
||
'("pdflatex -interaction nonstopmode -output-directory %o %f"
|
||
"bibtex %b"
|
||
"pdflatex -interaction nonstopmode -output-directory %o %f"
|
||
"pdflatex -interaction nonstopmode -output-directory %o %f"))
|
||
(setq org-latex-with-hyperref nil) ;; stop org adding hypersetup{author..} to latex export
|
||
;; (setq org-latex-prefer-user-labels t)
|
||
|
||
;; deleted unwanted file extensions after latexMK
|
||
(setq org-latex-logfiles-extensions
|
||
(quote ("lof" "lot" "tex~" "aux" "idx" "log" "out" "toc" "nav" "snm" "vrb" "dvi" "fdb_latexmk" "blg" "brf" "fls" "entoc" "ps" "spl" "bbl" "xmpi" "run.xml" "bcf" "acn" "acr" "alg" "glg" "gls" "ist")))
|
||
|
||
(unless (boundp 'org-latex-classes)
|
||
(setq org-latex-classes nil))
|
||
|
||
(provide 'org-custom)
|
||
|
||
;;; org-custom.el ends here
|