|
|
|
#+TITLE: Org Mode
|
|
|
|
#+OPTIONS: toc:nil
|
|
|
|
#+PROPERTY: header-args:emacs-lisp :shebang ";;; -*- lexical-binding: t; -*-\n"
|
|
|
|
|
|
|
|
** Table of Contents :toc_4:
|
|
|
|
- [[#latex-configuration][LaTeX Configuration]]
|
|
|
|
- [[#org-configuration][Org Configuration]]
|
|
|
|
- [[#org-functions][Org Functions]]
|
|
|
|
- [[#org-bullets][Org Bullets]]
|
|
|
|
- [[#org-export-packages][Org Export Packages]]
|
|
|
|
- [[#org-roam][Org Roam]]
|
|
|
|
- [[#org-table-of-contents][Org "Table of Contents"]]
|
|
|
|
|
|
|
|
** LaTeX Configuration
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package tex-mode
|
|
|
|
:ensure nil ; built-in
|
|
|
|
:defer t
|
|
|
|
:hook (latex-mode . (lambda ()
|
|
|
|
(setq indent-tabs-mode t)
|
|
|
|
(setq tab-width 4)
|
|
|
|
(setq tex-indent-basic 4)))
|
|
|
|
:config
|
|
|
|
|
|
|
|
(with-eval-after-load 'projectile
|
|
|
|
(defun compile-latex ()
|
|
|
|
"Compile LaTeX project."
|
|
|
|
(interactive)
|
|
|
|
(let ((default-directory (dot/find-project-root)))
|
|
|
|
(projectile-save-project-buffers)
|
|
|
|
(shell-command "make")))))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
** Org Configuration
|
|
|
|
|
|
|
|
|
|
|
|
Base Org.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package org
|
|
|
|
:config
|
|
|
|
(setq org-adapt-indentation nil)
|
|
|
|
(setq org-default-notes-file (expand-file-name "notes.org" org-directory))
|
|
|
|
(setq org-directory (concat (getenv "HOME") "/documents/org"))
|
|
|
|
(setq org-ellipsis "⤵")
|
|
|
|
(setq org-image-actual-width nil)
|
|
|
|
|
|
|
|
;; Enable structured template completion
|
|
|
|
(add-to-list 'org-modules 'org-tempo t)
|
|
|
|
(add-to-list 'org-structure-template-alist
|
|
|
|
'("el" . "src emacs-lisp")))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
Org agenda.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package org-agenda
|
|
|
|
:ensure nil ; built-in
|
|
|
|
:defer t
|
|
|
|
:config
|
|
|
|
(setq org-agenda-files `(,org-directory ,user-emacs-directory))
|
|
|
|
(setq org-agenda-span 14)
|
|
|
|
(setq org-agenda-window-setup 'current-window)
|
|
|
|
(evil-set-initial-state 'org-agenda-mode 'motion))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
Org capture.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package org-capture
|
|
|
|
:ensure nil ; built-in
|
|
|
|
;; Org-capture in new tab, rather than split window
|
|
|
|
:hook (org-capture-mode . delete-other-windows))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
Org keys.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package org-keys
|
|
|
|
:ensure nil ; built-in
|
|
|
|
:config
|
|
|
|
(setq org-return-follows-link t))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
Org links.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package ol
|
|
|
|
:ensure nil ; built-in
|
|
|
|
:config
|
|
|
|
;; Do not open links to .org files in a split window
|
|
|
|
(add-to-list 'org-link-frame-setup '(file . find-file)))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
Org source code blocks.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package org-src
|
|
|
|
:ensure nil ; built-in
|
|
|
|
:config
|
|
|
|
(setq org-edit-src-content-indentation 0)
|
|
|
|
(setq org-src-fontify-natively t)
|
|
|
|
(setq org-src-preserve-indentation t)
|
|
|
|
(setq org-src-tab-acts-natively t)
|
|
|
|
(setq org-src-window-setup 'current-window))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
Org exporter.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package ox
|
|
|
|
:ensure nil ; built-in
|
|
|
|
:defer t
|
|
|
|
:config
|
|
|
|
(setq org-export-coding-system 'utf-8-unix))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
Org latex exporter.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package ox-latex
|
|
|
|
:ensure nil ; built-in
|
|
|
|
:defer t
|
|
|
|
:config
|
|
|
|
;; Define how minted (highlighted src code) is added to src code blocks
|
|
|
|
(setq org-latex-listings 'minted)
|
|
|
|
(setq org-latex-minted-options '(("frame" "lines") ("linenos=true")))
|
|
|
|
;; Set 'Table of Contents' layout
|
|
|
|
(setq org-latex-toc-command "\\newpage \\tableofcontents \\newpage")
|
|
|
|
;; Add minted package to every LaTeX header
|
|
|
|
(add-to-list 'org-latex-packages-alist '("" "minted"))
|
|
|
|
;; Append -shell-escape so pdflatex exports minted correctly
|
|
|
|
(add-to-list 'org-latex-pdf-process (replace-regexp-in-string
|
|
|
|
"%latex "
|
|
|
|
"%latex -shell-escape "
|
|
|
|
(car org-latex-pdf-process))))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
** Org Functions
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(with-eval-after-load 'evil-commands
|
|
|
|
(defun dot/org-ret-at-point ()
|
|
|
|
"Org return key at point.
|
|
|
|
|
|
|
|
If point is on:
|
|
|
|
checkbox -- toggle it
|
|
|
|
link -- follow it
|
|
|
|
otherwise -- run the default (evil-ret) expression"
|
|
|
|
(interactive)
|
|
|
|
(let ((type (org-element-type (org-element-context))))
|
|
|
|
(pcase type
|
|
|
|
('link (if org-return-follows-link (org-open-at-point) (evil-ret)))
|
|
|
|
((guard (org-at-item-checkbox-p)) (org-toggle-checkbox))
|
|
|
|
(_ (evil-ret))
|
|
|
|
))))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
** Org Bullets
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package org-bullets
|
|
|
|
:hook (org-mode . org-bullets-mode))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
** Org Export Packages
|
|
|
|
|
|
|
|
HTML exporter.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package htmlize
|
|
|
|
:defer t
|
|
|
|
:config (setq org-export-html-postamble nil))
|
|
|
|
;;org-export-html-postamble-format ; TODO
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
GitHub flavored Markdown exporter.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package ox-gfm
|
|
|
|
:defer t)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
** Org Roam
|
|
|
|
|
|
|
|
Setup =org-roam=.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package org-roam
|
|
|
|
:defer 1
|
|
|
|
:init
|
|
|
|
(setq org-roam-v2-ack t)
|
|
|
|
:config
|
|
|
|
(setq org-roam-db-location (expand-file-name "org-roam.db" dot-cache-dir))
|
|
|
|
(setq org-roam-directory org-directory)
|
|
|
|
;; Exclude Syncthing backup directory
|
|
|
|
(setq org-roam-file-exclude-regexp "\\.stversions")
|
|
|
|
(setq org-roam-verbose nil)
|
|
|
|
|
|
|
|
(setq org-roam-capture-templates
|
|
|
|
'(("d" "default" plain
|
|
|
|
"%?"
|
|
|
|
:target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+TITLE: ${title}\n#+FILETAGS: %^{File tags}\n")
|
|
|
|
:unnarrowed t)))
|
|
|
|
|
|
|
|
(defun dot/org-roam-node-insert-immediate (arg &rest args)
|
|
|
|
(interactive "P")
|
|
|
|
(let ((args (push arg args))
|
|
|
|
(org-roam-capture-templates (list (append (car org-roam-capture-templates)
|
|
|
|
'(:immediate-finish t)))))
|
|
|
|
(apply #'org-roam-node-insert args)))
|
|
|
|
|
|
|
|
(cl-defmethod org-roam-node-slug ((node org-roam-node))
|
|
|
|
"Return the slug of NODE, strip out common words."
|
|
|
|
(let* ((title (org-roam-node-title node))
|
|
|
|
(words (split-string title " "))
|
|
|
|
(common-words '("a" "an" "and" "as" "at" "by" "is" "it" "of" "the" "to"))
|
|
|
|
(title (string-join (seq-remove (lambda (element) (member element common-words)) words) "_"))
|
|
|
|
(pairs '(("c\\+\\+" . "cpp") ;; convert c++ -> cpp
|
|
|
|
("c#" . "cs") ;; convert c# -> cs
|
|
|
|
("[^[:alnum:][:digit:]]" . "_") ;; convert anything not alphanumeric
|
|
|
|
("__*" . "_") ;; remove sequential underscores
|
|
|
|
("^_" . "") ;; remove starting underscore
|
|
|
|
("_$" . "")))) ;; remove ending underscore
|
|
|
|
(cl-flet ((cl-replace (title pair)
|
|
|
|
(replace-regexp-in-string (car pair) (cdr pair) title)))
|
|
|
|
(downcase (-reduce-from #'cl-replace title pairs)))))
|
|
|
|
|
|
|
|
;; Right-align org-roam-node-tags in the completion menu without a length limit
|
|
|
|
;; Source: https://github.com/org-roam/org-roam/issues/1775#issue-971157225
|
|
|
|
(setq org-roam-node-display-template "${title} ${tags:0}")
|
|
|
|
(setq org-roam-node-annotation-function #'dot/org-roam-annotate-tag)
|
|
|
|
(defun dot/org-roam-annotate-tag (node)
|
|
|
|
(let ((tags (mapconcat 'identity (org-roam-node-tags node) " #")))
|
|
|
|
(unless (string-empty-p tags)
|
|
|
|
(concat
|
|
|
|
(propertize " " 'display `(space :align-to (- right ,(+ 2 (length tags)))))
|
|
|
|
(propertize (concat "#" tags) 'face 'bold)))))
|
|
|
|
|
|
|
|
(org-roam-setup))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
Enable [[https://www.orgroam.com/manual.html#Roam-Protocol][Roam Protocol]], needed to process =org-protocol://= links
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package org-roam-protocol
|
|
|
|
:ensure nil ; org-roam-protocol.el is part of org-roam
|
|
|
|
:after org-roam
|
|
|
|
:config
|
|
|
|
|
|
|
|
;; Templates used when creating a new file from a bookmark
|
|
|
|
(setq org-roam-capture-ref-templates
|
|
|
|
'(("r" "ref" plain
|
|
|
|
"%?"
|
|
|
|
:target (file+head "${slug}.org" "#+TITLE: ${title}\n \n${body}")
|
|
|
|
:unnarrowed t))))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
The roam-ref protocol bookmarks to add:
|
|
|
|
|
|
|
|
#+BEGIN_SRC javascript
|
|
|
|
javascript:location.href =
|
|
|
|
'org-protocol://roam-ref?template=r'
|
|
|
|
+ '&ref=' + encodeURIComponent(location.href)
|
|
|
|
+ '&title=' + encodeURIComponent(document.title)
|
|
|
|
+ '&body=' + encodeURIComponent(window.getSelection())
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
Setup =org-roam-ui=, runs at http://127.0.0.1:35901.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package org-roam-ui
|
|
|
|
:after org-roam
|
|
|
|
:config
|
|
|
|
(setq org-roam-ui-follow t)
|
|
|
|
(setq org-roam-ui-open-on-start t)
|
|
|
|
(setq org-roam-ui-sync-theme nil) ;; FIXME: Make this work (org-roam-ui-get-theme)
|
|
|
|
(setq org-roam-ui-update-on-save t))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
Easily searchable .org files via Deft.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package deft
|
|
|
|
:after org
|
|
|
|
:hook (deft-mode . dot/hook-disable-line-numbers)
|
|
|
|
:config
|
|
|
|
(setq deft-auto-save-interval 0)
|
|
|
|
(setq deft-default-extension "org")
|
|
|
|
(setq deft-directory org-directory)
|
|
|
|
(setq deft-file-naming-rules '((noslash . "-")
|
|
|
|
(nospace . "-")
|
|
|
|
(case-fn . downcase)))
|
|
|
|
(setq deft-new-file-format "%Y%m%d%H%M%S-deft")
|
|
|
|
(setq deft-recursive t)
|
|
|
|
;; Exclude Syncthing backup directory
|
|
|
|
(setq deft-recursive-ignore-dir-regexp (concat "\\.stversions\\|" deft-recursive-ignore-dir-regexp))
|
|
|
|
;; Remove file variable -*- .. -*- and Org Mode :PROPERTIES: lines
|
|
|
|
(setq deft-strip-summary-regexp (concat "\\(^.*-\\*-.+-\\*-$\\|^:[[:alpha:]_]+:.*$\\)\\|" deft-strip-summary-regexp))
|
|
|
|
(setq deft-use-filename-as-title nil)
|
|
|
|
(setq deft-use-filter-string-for-filename t)
|
|
|
|
|
|
|
|
(add-to-list 'deft-extensions "tex")
|
|
|
|
|
|
|
|
;; Start filtering immediately
|
|
|
|
(evil-set-initial-state 'deft-mode 'insert)
|
|
|
|
|
|
|
|
(defun deft-parse-title (file contents)
|
|
|
|
"Parse the given FILE and CONTENTS and determine the title."
|
|
|
|
(org-element-property
|
|
|
|
:value
|
|
|
|
(car
|
|
|
|
(org-element-map
|
|
|
|
(with-temp-buffer
|
|
|
|
(insert contents)
|
|
|
|
(org-element-parse-buffer 'greater-element))
|
|
|
|
'keyword
|
|
|
|
(lambda (e) (when (string-match "TITLE" (org-element-property :key e)) e)))))))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
** Org "Table of Contents"
|
|
|
|
|
|
|
|
Generate table of contents without exporting.
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(use-package toc-org
|
|
|
|
:hook (org-mode . toc-org-mode))
|
|
|
|
#+END_SRC
|