UP | HOME

Literate doom-emacs config

Table of Contents

0.1. About

This is a literate config file for doom-emacs by hlinssner. This is meant to be used with the develop branch. Much of the basic setup is pulled from the emacs literate starter by gilbertw1. The companion packages page describes the basic package setup, while the init.el is described on the project homepage.

0.1.1. About that TOC..

So as mentioned here there is trouble when org-export tries to create files while keeping the org-toc tag.

It's not really a problem since org-export actually generates a TOC for the files anyway.

0.2. Personal Information

Let's set some variables with basic user information.

(setq user-full-name "Rohit Goswami (HaoZeke)"
      user-mail-address "rohit.goswami@aol.com")

1. Doom Emacs Stuff

1.1. Visual tweaks

1.1.1. Font Faces

Start by becoming resolution aware 1.

(setq resolution-factor 1.11) ;; default
(when (display-graphic-p)
  (setq resolution-factor (eval (/ (x-display-pixel-height) 1080.0)))
  )
(setq base-font-size 27.0)
(defvar hz/font-setup-verbose 'nil
  "If non-nil, display verbose messages about font setup.")

Now to find and set fonts.

(when (display-graphic-p)
  (let ((font-list '("Intel One Mono"
                     "Cascadia Code PL"
                     "Attribute Mono"
                     "OperatorMono Nerd Font"
                     "Droid Sans Mono"
                     "Droid Sans Fallback"))
        (found-font nil))

    (dolist (font-name font-list)
      (if (find-font (font-spec :name font-name))
          (progn
            (setq user-font font-name)
            (setq found-font t))
        (when hz/font-setup-verbose
          (message "Font '%s' does not exist!" font-name))))

    (unless found-font
      (warn "No suitable font found. Using system defaults."))

    ;; Set the font weight based on the found font
    (setq user-font-weight
          (cond
           ((string= user-font "Droid Sans Mono") 'medium)
           (t 'normal)))

    ;; Set up the fonts using the found font and resolution factor
    (setq doom-font (font-spec :family user-font
                               :weight user-font-weight
                               :size (eval (round (* base-font-size resolution-factor))))
          doom-big-font (font-spec :family user-font
                                   :weight user-font-weight
                                   :size (eval (round (* (+ base-font-size 4) resolution-factor))))
          doom-variable-pitch-font (font-spec :family user-font
                                              :weight user-font-weight
                                              :size (eval (round (* (- base-font-size 1) resolution-factor))))
          doom-modeline-height (eval (round (* 36 resolution-factor)))

          )
    ))

Also doom-big-font-mode with SPC t b is very useful 2.

  1. Unicode Fonts

    The unicode module uses doom-font for everything, but still needs a fallback font.

    (setq doom-unicode-font (font-spec :family "Symbola"
                                       :size (eval (round (* (- base-font-size 2) resolution-factor)))))
    

    Now that this is merged…

    (defun hz/setup-font-sets ()
      "Ensure fontsets for unicode fallback are configured correctly."
      (when (and doom-unicode-font (fboundp 'set-fontset-font))
        (set-fontset-font t 'unicode doom-unicode-font nil 'append)))
    
    (add-hook 'after-setting-font-hook #'hz/setup-font-sets)
    

1.1.2. Helm and Childframes

I prefer the regular diminished font size, even for the childframes.

;; Helm is no longer enabled (using vertico)
;; (setq +helm-posframe-text-scale 0)

1.1.3. Saner Dashboard

I have trouble at work with the current DOOM dashboard. This one is from the doom-emacs lead developer, as found on Discord.

(setq +doom-dashboard-banner-file (expand-file-name "banner.png" doom-private-dir))

1.2. Tweaks

1.2.1. Non-posix shells

Apparently fish and nushell are particularly incompatible..

(when (getenv "SHELL")
  (let ((user-shell (getenv "SHELL")))
    (when (or (string-match-p "fish" user-shell)
              (string-match-p "nu" user-shell))
      ;; Set a POSIX-compliant shell for internal Emacs processes
      (setq shell-file-name (executable-find "bash"))

      ;; Ensure Emacs terminal emulators still use the user's preferred shell
      (setq-default vterm-shell user-shell)
      (setq-default explicit-shell-file-name user-shell)

      ;; Also update the specific shell script variable if needed
      (setq-default sh-shell-file user-shell))))

1.2.2. Projectile cache management

(add-hook 'projectile-after-switch-project-hook (lambda () (projectile-invalidate-cache nil)))

1.3. Bugfixes

Most of these should be removed when doom fixes them.

;; Doom manages package-archives via straight.el; manual override removed
;; (setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
;;                          ("nongnu" . "https://elpa.nongnu.org/nongnu/")
;;                          ("melpa" . "https://melpa.org/packages/")))

1.4. Helm changes

This makes `helm` behave more like `ivy` while working with directories.

(after! helm
  ;; I want backspace to go up a level, like ivy
  (add-hook! 'helm-find-files-after-init-hook
    (map! :map helm-find-files-map
          "<DEL>" #'helm-find-files-up-one-level)))

1.5. Disable eager functions

1.5.1. Kill spellcheck

This is really really really excruciatingly slow for LaTeX mode and maybe even for other random buffers.

(setq-hook! 'LaTeX-mode-hook +spellcheck-immediately nil)
  1. Snippets

    I am not sure if these need to be initialized.

    ; AndreaCrotti
    (use-package! yasnippet-snippets
      :after yasnippet)
    

1.5.2. Kill over-eager literate after-save-hook

This is a little too frequent for working with a git repo. Henrik mentioned an async version of the re-compliation might be in the works, until then however I will probably only manually trigger the re-compliation.

(after! org
  (remove-hook 'after-save-hook #'+literate-recompile-maybe-h))

1.5.3. Kill Orgmode template

These conflict with my other templates.

(set-file-template! "\\.org$" :ignore t)

1.6. Variables

(load! "local/rg-bibtex")
(rg/bibtex-configure-paths)

1.6.1. Theme

Sometimes I do tire of the defaults.

;; Also like doom-city-lights, doom-oceanic-next, doom-tomorrow-night, doom-wilmersdorf, leuven, doom-monokai-pro, doom-solarized-dark-high-contrast
;; Light ones like solarized
(setq doom-theme 'doom-tomorrow-night)

1.6.2. Do not Format on Save

Formatting with styler takes forever.

(setq +format-on-save-enabled-modes '(not emacs-lisp-mode ; works well enough without it
                                          sql-mode        ; sqlformat is broken
                                          tex-mode        ; latexindent is broken
                                          latex-mode      ; latexindent is broken
                                          bibtex-mode     ; is broken
                                          ess-r-mode      ; styler takes forever
                                          web-mode      ; dunno who this is for
                                          ))

1.7. Keybindings

1.7.1. Evil Setup and Error Handling

Actually this might not be ported over so I'm just going to put this elsewhere.

;; I like short names
(general-evil-setup t)
;; Stop telling me things begin with non-prefix keys
(general-auto-unbind-keys)

1.7.2. Spacemacs Equivalency

  1. Kill buffer

    Also it's inconvenient to have a key chord requiring two hands to close a buffer.

    ;; Compatibility, delete when fully migrated
    (defconst my-leader "SPC")
    ;; Bind a new key chord
    (map!
     (:leader
      (:prefix "b"
       :desc "Kill buffer" "d" #'kill-this-buffer)
      (:prefix ("k" . "kill")
       :desc "Save and kill" "e" 'save-buffers-kill-terminal
       :desc "Kill buffer" "b" 'my-kill-this-buffer
       :desc "Delete frame" "f" 'delete-frame
       (:prefix ("o" . "Other")
        :desc "Frames" "f" 'delete-other-frames
        :desc "Windows" "w" 'delete-other-windows
        )
       )
      ))
    
    1. general.el

      The binding syntax of the future, TODAY!

      ;; ** Global Keybindings
      ;; Normal mode?
      (nmap
        :prefix my-leader
        "b d" #'kill-this-buffer
        ;; kill things
        "k" '(:ignore t :which-key "kill")
        "k e" 'save-buffers-kill-terminal
        "k b" 'my-kill-this-buffer
        "k f" 'delete-frame
        "k o f" 'delete-other-frames
        "k o w" 'delete-other-windows
        "a" 'helm-mini)
      ;; (my-leader-def 'normal 'override
      ;;   "a" 'org-agenda)
      

1.7.3. Global Maps

  1. Multiple Cursors

    These need practice. Many of these are already in the default configuration, but they are redefined here for mnemonic usage. Also to add the which-key hints.

    (nmap
      :prefix "gz"
      :keymaps 'global
      "r" '(mc/edit-lines :wk "Span region")
      "z" '(+evil/mc-make-cursor-here :wk "Place frozen cursor")
      )
    
  2. Move around with Links

    Useful for navigating files and what not.

    (map! :leader
          :desc "Follow thing"  "RET" 'org-open-at-point)
    
  3. Replace Stuff

    There are way too many of these to keep using helm.

    (map! :leader
          (:prefix ("r" . "Replace")
           :desc "String" "s" 'replace-string
           :desc "Query" "q" 'query-replace
           (:prefix ("r" . "Regexp")
            :desc "String" "s" 'replace-regexp
            :desc "Query" "q" 'query-replace-regexp
            )
           )
          )
    
  4. Insert Unicode

    This should hopefully propagate across all modes.

    (map! :leader
          (:prefix ("i" . "Insert")
           :desc "Unicode" "u" 'insert-char
           :desc "Snippet" "s" 'yas-insert-snippet
           :desc "From Clipboard" "y" '+default/yank-pop
           :desc "From Evil Registers" "r" 'evil-show-registers
          )
    )
    
  5. Wrap Words
    • [ ] Load conditionally

    This is for working with the various options enabled by +smartparens.

    (map! :leader
          (:prefix ("i" . "Insert")
            (:prefix ("w" . "Wrap")
              :desc "Backticks" "`" . 'sp-wrap-backtick
              :desc "Tildes" "~" . 'sp-wrap-tilde
              )))
    
  6. Lookup

    These were bound to really weird things.

    (nmap
      :prefix my-leader
      ;; look things up
      "l" '(:ignore t :wk "lookup")
      "l o" '(+lookup/online-select :wk "Online")
      "l f" '(+lookup/file :wk "File")
      )
    
  7. No ESC

    The escape key for exiting things seems very painful.

    (general-define-key
     :keymaps '(insert visual normal)
     "S-SPC" 'evil-force-normal-state)
    

1.7.4. Markdown Improvements

Local leader is already bound to `m` and there are few bindings, this just adds more.

(map! :localleader
      :map markdown-mode-map
      :prefix ("i" . "Insert")
      :desc "Blockquote"    "q" 'markdown-insert-blockquote
      :desc "Bold"          "b" 'markdown-insert-bold
      :desc "Code"          "c" 'markdown-insert-code
      :desc "Emphasis"      "e" 'markdown-insert-italic
      :desc "Footnote"      "f" 'markdown-insert-footnote
      :desc "Code Block"    "s" 'markdown-insert-gfm-code-block
      :desc "Image"         "i" 'markdown-insert-image
      :desc "Link"          "l" 'markdown-insert-link
      :desc "List Item"     "n" 'markdown-insert-list-item
      :desc "Pre"           "p" 'markdown-insert-pre
      (:prefix ("h" . "Headings")
       :desc "One"   "1" 'markdown-insert-atx-1
       :desc "Two"   "2" 'markdown-insert-atx-2
       :desc "Three" "3" 'markdown-insert-atx-3
       :desc "Four"  "4" 'markdown-insert-atx-4
       :desc "Five"  "5" 'markdown-insert-atx-5
       :desc "Six"   "6" 'markdown-insert-atx-6))

1.7.5. Org Noter

These bindings should probably be after org-noter is loaded.

(map! :localleader
      :map (org-mode-map pdf-view-mode-map)
      (:prefix ("o" . "Org")
        (:prefix ("n" . "Noter")
          :desc "Noter" "n" 'org-noter
          )))

1.7.6. Org Mode additions

Apart from extension specific bindings, here we define useful functions which are a part of org-mode.

(after! org (map! :localleader
                  :map org-mode-map
                  :desc "Eval Block" "e" 'ober-eval-block-in-repl
                  (:prefix "o"
                   :desc "Tags" "t" 'org-set-tags
                   :desc "Roam Bibtex" "b" 'orb-note-actions
                   (:prefix ("p" . "Properties")
                    :desc "Set" "s" 'org-set-property
                    :desc "Delete" "d" 'org-delete-property
                    :desc "Actions" "a" 'org-property-action
                    )
                   )
                  (:prefix ("i" . "Insert")
                   :desc "Link" "l" 'org-insert-link
                   :desc "Item" "o" 'org-toggle-item
                   :desc "Citation" "c" 'org-ref-insert-cite-link
                   :desc "Footnote" "f" 'org-footnote-action
                   :desc "Table" "t" 'org-table-create-or-convert-from-region
                   (:prefix ("d" . "Download")
                    :desc "Screenshot" "s" 'org-download-screenshot
                    :desc "Clipboard" "c" 'org-download-clipboard
                    :desc "Link" "l" 'org-download-image
                    )
                   (:prefix ("b" . "Math")
                    :desc "Bold" "f" 'org-make-bold-math
                    :desc "Blackboard" "b" 'org-make-blackboard-math
                    :desc "Remove" "r" 'org-make-symrm-math
                    :desc "Vert" "v" 'org-make-vert-math
                    )
                   (:prefix ("h" . "Headings")
                    :desc "Normal" "h" 'org-insert-heading
                    :desc "Todo" "t" 'org-insert-todo-heading
                    (:prefix ("s" . "Subheadings")
                     :desc "Normal" "s" 'org-insert-subheading
                     :desc "Todo" "t" 'org-insert-todo-subheading
                     )
                    )
                   (:prefix ("e" . "Exports")
                    :desc "Dispatch" "d" 'org-export-dispatch
                    )
                   )
                  )
  )
  1. Math Environments

    Modified from this TeXSE answer.

    (add-hook 'LaTeX-mode-hook 'add-my-latex-environments)
    (defun add-my-latex-environments ()
      (LaTeX-add-environments
       '("thm" LaTeX-env-label)
       '("prop" LaTeX-env-label)
       '("lem" LaTeX-env-label)
       '("cor" LaTeX-env-label)
       '("defn" LaTeX-env-label)
       '("not" LaTeX-env-label)
       '("rem" LaTeX-env-label)
       '("ex" LaTeX-env-label)
       '("align" LaTeX-env-label)
       '("notation" LaTeX-env-label)
       '("dmath" LaTeX-env-label)
       ))
    
    ;; Code I added to make syntax highlighting work in Auctex
    
    (setq font-latex-math-environments (quote
                                        ("display" "displaymath" "equation" "eqnarray" "gather" "multline"
                                         "align" "alignat" "xalignat" "dmath")))
    (setq TeX-insert-braces 'nil) ;;Stops putting {} on argumentless commands to "save" whitespace
    
    ;; Additionally, reftex code to recognize this environment as an equation
    (setq reftex-label-alist
          '(("dmath" ?e nil nil t)))
    
  2. Special Math Environments

    Stolen from here. Note that these are meant to work with unicode-math.

    (defun org-make-bold-math ()
      "If there's a selection -- wrap this with '\symbf{' and '}'
       and put the point to the end.  Otherwise -- put the point
       between '\symbf{' and '}'
    
       Also: when not in math mode -- enclose the thing in dollars."
    
      (interactive)
    
      (let (start end
                  (delim "")
                  (jump 1)
                  )
    
        (when (not (texmathp))
          (setq delim "$")
          (setq jump 2)
          )
    
        (if (use-region-p)
            (progn
              (setq start (region-beginning))
              (setq end (region-end))
    
              (narrow-to-region start end)
    
              (goto-char (point-min))
              (insert (concat delim "\\symbf{"))
    
              (goto-char (point-max))
              (insert (concat "}" delim))
              (widen)
              )
    
          (progn
            (insert (concat delim "\\symbf{}" delim))
            (backward-char jump)
            )
          )
        ))
    
    
    (defun org-make-blackboard-math ()
      "If there's a selection -- wrap this with '\symbb{' and '}'
       and put the point to the end.  Otherwise -- put the point
       between '\symbb{' and '}'
    
       Also: when not in math mode -- enclose the thing in dollars."
    
      (interactive)
    
      (let (start end
                  (delim "")
                  (jump 1)
                  )
    
        (when (not (texmathp))
          (setq delim "$")
          (setq jump 2)
          )
    
        (if (use-region-p)
            (progn
              (setq start (region-beginning))
              (setq end (region-end))
    
              (narrow-to-region start end)
    
              (goto-char (point-min))
              (insert (concat delim "\\symbb{"))
    
              (goto-char (point-max))
              (insert (concat "}" delim))
              (widen)
              )
    
          (progn
            (insert (concat delim "\\symbb{}" delim))
            (backward-char jump)
            )
          )
        ))
    
    (defun org-make-symrm-math ()
      "If there's a selection -- wrap this with '\symrm{' and '}'
       and put the point to the end.  Otherwise -- put the point
       between '\symrm{' and '}'
    
       Also: when not in math mode -- enclose the thing in dollars."
    
      (interactive)
    
      (let (start end
                  (delim "")
                  (jump 1)
                  )
    
        (when (not (texmathp))
          (setq delim "$")
          (setq jump 2)
          )
    
        (if (use-region-p)
            (progn
              (setq start (region-beginning))
              (setq end (region-end))
    
              (narrow-to-region start end)
    
              (goto-char (point-min))
              (insert (concat delim "\\symrm{"))
    
              (goto-char (point-max))
              (insert (concat "}" delim))
              (widen)
              )
    
          (progn
            (insert (concat delim "\\symrm{}" delim))
            (backward-char jump)
            )
          )
        ))
    
    (defun org-make-vert-math ()
      "If there's a selection -- wrap this with '\vert{' and '}'
       and put the point to the end.  Otherwise -- put the point
       between '\vert{' and '}'
    
       Also: when not in math mode -- enclose the thing in dollars."
    
      (interactive)
    
      (let (start end
                  (delim "")
                  (jump 1)
                  )
    
        (when (not (texmathp))
          (setq delim "$")
          (setq jump 2)
          )
    
        (if (use-region-p)
            (progn
              (setq start (region-beginning))
              (setq end (region-end))
    
              (narrow-to-region start end)
    
              (goto-char (point-min))
              (insert (concat delim "‖"))
    
              (goto-char (point-max))
              (insert (concat "‖" delim))
              (widen)
              )
    
          (progn
            (insert (concat delim "‖‖" delim))
            (backward-char jump)
            )
          )
        ))
    

1.7.7. Anki Editor

These are only relevant to org-mode. Nevertheless they are not part of org-mode so semantically it makes no sense to use o after the localleader.

(map! :localleader
      :map org-mode-map
      (:prefix ("a" . "Anki")
       :desc "Push" "p" 'anki-editor-push-notes
       :desc "Retry" "r" 'anki-editor-retry-failure-notes
       :desc "Insert" "n" 'anki-editor-insert-note
       (:prefix ("c" . "Cloze")
        :desc "Dwim" "d" 'anki-editor-cloze-dwim
        :desc "Region" "r" 'anki-editor-cloze-region
        )
       )
      )

1.7.8. CC Mode

These are basically wrappers around various rtags functions.

;; rtags is no longer installed; using clangd via eglot instead
(nmap
  :prefix my-leader
  :keymaps 'c-mode-base-map
  "m" '(:ignore t :wk "Local Commands")
  "m r" '(:ignore t :wk "Rtags")
  "m r c" '(rtags-check-includes :wk "Check Includes")
  "m r f" '(:ignore t :wk "Find")
  "m r f s" '(:ignore t :wk "Symbol")
  "m r f s a" '(rtags-find-symbol-at-point :wk "At point")
  "m r f s s" '(rtags-find-symbol :wk "Symbol")
  "m r f s c" '(:ignore t :wk "Current")
  "m r f s c f" '(rtags-find-symbol-current-file :wk "File")
  "m r f s c d" '(rtags-find-symbol-current-dir :wk "Directory")
  "m r f f" '(rtags-find-functions-called-by-this-function :wk "Functions")
  "m r f r" '(rtags-find-references :wk "References")
  )

1.7.9. Evil Colemak

These are mostly because movement without hnei is horrible. Read about it here.

(use-package! evil-colemak-basics
  :after evil
  :config
  (setq evil-colemak-basics-rotate-t-f-j t)
  (global-evil-colemak-basics-mode)
  )
  1. Visual Lines

    Since I tend to keep visual-line-mode all the time, evil-better-visual-line is a natural choice.

    (use-package! evil-better-visual-line
      :after evil-colemak-basics
      :config
      (evil-better-visual-line-on)
      (map! :map evil-colemak-basics-keymap
            (:nvm "n" 'evil-better-visual-line-next-line
             :nvm "e" 'evil-better-visual-line-previous-line
             :nvm "g n" 'evil-next-line
             :nvm "g e" 'evil-previous-line))
      )
    
  2. Search

    Harmonizing with Vimium.

    (after! evil (map! :map evil-motion-state-map
                       (:n :desc "Previous match" "K" 'evil-search-previous
                        :n :desc "Next match" "k" 'evil-search-next
                        :n :desc "Forward search" "/" 'evil-search-forward
                        )
                       ))
    
  3. Window Bindings

    These are somehow not part of the evil-colemak setup.

    (after! evil
      (map! :map evil-window-map
            (:leader
             (:prefix ("w" . "Select Window")
              :n :desc "Left"  "h" 'evil-window-left
              :n :desc "Up"    "e" 'evil-window-up
              :n :desc "Down"  "n" 'evil-window-down
              :n :desc "Right" "i" 'evil-window-right
              ))
            ))
    
  4. Page Movement

    Harmonizing with Zathura.

    (after! evil
      (map! :map evil-colemak-basics-keymap
          :nv "N" 'evil-scroll-page-down
          :nv "E" 'evil-scroll-page-up)
      )
    
  5. Evil Org

    Annoyingly, evil-org-mode had a map which kept overriding all my other settings. Thankfully it has a helper variable to set movement. I also do not need this anyway, at-least not by default.

    (after! org
      (remove-hook 'org-mode-hook 'evil-org-mode)
      (setq evil-org-movement-bindings
            '((up . "e") (down . "n")
              (left . "h") (right . "i"))
            )
    )
    

1.7.10. DONE Neotree –> Treemacs

  1. CANCELLED Toggle pane

    This remaps SPC o N to use treemacs. I guess this doesn't make all that much sense, but t and T and bound to terminals and that makes sense, so I guess this is fine.

    ;; Remap opening the sidebar
    (map! :leader
          :nv "o n" nil
          :desc "Open treemacs pane"
          :n "o n" #'+treemacs/toggle)
    ;; Remap finding stuff
    (map! :leader
          :nv "o N" nil
          :desc "Treemacs find file"
          :n "o N" 'treemacs-find-file)
    

    Cancelled since this commit on the develop branch.

1.7.11. TeX Mode

These are more semantic for me.

(nmap
  :prefix my-leader
  :keymaps '(latex-mode-map tex-mode-map LaTeX-mode-map)
  ;; Folding Stuff
  "m f" '(:ignore t :wk "Fold Things")
  "m f c" '(TeX-fold-comment :wk "Comment")
  "m f e" '(TeX-fold-env :wk "Environment")
  "m f m" '(TeX-fold-math :wk "Math")
  ;; Insertions
  "m i" '(:ignore t :wk "Insert")
  "m i m" '(LaTeX-math-mode :wk "Math mode toggle")
  "m i r" '(:ignore t :wk "References")
  "m i r r" '(reftex-citation :wk "Reftex")
  )

1.8. Safe Evals and Variables

1.8.1. MacOS Variables

To use path variables more easily.

(cond ((featurep :system 'macos) (use-package! exec-path-from-shell
                                   :config
                                   (exec-path-from-shell-initialize)
                                   )
       ))

1.8.2. Private Variables

These are encrypted with gpg and are essentially set mostly by custom-*.

(use-package! epa-file
  :demand
  :config
  (epa-file-enable)
  )

Now we set the customize path.

(after! epa-file
  (setq custom-file (concat doom-private-dir "local/private.el.gpg"))
  (load custom-file)
  (rg/bibtex-configure-paths)
  )
  1. MacOS

    On a Mac, when using Nix and Emacs 28, some of the path variables need to be set to find gpg. These should probably be handled through doom env since the terminal does not have trouble finding gpg.

    (cond ((featurep :system 'macos) (custom-set-variables '(epg-gpg-program "/usr/local/bin/gpg")) ;; brew
           (setq exec-path (append exec-path '("/run/current-system/sw/bin"))) ;; nix
           (setq exec-path (append exec-path '("/usr/local/bin/"))) ;; brew
           ))
    
  2. Linux

    Over time I've had to add some more paths…

    (cond
     ((featurep :system 'linux) ;; (eq system-type 'gnu/linux)
      (add-to-list 'exec-path (expand-file-name "~/.local/bin"))
      (add-to-list 'exec-path (expand-file-name "~/.cargo/bin"))
      (add-to-list 'exec-path (expand-file-name "~/.nix-profile/bin"))
      (let ((tex-live-paths (file-expand-wildcards "~/.local/share/texlive-*/bin")))
        (when tex-live-paths
          (setq exec-path (delete-dups (append tex-live-paths exec-path)))
          ))
      ))
    

1.8.3. Safe Variables

The problem is that packages.el isn't being produced by the clever little ugly commit I tried so, this is a workaround to tangle any file to be produced in .el format in the same location.

  1. Tangle

    So adding the automatic tangling code doesn't mangle things up everytime you open emacs.

    (setq safe-local-variable-values '((after-save-hook . haozeke/org-save-and-export-latex)
     (before-save-hook . org-babel-execute-buffer)))
    

1.8.4. Asynchronous Exports

As per this interesting answer on the superuser forums, I need to set org-export-async-init-file.

(setq org-export-async-init-file (concat doom-private-dir "local/async-ox.el"))
(load! "local/rg-compat")
(load! "local/rg-health")
(load! "local/rg-prose")
(load! "local/rg-snapper")
(load! "local/rg-vale")

1.8.5. TRAMP Settings

I use some paths on my remote machines, which are non-standard.

(after! tramp
  (add-to-list 'tramp-remote-path "~/.local/bin")
  (add-to-list 'tramp-remote-path "~/.cargo/bin")
  (add-to-list 'tramp-remote-path "~/.hpc/bin")
  (add-to-list 'tramp-remote-path "~/.local/lsp/bin")
  (add-to-list 'tramp-remote-path "~/.micromamba/envs/lsp/bin/")
  (setq remote-file-name-inhibit-cache 60)
  (setq remote-file-name-inhibit-locks 't)
  (setq tramp-completion-reread-directory-timeout 60)
  (setq tramp-verbose 1)
  (setq tramp-inline-compress-start-size 1000)
  (setq tramp-default-method "sshx")
  (setq vc-ignore-dir-regexp (format "%s\\|%s\\|%s"
                                     vc-ignore-dir-regexp
                                     tramp-file-name-regexp
                                     "[/\\\\]node_modules")
        )
  (setq-default tramp-ssh-controlmaster-options
                "-o ControlMaster=auto -o ControlPath='/tmp/tramp.%%C' -o ControlPersist=90m")
  )

1.8.6. Language Servers

Between lsp-mode and eglot I ended up with eglot for reasons better described here.

(after! eglot
  (add-hook 'nix-mode-hook 'eglot-ensure)
  (add-hook 'f90-mode-hook 'eglot-ensure)
  (set-eglot-client! 'cc-mode '("clangd" "-j=3" "--clang-tidy"))
  (set-eglot-client! 'python-mode '("uvx" "ruff" "server"))
  (set-eglot-client! 'org-mode '("harper-ls" "--stdio"))
  (set-eglot-client! 'markdown-mode '("harper-ls" "--stdio"))
  (set-eglot-client! 'text-mode '("harper-ls" "--stdio"))
  (set-eglot-client! 'latex-mode '("harper-ls" "--stdio"))
  (add-hook 'markdown-mode-hook 'eglot-ensure)
  (when (string= (system-name) "Rohits-MacBook-Pro.local")
    (setq exec-path (append exec-path '(
                                        (concat (getenv "HOME") "/.micromamba/envs/lsp/bin/") ;; python, fortran
                                        (concat (getenv "HOME") "/.local/lsp/bin/") ;; clangd
                                        (concat (getenv "HOME") "/.digestif/bin/") ;; tex
                                        (concat (getenv "HOME") "/.nvm/versions/node/v16.1.0/bin/bash-language-server")
                                        )))
    )
  )

Also booster helps.

(use-package! eglot-booster
  :after eglot
  :commands (eglot-booster-mode)
  :config
  (eglot-booster-mode)
  (set-eglot-client! 'python-mode '("emacs-lsp-booster" "uvx" "ruff" "server"))
  (set-eglot-client! 'cc-mode '("emacs-lsp-booster" "clangd" "-j=3" "--clang-tidy"))
  (set-eglot-client! '(rust-mode rust-ts-mode) '("emacs-lsp-booster" "rust-analyzer"))
  )
  1. Vale and typos

    Prose linting with vale (custom rgoswami style at ~/.config/vale) and spell checking with typos (Rust, low false-positive).

    (flycheck-define-checker vale
      "A checker for prose using vale with custom rgoswami style rules."
      :command ("vale" "--output" "line"
                "--config" (eval (expand-file-name "~/.config/vale/.vale.ini"))
                source)
      :standard-input nil
      :error-patterns
      ((error line-start (file-name) ":" line ":" column ":" (id (one-or-more (not (any ":")))) ":" (message) line-end))
      :modes (markdown-mode gfm-mode org-mode text-mode latex-mode))
    (add-to-list 'flycheck-checkers 'vale 'append)
    
    (flycheck-define-checker typos
      "A spell checker for code and prose using typos (Rust)."
      :command ("typos" "--format" "brief" source)
      :standard-input nil
      :error-patterns
      ((warning line-start (file-name) ":" line ":" column ": " (message) line-end))
      :modes (markdown-mode gfm-mode org-mode text-mode latex-mode
              python-mode rust-mode c-mode c++-mode nim-mode
              emacs-lisp-mode sh-mode yaml-mode))
    (add-to-list 'flycheck-checkers 'typos 'append)
    
    (after! flycheck
      (add-to-list 'flycheck-disabled-checkers 'org-lint)
      (dolist (hook '(org-mode-hook markdown-mode-hook gfm-mode-hook
                      text-mode-hook latex-mode-hook))
        (add-hook hook #'rg/prose-flycheck-on-save)))
    

1.9. Package Settings

These should eventually go into a different module. Each of these.

1.9.1. Word wrap

This section is to work with the settings for the word-wrap doom module.

;; enable word-wrap in C/C++/ObjC/Java
(add-hook! 'markdown-mode-hook #'+word-wrap-mode)
(add-hook! 'text-mode-hook #'+word-wrap-mode)
(add-hook! 'tex-mode-hook #'+word-wrap-mode)

1.9.2. Spellings

(after! spell-fu
  (let ((word-list "/usr/share/dict/cracklib-small"))
    (when (file-readable-p word-list)
      (setq ispell-alternate-dictionary word-list)))
  (setq spell-fu-idle-delay 0.5 ; default is 0.25
        ispell-program-name "aspell"
        ispell-extra-args '("--sug-mode=ultra")
        ispell-dictionary "en_US"
        ispell-personal-dictionary "~/.aspell.en.pws"
        spell-fu-dictionary "~/.config/dict")
  (ispell-change-dictionary "american" t)
  )

Also, it gets annoying to have spell check enabled while working with code.

;; Can always be enabled with SPC t s
(remove-hook 'text-mode-hook #'spell-fu-mode)

1.9.3. Magit Aids

  1. DONE Magit todos

    Of course this is not really meant to be here.. A variation of this was included upstream in the develop branch.

    (use-package! magit-org-todos
      :mode "\\COMMIT_EDITMSG\\'"
      :commands (magit-org-todods magit-org-todos-autoinsert)
      :config
      (magit-org-todos-autoinsert))
    
    ;; (use-package! magit-todos)
    
  2. DONE Magithub

    This is for sweet github integration. Also integrated upstream.

    (use-package! magithub
      :after magit
      :commands (magithub-clone
                 magithub-completion-enable)
      ;; :ensure t
      :config
      (magithub-feature-autoinject t)
      (setq
       magithub-clone-default-directory "$HOME/Git/Github/"
       magithub-dir (concat doom-etc-dir "magithub/")
       magithub-preferred-remote-method 'clone_url))
    (use-package! evil-magit :after magit
                  :init
                  (setq evil-magit-state 'normal))
    
  3. DONE Magit Delta
    (use-package! magit-delta
      :if (executable-find "delta")
      :hook (magit-mode . magit-delta-mode)
      :config
      ;; Kanged https://github.com/dandavison/magit-delta/issues/13
      ;; This ensures the "magit-delta" feature is enabled
      ;; to configure delta's behavior specifically for Magit.
      (unless (member "--features" magit-delta-delta-args)
        (setq magit-delta-delta-args
              (append magit-delta-delta-args '("--features" "magit-delta"))))
    
      ;; Define a function to toggle magit-delta and refresh the buffer.
      (defun hz/magit-delta-toggle ()
        "Toggle magit-delta-mode and refresh magit."
        (interactive)
        (magit-delta-mode (if magit-delta-mode -1 1))
        (magit-refresh))
      :general
      (:keymaps 'magit-mode-map
       :states 'normal
       :prefix ","
       "t" '(hz/magit-delta-toggle :wk "toggle magit-delta"))
      )
    

    Currently there are still performance issues, which is why the toggle keybinding is useful, however, there is a nicer workaround, simply disable for larger diffs as described here. Eventually this should be fixed somewhere else.

    (defvar hz/magit-delta-point-max 50000)
    ;; Disable mode if there are too many characters
    (advice-add 'magit-delta-call-delta-and-convert-ansi-escape-sequences :around
                (defun hz/magit-delta-colorize-maybe-a (fn &rest args)
                  (if (<= (point-max) hz/magit-delta-point-max)
                      (apply fn args)
                    (magit-delta-mode -1))))
    ;; Re-enable mode after `magit-refresh' if there aren't too many characters
    (add-hook 'magit-post-refresh-hook
              (defun hz/magit-enable-magit-delta-maybe-h (&rest _args)
                (when (and (not magit-delta-mode)
                           (<= (point-max) hz/magit-delta-point-max))
                  (magit-delta-mode +1))))
    

1.9.4. PDF Tools

These bindings are essentially part of org-noter however, they do not actually need to be bound in org-mode files. Also updated to have evil-colemak bindings.

(after! pdf-view
  ;; open pdfs scaled to fit page
  (setq-default pdf-view-display-size 'fit-width)
  (add-hook! 'pdf-view-mode-hook (evil-colemak-basics-mode -1))
  ;; automatically annotate highlights
  (setq pdf-annot-activate-created-annotations t
        pdf-view-resize-factor 1.1)
  ;; faster motion
  (map!
   :map pdf-view-mode-map
   :n "g g"          #'pdf-view-first-page
   :n "G"            #'pdf-view-last-page
   :n "N"            #'pdf-view-next-page-command
   :n "E"            #'pdf-view-previous-page-command
   :n "e"            #'evil-collection-pdf-view-previous-line-or-previous-page
   :n "n"            #'evil-collection-pdf-view-next-line-or-next-page
   :localleader
   (:prefix "o"
            (:prefix "n"
             :desc "Insert" "i" 'org-noter-insert-note
             ))
   ))

1.10. Anki Editor

This is for my favorite anki interaction mechanism.

(use-package! anki-editor
  :after org-noter
  :config
  ; I like making decks
  (setq anki-editor-create-decks 't))

1.11. Org Additions

These are numerous and complicated enough to be in a segment of their own.

1.11.1. todo Modifications

I like having the date on my TODO items.

(setq org-log-done "time"
      org-log-done-with-time 't)

1.11.2. Ignore Support

For the longest time I was setting this per file for bizarre reasons. This makes much more sense.

(use-package! ox-extra
  :after org
  :config
  (ox-extras-activate '(ignore-headlines))
  )

1.11.3. File Handling

This controls what is used to open links in org documents. Since there are only a few defaults defined, I am just prepending them to my changes instead of dealing with append and stuff.

(setq org-file-apps
  '((auto-mode . emacs)
    ("\\.mm\\'" . default)
    ("\\.x?html?\\'" . default)
    ("\\.pdf\\'" . default)
    ("\\.png\\'" . viewnior)
    ("\\.jpg\\'" . viewnior)
    ("\\.svg\\'" . viewnior)
    ))

1.11.4. Ob-Mermaid

(use-package! mermaid-mode)
(use-package! ob-mermaid)

1.11.5. Org Download

This is already included in the standard doom setup. However, I was having trouble with relative exports so I have this one instead. Partially kanged from doom-emacs. Before setting this up, a new function is defined to call the screenshot process, this setup is kanged from here.

;; From https://github.com/poligen/dotfiles/blob/25785810f9bf98f6eec93e400c686a4ad65ac310/doom.d/config.el
;; My customized org-download to incorporate flameshot gui Workaround to setup flameshot, which enables annotation.
;; In flameshot, set filename as "screenshot", and the command as "flameshot gui -p /tmp", so that we always ends up
;; with /tmp/screenshot.png. Nullify org-download-screenshot-method by setting it to `echo', so that essentially we
;; are only calling (org-download-image org-download-screenshot-file).
(defun hz-org-download-screenshot ()
  "Capture screenshot and insert the resulting file.
The screenshot tool is determined by `org-download-screenshot-method'."
  (interactive)
  (let ((tmp-file "/tmp/screenshot.png"))
    (delete-file tmp-file)
    (call-process-shell-command "flameshot gui -p /tmp/")
    ;; Because flameshot exit immediately, keep polling to check file existence
    (while (not (file-exists-p tmp-file))
      (sleep-for 2))
    (org-download-image tmp-file)))

Now we can configure the package itself.

(use-package! org-download
  :after org
  :config
  (setq-default org-download-image-dir "./images/"
                ;; org-download-screenshot-method "flameshot gui --raw > %s"
                org-download-delete-image-after-download t
                org-download-method 'directory
                org-download-heading-lvl 1
                org-download-screenshot-file "/tmp/screenshot.png"
                )
  (cond ((featurep :system 'linux)
         (if (getenv "WAYLAND_DISPLAY")
             (setq-default org-download-screenshot-method "grim -g \"$(slurp)\" - > %s")
           (setq-default org-download-screenshot-method "xclip -selection clipboard -t image/png -o > %s")
           )
         )
        ((featurep :system 'macos) (setq-default org-download-screenshot-method "screencapture -i %s")))
  )

1.11.6. Org Babel

Julia and Mathematica are not set. Other languages might also be needed here eventually.

(after! org
  (org-babel-do-load-languages 'org-babel-load-languages
                               (append org-babel-load-languages
                                       ;; '((julia . t))
                                       '((mathematica . t))
                                       '((ditaa . t))
                                       )))
(setq org-babel-mathematica-command "~/.local/bin/mash"
      org-ditaa-jar-path (concat (getenv "HOME") "/.local/bin/ditaa0_9.jar")
)

1.11.7. Org CV

(use-package! ox-awesomecv
  :after org
  :config
  (defun hz/org-export-to-file-awesomecv-tex ()
    (interactive)
    (let ((outfile (org-export-output-file-name ".tex")))
      (org-export-to-file 'awesomecv outfile)))
  )

Usage is from stotok and the zzamboni configurations.

(use-package! ox-moderncv
  :after org
  :config
  (defun hz/org-export-to-file-moderncv-tex ()
    (interactive)
    (let ((outfile (org-export-output-file-name ".tex")))
      (org-export-to-file 'moderncv outfile)))
  )

1.11.8. Async Org Babel

From here. Now we can configure this.

(use-package! org-babel-eval-in-repl
  :after org
  :config
  (setq eir-jump-after-eval nil)
  )

1.11.9. Org Config

These are just variables I need to set to prevent things from dying.

  1. Highlighting LaTeX

    For better font-locking within orgmode.

    (setq org-latex-preview '(native latex script entities))
    
  2. Default packages for XeLaTeX

    Unicode math with tectonic (XeLaTeX by default). No need for inputenc / fontenc conditionals since we never use pdflatex. Minted removed in favor of engrave-faces (set in shared preferences).

    (setq org-latex-packages-alist 'nil)
    (setq org-latex-default-packages-alist
          '((""     "graphicx"  t)
            (""     "longtable" nil)
            (""     "wrapfig"   nil)
            (""     "rotating"  nil)
            ("normalem" "ulem"  t)
            (""     "amsmath"   t)
            (""     "amssymb"   t)
            (""     "unicode-math"   t)
            (""     "mathtools"   t)
            (""     "textcomp"  t)
            (""     "capt-of"   nil)
            (""     "hyperref"  nil)))
    (after! org
      (plist-put org-format-latex-options :scale 2.2)
      ;; tectonic-based preview via dvisvgm (SVG, theme-aware)
      (add-to-list 'org-preview-latex-process-alist
                   '(dvisvgm-tectonic :programs ("tectonic" "dvisvgm")
                     :description "xdv > svg"
                     :image-input-type "xdv" :image-output-type "svg"
                     :image-size-adjust (1.7 . 1.5)
                     :latex-compiler ("tectonic -X compile --outfmt xdv --keep-logs -o %o %f")
                     :image-converter ("dvisvgm %f -n -b min -c %S -o %O")))
      )
    
  3. Inline images

    Previews via tectonic + dvisvgm for SVG output (theme-aware, sharp at any scale).

    (after! org
      (setq org-preview-latex-default-process 'dvisvgm-tectonic)
      (setq org-startup-with-inline-images 'nil)
      (setq org-image-actual-width 400)
      )
    

1.11.10. Org Latex Subfigure

This modified environment makes it easier to work with reports.

;; TODO: Figure out how to pass parameters other than width
;; TODO: Also make a subcaption label
(org-link-set-parameters
 "subfig"
 :follow (lambda (file) (find-file file))
 :face '(:foreground "chocolate" :weight bold :underline t)
 :display 'full
 :export (lambda (file desc backend)
           (when (eq backend 'latex)
             (if (string-match ">(\\(.+\\))" desc)
                 (concat "\\begin{subfigure}[b]{"
                         (match-string 1 desc)
                         "}\\caption{" (replace-regexp-in-string "\s+>(.+)" "" desc) "}"
                         "\\includegraphics"
                         "["
                         "width=\\textwidth"
                         "]"
                         "{"
                         file
                         "}"
                         "\\end{subfigure}"
                         )
               (format "\\begin{subfigure}[b]{\\textwidth}\\includegraphics{%s}\\caption{%s}\\end{subfigure}" file desc)))))
  1. Prevent invisible area modifications

    First discussed here. The invisible area modifications are a plague. I can't imagine why this is not set by default.

    (setq org-catch-invisible-edits 'show-and-error)
    
  2. Compact subtrees

    We would like to not have additional newlines between trees.

    (setq org-cycle-separator-lines 0)
    

1.11.11. Org Search (replaces helm-org-rifle)

org-ql for structured queries across org files (headings + content + tags + properties). consult-org-heading for quick heading jumps in current buffer / agenda. Together they cover everything helm-org-rifle did but with vertico.

(use-package! org-ql
  :after org
  :commands (org-ql-search org-ql-view org-ql-find))

(after! org
  (map! :leader
        (:prefix ("o" . "open")
         :desc "Org heading (buffer)" "h" #'consult-org-heading
         :desc "Org heading (agenda)" "H" #'consult-org-agenda
         :desc "Org-ql find" "q" #'org-ql-find
         :desc "Org-ql search" "Q" #'org-ql-search)))

1.11.12. Org Mind Map

This is used to create graphiz graphs from org-mode stuff.

(use-package! org-mind-map
  :general
  (:keymaps 'org-mode-map
   :states 'normal
   :prefix my-leader
   "m e m" '(org-mind-map-write :wk "Export mind-map") ))

1.11.13. Org Modern

(use-package! org-modern
  :after org
  :config
  (setq global-org-modern-mode t)
)

1.11.14. Org Appear

Reveal hidden markup (emphasis, links, subscripts, entities) when cursor is on them.

(use-package! org-appear
  :hook (org-mode . org-appear-mode)
  :config
  (setq org-hide-emphasis-markers t
        org-appear-autoemphasis t
        org-appear-autolinks t
        org-appear-autosubmarkers t
        org-appear-autoentities t))

1.11.15. LaTeX Auto-Activating Snippets

Context-aware auto-expanding snippets in math environments. Typing sr expands to \sqrt{}, // to \frac{}{}, etc.

(use-package! laas
  :hook ((LaTeX-mode . laas-mode)
         (org-mode . laas-mode)))

1.11.16. Ox-Chameleon

Theme-matching LaTeX PDF exports. Picks up the current Emacs theme colors for headings, links, and source blocks so exported PDFs stay consistent with the editor appearance.

(after! ox
  (require 'ox-chameleon))

1.11.17. Org Glossary

Glossaries, acronyms, and index support for org documents. Define terms in a :glossary: drawer and reference them with gls:term links.

(use-package! org-glossary
  :hook (org-mode . org-glossary-mode))

1.11.18. OrgDiff

Visual diffs of org files via latexdiff on exported LaTeX. Integrates with magit for commit-to-commit comparison. Requires latexdiff from texlive.

(use-package! orgdiff
  :after org
  :config
  (let ((texlive-bin (car (file-expand-wildcards
                           (expand-file-name "~/.local/share/texlive-*/bin/x86_64-linux")))))
    (when texlive-bin
      (add-to-list 'exec-path texlive-bin)
      (setenv "PATH" (concat texlive-bin ":" (getenv "PATH"))))))

1.11.19. Org Gantt

Useful TeX generator.

(use-package! org-gantt
 :after org)

1.11.20. Org Drill

It makes sense to keep this around so as to leverage existing resources.

;;(use-package! org-drill
;;  :after org)

1.11.21. Org Re-Reveal Additions

We will load a couple of helpers to get functionality closer to emacs-reveal. This is apparently the org-ref for org-re-reveal. For themes (e.g. robot-lung), we have a new directory. We would also now keep a local copy of our revealjs setup.

(after! org-re-reveal
  (use-package! org-re-reveal-ref) ; fixes org-ref
  (setq reveal-extras (concat doom-private-dir "reveal/extras/")
        org-re-reveal-root (concat doom-private-dir "reveal/rjs/")
        sfeir-root (concat doom-private-dir "reveal/sfeir-school-theme/"))
)

Note that this needs to be updated manually since themes change.

1.11.22. Org GCal

Note that we configure this as per the README in the private configuration since all of these are very personal.

(use-package! org-gcal)

1.11.23. ox-hugo Settings

This should be set for everything. I like to keep the last modified date, but only consider things to be modified if 12 hours have passed.

(let* ((hugo-section "posts")
       (emacs-major-version (car (version-to-list emacs-version)))
       (emacs-minor-version (nth 1 (version-to-list emacs-version)))
       (org-mode-version org-version)
       (hugo-creator-string (format "Emacs %s.%s (Org mode %s + ox-hugo + HaoZeke)"
                                    emacs-major-version
                                    emacs-minor-version
                                    org-mode-version))
       (org-creator-string (format "Emacs %s.%s (Org mode %s + HaoZeke)"
                                   emacs-major-version
                                   emacs-minor-version
                                   org-mode-version))
       (auto-set-lastmod 't)
       (suppress-period 43200.0))
  (setq org-hugo-auto-set-lastmod auto-set-lastmod
        org-hugo-section hugo-section
        org-hugo-suppress-lastmod-period suppress-period
        org-hugo-export-creator-string hugo-creator-string
        org-export-creator-string org-creator-string))

1.11.24. Citeproc

I also like to have rational and numbered citations.

(after! ox-hugo
  (use-package! citeproc-org
    :config
    (citeproc-org-setup)
    (setq citeproc-org-org-bib-header "* References\n")
    )
  )

We will now lower the heading to the appropriate level. This is kanged from TimQuelch.

(after! citeproc-org
  (defun hz/min-headline-level ()
    (--> (org-element-parse-buffer)
         (org-element-map it 'headline (apply-partially #'org-element-property :level))
         (or it '(0))
         (-min it)))

  (defadvice! hz/citeproc-org-render-references (orig &rest args)
    :around 'citeproc-org-render-references
    (let* ((minlevel (hz/min-headline-level))
           (totallevel (max 1 minlevel))
           (citeproc-org-org-bib-header (concat (make-string totallevel ?*)
                                                (string-trim-left citeproc-org-org-bib-header "\\**"))))
      (apply orig args))))

1.11.25. CalcTeX

Writing TeX math can be painful, in-spite of all the unicode and other fancy tricks. This makes things a lot more feasible. Some of the configuration is directly lifted from Tecosaur's configuration.

(use-package! calctex
  :commands calctex-mode
  :init
  (add-hook 'calc-mode-hook #'calctex-mode)
  :config
  (setq calctex-additional-latex-packages "
\\usepackage[usenames]{xcolor}
\\usepackage{soul}
\\usepackage{adjustbox}
\\usepackage{amsmath}
\\usepackage{amssymb}
\\usepackage{siunitx}
\\usepackage{cancel}
\\usepackage{mathtools}
\\usepackage{mathalpha}
\\usepackage{xparse}
\\usepackage{arevmath}"
        calctex-additional-latex-macros
        (concat calctex-additional-latex-macros
                "\n\\let\\evalto\\Rightarrow"))
  (defadvice! no-messaging-a (orig-fn &rest args)
    :around #'calctex-default-dispatching-render-process
    (let ((inhibit-message t) message-log-max)
      (apply orig-fn args)))
  ;; Fix hardcoded dvichop path (whyyyyyyy)
  (let ((vendor-folder (concat (file-truename doom-local-dir)
                               "straight/"
                               (format "build-%s" emacs-version)
                               "/calctex/vendor/")))
    (setq calctex-dvichop-sty (concat vendor-folder "texd/dvichop")
          calctex-dvichop-bin (concat vendor-folder "texd/dvichop")))
  (unless (file-exists-p calctex-dvichop-bin)
    (message "CalcTeX: Building dvichop binary")
    (let ((default-directory (file-name-directory calctex-dvichop-bin)))
      (call-process "make" nil nil nil))))

Now we would like also to have a sidebar for working in the embedded mode.

(defvar calc-embedded-trail-window nil)
(defvar calc-embedded-calculator-window nil)

(defadvice! calc-embedded-with-side-pannel (&rest _)
  :after #'calc-do-embedded
  (when calc-embedded-trail-window
    (ignore-errors
      (delete-window calc-embedded-trail-window))
    (setq calc-embedded-trail-window nil))
  (when calc-embedded-calculator-window
    (ignore-errors
      (delete-window calc-embedded-calculator-window))
    (setq calc-embedded-calculator-window nil))
  (when (and calc-embedded-info
             (> (* (window-width) (window-height)) 1200))
    (let ((main-window (selected-window))
          (vertical-p (> (window-width) 80)))
      (select-window
       (setq calc-embedded-trail-window
             (if vertical-p
                 (split-window-horizontally (- (max 30 (/ (window-width) 3))))
               (split-window-vertically (- (max 8 (/ (window-height) 4)))))))
      (switch-to-buffer "*Calc Trail*")
      (select-window
       (setq calc-embedded-calculator-window
             (if vertical-p
                 (split-window-vertically -6)
               (split-window-horizontally (- (/ (window-width) 2))))))
      (switch-to-buffer "*Calculator*")
      (select-window main-window))))

1.12. Syntax Highlighting

This section is for setting up major modes for various file formats which are typically non-standard. These are matched by extensions.

1.12.1. TODO Misc Highlighting

  1. Direnv

    direnv is essentially a specialized bash script. Until I have time to make a proper font locking mode for it, this should suffice.

    (setq auto-mode-alist (append '(("\\.envrc$" . shell-script-mode))
                                  auto-mode-alist))
    
  2. Vim

    I still keep my vim dotfiles up to date…

    (use-package! vimrc-mode
      :mode "\\.vimrc\\'")
    

1.12.2. CPP Additions

  1. Doxygen Support
    (use-package! highlight-doxygen
      :hook ((c-mode c++-mode) . highlight-doxygen-mode))
    
  2. More Files

    inl files are often used for extended header definitions.

    (setq auto-mode-alist (append '(
                                    ("\\.C$" . c++-mode)
                                    ("\\.cc$" . c++-mode)
                                    ("\\.cpp$" . c++-mode)
                                    ("\\.inl$" . c++-mode)
                                    ("\\.H$" . c++-mode)
                                    ("\\.hh$" . c++-mode)
                                    ("\\.hpp$" . c++-mode)
                                    )
                                  auto-mode-alist))
    

1.12.3. Fortran

By default, fortran-mode is used for f90 files which is less than ideal.

(setq auto-mode-alist (append '(
                                ("\\.f\\'" . fortran-mode)
                                ("\\.f77\\'" . fortran-mode)
                                ("\\.f90\\'" . f90-mode)
                                ("\\.F90\\'" . f90-mode)
                                )
                              auto-mode-alist))

1.12.4. Quarto

Not a fan, but is still occasionally useful.

(use-package! quarto-mode)

1.12.5. Meson

Mostly used with cpp files.

(use-package! meson-mode
  :mode "\\.build\\'"
  :config
  (when (modulep! :completion company)
    (add-hook!'meson-mode-hook 'company-mode))
  )

1.12.6. xonsh Mode

(use-package! xonsh-mode
  :mode "\\.xsh\\'"
  :config
  (when (modulep! :completion company)
    (add-hook!'xonsh-mode-hook 'company-mode))
  )

1.12.7. PKGBUILD Mode

This is the non doom way of loading this.

(autoload 'pkgbuild-mode "pkgbuild-mode.el" "PKGBUILD mode." t)
(setq auto-mode-alist (append '(("/PKGBUILD$" . pkgbuild-mode))
                              auto-mode-alist))

I use doom. So.

(use-package! pkgbuild-mode
  :mode "\\PKGBUILD")

1.12.8. LAMMPS Mode

  1. No doom setup

    For most users.

    (autoload 'lammps-mode "lammps-mode.el" "LAMMPS mode." t)
    (setq auto-mode-alist (append
                                  '(("in\\.'" . lammps-mode))
                                  '(("\\.lmp\\'" . lammps-mode))
                                  auto-mode-alist
                                  ))
    
  2. Doom Version

    With macros.

    (use-package! lammps-mode)
    (setq auto-mode-alist (append
                                  '(("in\\.'" . lammps-mode))
                                  '(("\\.lmp\\'" . lammps-mode))
                                  auto-mode-alist
                                  ))
    

1.12.9. Pug Mode

Need better font locking everywhere.

(use-package! pug-mode
  :mode "\\.pug\\'")

1.12.10. Conf Mode Files

The rc files are usually encountered while building android stuff. They are handled well by conf-mode. Turns out that vmd files also look just like conf-mode things…

(setq auto-mode-alist
             (append
             '(("\\.rc\\'" . conf-mode))
             '(("\\.vmd\\'" . conf-mode))
             auto-mode-alist
             ))

1.12.11. JVM Languages

Since java+meghnada, clojure, and scala are covered by the standard doom config, the rest of these need to be loaded here.

(use-package! kotlin-mode
  :mode "\\.kt\\'")

(use-package! groovy-mode
  :mode "\\.groovy\\'")

1.12.12. Systemd

For all those user-units.

(use-package! systemd
  :mode "\\.service\\'")

1.12.13. Dart Mode

Dart seems like a rather fun C-like language. Sort of fallen on the wayside what with Golang and what not but still might be worth a shot.

(use-package! dart-mode
  :mode "\\.dart\\'")

1.12.14. SaltStack

I like having spell checks for everything.

;; Load it
(use-package! salt-mode
  :config
;; Flyspell
(add-hook 'salt-mode-hook
        (lambda ()
            (flyspell-mode 1))))

1.12.15. Mathematica

Apparently, wolfram-mode is the best for syntax highlighting.

;; Load it
(use-package! wolfram-mode
  :config
  (setq mathematica-command-line "~/.local/bin/mash")
  (add-to-list 'org-src-lang-modes '("mathematica" . wolfram)))

1.12.16. Snakemake

(use-package! snakemake-mode
  :mode "\\.smk"
  )
(after! snakemake-mode
  (set-formatter! 'snakefmt '("uvx" "snakefmt" "-") :modes '(snakemake-mode))
)

1.12.17. CapnProto

(use-package! capnp-mode
    :mode "\\.capnp")

1.12.18. Nushell

(use-package! nushell-mode
    :mode "\\.nu")

1.12.19. Fish shell

(use-package! fish-mode
    :mode "\\.fish")

1.12.20. Nickel

(use-package! nickel-mode
  :mode "\\.ncl"
  )
(after! nickel-mode
  (set-formatter! 'nickelfmt
    '("nickel" "format")
    :modes '(nickel-mode))
  )

1.12.21. Meson

There is in built support for meson but it has no registered formatter.

(after! meson-mode
  (set-formatter! 'mesonfmt
    '("meson" "format")
    :modes '(meson-mode))
  )

1.12.22. R

I now use pixi to handle some of this.. so.

pixi global add --environment r_env r-styler --expose pixiR=R
(set-formatter!
  'rstyler
  '("pixiR" "-s" "--no-save" "--no-restore" "-e" "styler::style_text(readLines(file('stdin')))")
  :modes '(ess-r-mode))

Also nice to use essgd:

(use-package! essgd
  :after ess-r-mode
  :commands (essgd-start))

1.12.23. Astro

;; (setq treesit-language-source-alist
;;       '((astro "https://github.com/virchau13/tree-sitter-astro")
;;         (css "https://github.com/tree-sitter/tree-sitter-css")
;;         (tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src")))
;; (mapc #'treesit-install-language-grammar '(astro css tsx))
;; (use-package! astro-ts-mode
;;     :mode "\\.astro")

1.12.24. Dockerfile Mode

This package from spotify has support for building things as well as highlighting Dockerfiles.

(use-package! dockerfile-mode
  :mode "Dockerfile\\'"
  :config
  (put 'dockerfile-image-name 'safe-local-variable #'stringp)
  )

1.13. Aesthetics

1.13.1. Wakatime

Was removed from the core modules of doom-emacs.

(use-package! wakatime-mode
  :config
  (cond ((featurep :system 'linux) (setq wakatime-cli-path "/usr/bin/wakatime"))
        ((featurep :system 'macos) (setq wakatime-cli-path "/usr/local/bin/wakatime-cli")) ;; We assume homebrew
        )
  )

1.14. Functions

1.14.1. Org-Export HTML with useful IDs

This minor mode from here is crucial to having sane reveal-js slides which don't keep jumping back to the title slide on every export.

(define-minor-mode unpackaged/org-export-html-with-useful-ids-mode
  "Attempt to export Org as HTML with useful link IDs.
Instead of random IDs like \"#orga1b2c3\", use heading titles,
made unique when necessary."
  :global t
  (if unpackaged/org-export-html-with-useful-ids-mode
      (advice-add #'org-export-get-reference :override #'unpackaged/org-export-get-reference)
    (advice-remove #'org-export-get-reference #'unpackaged/org-export-get-reference)))

(defun unpackaged/org-export-get-reference (datum info)
  "Like `org-export-get-reference', except uses heading titles instead of random numbers."
  (let ((cache (plist-get info :internal-references)))
    (or (car (rassq datum cache))
        (let* ((crossrefs (plist-get info :crossrefs))
               (cells (org-export-search-cells datum))
               ;; Preserve any pre-existing association between
               ;; a search cell and a reference, i.e., when some
               ;; previously published document referenced a location
               ;; within current file (see
               ;; `org-publish-resolve-external-link').
               ;;
               ;; However, there is no guarantee that search cells are
               ;; unique, e.g., there might be duplicate custom ID or
               ;; two headings with the same title in the file.
               ;;
               ;; As a consequence, before re-using any reference to
               ;; an element or object, we check that it doesn't refer
               ;; to a previous element or object.
               (new (or (cl-some
                         (lambda (cell)
                           (let ((stored (cdr (assoc cell crossrefs))))
                             (when stored
                               (let ((old (org-export-format-reference stored)))
                                 (and (not (assoc old cache)) stored)))))
                         cells)
                        (when (org-element-property :raw-value datum)
                          ;; Heading with a title
                          (unpackaged/org-export-new-title-reference datum cache))
                        ;; NOTE: This probably breaks some Org Export
                        ;; feature, but if it does what I need, fine.
                        (org-export-format-reference
                         (org-export-new-reference cache))))
               (reference-string new))
          ;; Cache contains both data already associated to
          ;; a reference and in-use internal references, so as to make
          ;; unique references.
          (dolist (cell cells) (push (cons cell new) cache))
          ;; Retain a direct association between reference string and
          ;; DATUM since (1) not every object or element can be given
          ;; a search cell (2) it permits quick lookup.
          (push (cons reference-string datum) cache)
          (plist-put info :internal-references cache)
          reference-string))))

(defun unpackaged/org-export-new-title-reference (datum cache)
  "Return new reference for DATUM that is unique in CACHE."
  (cl-macrolet ((inc-suffixf (place)
                  `(progn
                     (string-match (rx bos
                                       (minimal-match (group (1+ anything)))
                                       (optional "--" (group (1+ digit)))
                                       eos)
                                   ,place)
                     ;; HACK: `s1' instead of a gensym.
                     (-let* (((s1 suffix) (list (match-string 1 ,place)
                                                (match-string 2 ,place)))
                             (suffix (if suffix
                                         (string-to-number suffix)
                                       0)))
                       (setf ,place (format "%s--%s" s1 (cl-incf suffix)))))))
    (let* ((title (org-element-property :raw-value datum))
           (ref (url-hexify-string (substring-no-properties title)))
           (parent (org-element-property :parent datum)))
      (while (--any (equal ref (car it))
                    cache)
        ;; Title not unique: make it so.
        (if parent
            ;; Append ancestor title.
            (setf title (concat (org-element-property :raw-value parent)
                                "--" title)
                  ref (url-hexify-string (substring-no-properties title))
                  parent (org-element-property :parent parent))
          ;; No more ancestors: add and increment a number.
          (inc-suffixf ref)))
      ref)))

1.14.2. Org-mode export pdf when saved

This one is to generate pdfs whenever a buffer is saved. Mainly taken from this stack exchange question.

; Pdf
(defun haozeke/org-save-and-export-pdf ()
  (if (eq major-mode 'org-mode)
    (org-latex-export-to-pdf :async t)))

1.14.3. Org-mode export koma-letter

Since the koma-letter backend is separate, this needs a function as well.

(defun haozeke/org-save-and-export-koma-letter-pdf ()
  (if (eq major-mode 'org-mode)
    (org-koma-letter-export-to-pdf)))

1.14.4. Org-mode export TeX

Similar to the one above, but tex generation is much faster and this way I can keep editing my files without waiting for it to finish creating the pdf.

; LaTeX
(defun haozeke/org-save-and-export-latex ()
  (interactive)
  (if (eq major-mode 'org-mode)
    (org-latex-export-to-latex t)))
(defun haozeke/org-save-and-export-beamer ()
  (interactive)
  (if (eq major-mode 'org-mode)
    (org-beamer-export-to-latex t)))

1.14.5. Org-mode clear results

;; Kanged from https://emacs.stackexchange.com/a/51378/19155
(defun hz-clear-all-results ()
  "Clear all results in the buffer."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (org-babel-next-src-block)
      (org-babel-remove-result))))

1.14.6. TODO Caveats

  • Minted needs to be setup.
  • There are really a lot of optimizations to the above.

1.14.7. Helper function

Figure out if I can replicate this some other way. Taken from sam217pa's github repo.

;; this function is used to append multiple elements to the list 'ox-latex
(defun append-to-list (list-var elements)
  "Append ELEMENTS to the end of LIST-VAR. The return value is the new value of LIST-VAR."
  (unless (consp elements) (error "ELEMENTS must be a list"))
  (let ((list (symbol-value list-var)))
    (if list
        (setcdr (last list) elements)
      (set list-var elements)))
(symbol-value list-var))

1.14.8. Async Command without Buffers

This supresses the output window. Useful for when I do async exports. From this question.

(defun async-shell-command-no-window
    (command)
  (interactive)
  (let
      ((display-buffer-alist
        (list
         (cons
          "\\*Async Shell Command\\*.*"
          (cons #'display-buffer-no-window nil)))))
    (async-shell-command
     command)))

1.14.9. Better Rust Formatting

Some of these are kanged from here.

(setq rustic-format-on-save t
      ;; rustfmt uses `--edition 2015` by default. For now, 2021 seems to be a
      ;; reasonable alternative.
      rustic-rustfmt-args "--edition 2021")

1.14.10. Smarter Clang Formatting

This is taken from this blog.

(defun haozeke/clang-format-buffer-conditional ()
(interactive)
  "Reformat buffer if .clang-format exists in the projectile root."
  (when (f-exists? (expand-file-name ".clang-format" (projectile-project-root)))
    (+format/buffer)))

1.14.11. Org-mode export to Markdown

This is a convinience function for working with nanoc.

(defun haozeke/org-pandoc-markdown (dir &optional pargs)
  "A wrapper to generate yaml metadata markdown files. Takes the output
  directory followed by pandoc arguments"
  (if (not (file-exists-p dir)) (make-directory dir))
  (async-shell-command-no-window
   (concat "pandoc -f org -t markdown -s " pargs " " (buffer-name) " -o "
           dir "/" (file-name-sans-extension (buffer-name)) ".md"))
    )

1.14.12. Org-mode export for the Carpentries workbench

(defun export-as-workbench-md ()
  "Save, strip the export line via grep, and pipe to Pandoc."
  (interactive)
  (save-buffer)
  (let* ((src (buffer-file-name))
         ;; Get the filename from the buffer keywords
         (kv  (org-collect-keywords '("EXPORT_FILE_NAME")))
         (out (or (cadr (assoc "EXPORT_FILE_NAME" kv))
                  (concat (file-name-sans-extension src) ".md")))
         ;; Grep excludes the line -> Pipe -> Pandoc
         (cmd (format "grep -v '^#+EXPORT_FILE_NAME:' %s | pandoc -f org -t markdown-smart+fenced_divs -o %s"
                      (shell-quote-argument src)
                      (shell-quote-argument out))))

    (shell-command cmd)
    (message "Exported to %s" out)))

or alternatively a baroque but windows compatible variant without grep.

1.14.13. TODO Smartparens Wrapping

  • [ ] Make this conditional and only when +smartparens is active

This is to define some more wrapping functions I use often (for markdown and org-mode inline code):

(defun sp-wrap-backtick ()
  "Wrap following sexp in backticks."
  (interactive)
  (sp-wrap-with-pair "`"))
(defun sp-wrap-tilda ()
  "Wrap following sexp in tildes."
  (interactive)
  (sp-wrap-with-pair "~"))

1.14.14. Sort words

From the Emacs Wiki.

(defun sort-words (reverse beg end)
  "Sort words in region alphabetically, in REVERSE if negative.
Prefixed with negative \\[universal-argument], sorts in reverse.

The variable `sort-fold-case' determines whether alphabetic case
affects the sort order.

See `sort-regexp-fields'."
  (interactive "*P\nr")
  (sort-regexp-fields reverse "\\w+" "\\&" beg end))

1.14.15. doas helpers

doom-emacs comes with sudo support, these are simply clones with doas instead.

(defun doom--doas-file-path (file)
  (let ((host (or (file-remote-p file 'host) "localhost")))
    (concat "/" (when (file-remote-p file)
                  (concat (file-remote-p file 'method) ":"
                          (if-let (user (file-remote-p file 'user))
                              (concat user "@" host)
                            host)
                          "|"))
            "doas:root@" host
            ":" (or (file-remote-p file 'localname)
                    file))))

(defun doom/doas-find-file (file &optional arg)
  "Open FILE as root.

This will prompt you to save the current buffer, unless prefix ARG is given, in
which case it will save it without prompting."
  (interactive
   (list (read-file-name "Open file as root: ")
         current-prefix-arg))
  ;; HACK: Teach `save-place' to treat the new "remote" buffer as if it were
  ;;   visiting the same local file (because it is), and preserve the cursor
  ;;   position as usual.
  (letf! ((defun remote-local-name (path)
            (if path (or (file-remote-p path 'localname) path)))
          (defmacro with-local-name (&rest body)
            `(when save-place-mode
               (let ((buffer-file-name (remote-local-name buffer-file-name))
                     (default-directory (remote-local-name default-directory)))
                 ,@body))))
    (let ((window-start (window-start))
          (buffer (current-buffer)))
      (when (and buffer-file-name (file-equal-p buffer-file-name file))
        (when (buffer-modified-p)
          (save-some-buffers arg (lambda () (eq (current-buffer) buffer))))
        (with-local-name (save-place-to-alist)))
      (prog1
          ;; HACK: Disable auto-save in temporary tramp buffers because it could
          ;;   trigger processes that hang silently in the background, making
          ;;   those buffers inoperable for the rest of that session (Tramp
          ;;   caches them).
          (let ((auto-save-default nil)
                ;; REVIEW: use only these when we drop 28 support
                (remote-file-name-inhibit-auto-save t)
                (remote-file-name-inhibit-auto-save-visited t)
                ;; Prevent redundant work
                save-place-mode)
            (find-file (doom--doas-file-path (expand-file-name file))))
        ;; Record of the cursor's old position if it isn't at BOB (indicating
        ;; this buffer was already open), in case the user wishes to go to it.
        (unless (bobp)
          (doom-set-jump-h)
          ;; save-place-find-file-hook requires point be a BOB to do its thang.
          (goto-char (point-min)))
        (with-local-name (save-place-find-file-hook))
        (set-window-start nil window-start)))))
(defun doom/doas-this-file ()
  "Open the current file as root on Alpine Linux."
  (interactive)
  (doom/doas-find-file
   (or (buffer-file-name (buffer-base-buffer))
       (when (or (derived-mode-p 'dired-mode)
                 (derived-mode-p 'wdired-mode))
         default-directory)
       (user-error "Current buffer isn't visiting a file"))))

(defun doom/doas-save-buffer ()
  "Save this file as root on Alpine Linux."
  (interactive)
  (let ((file (doom--doas-file-path (buffer-file-name (buffer-base-buffer)))))
    (if-let (buffer (find-file-noselect file))
        (let ((origin (current-buffer)))
          (copy-to-buffer buffer (point-min) (point-max))
          (unwind-protect
              (with-current-buffer buffer
                (save-buffer))
            (unless (eq origin buffer)
              (kill-buffer buffer))
            (with-current-buffer origin
              (revert-buffer t t))))
      (user-error "Unable to open %S" file))))

1.15. Chat Clients

1.15.1. Matrix

Configuring the only emacs chat client I use.

;; (use-package! matrix-client
;;   :init
;;   :commands matrix-client-connect)

1.16. Projects

These are to help setup org-mode workflows.

; Make sure it's not set before adding to it
(unless (boundp 'org-publish-project-alist)
  (setq org-publish-project-alist nil))

1.16.1. dotdoom

This is used to generate plain HTML for my dotdoom repo. The setup is taken from the worg documentation and this repository. It so turns out that we can host the entire thing from the master branch on GitHub, but only if it is in a docs/ subfolder… Plus org-html-export-to-html does not accept filenames which was a real bummer.

; dotdoom publishing
; This is a rather harmless useful variable
(setq dotdoom-root-dir "~/.config/doom/")
(setq dotdoom-publish-dir  (concat dotdoom-root-dir "docs"))

Now that the variables are set, we can move on to actually setting up the rest of the export, this includes my own analytics and stuff. Infact maybe the analytics would be better handled by offloading the damn thing to Netlify, though their recent changes to the TOS are worrying, so Microsoft owned GitHub seems to be the better option for now.

  1. Org Setup

    It turns out that each part of the site which needs a separate publish function needs to be added to the org-publish-project-alist so we will define each rule.

    (add-to-list 'org-publish-project-alist
                 `("dotdoom-org"
                   :base-directory ,dotdoom-root-dir
                   :publishing-directory ,dotdoom-publish-dir
                   :base-extension "org"
                   :infojs-opt "view:t toc:t ltoc:t mouse:underline buttons:0 path:https://thomasf.github.io/solarized-css/org-info.min.js"
                   :html-head "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://thomasf.github.io/solarized-css/solarized-dark.min.css\" />"
                   :recursive t
                   :publishing-function org-html-publish-to-html
                   :auto-index nil ; I make my own from the readme.org
                   ;; :html-head-include-default-style nil ; supresses the rest
                   ;; :index-filename "README.org"
                   ;; :index-title "index"
                   ;; :auto-sitemap t                ; Generate sitemap.org automagically...
                   ;; :sitemap-filename "index.org"  ; ... call it sitemap.org (it's the default)...
                   ;; :sitemap-title "index"         ; ... with title 'sitemap'.
                   :link-home "index.html"))
    
  2. Static Content

    We will at the very least need the .txt files to be transferred as is for keybase.

    (add-to-list 'org-publish-project-alist
          `("dotdoom-static"
             :base-directory ,dotdoom-root-dir
             :publishing-directory ,dotdoom-publish-dir
             :base-extension "txt"
             :recursive nil
             :publishing-function org-publish-attachment))
    
  3. Inherit and Combine

    Now we compose the previous projects, keeping in mind the fact that they are in the LTR order of preference.

    (add-to-list 'org-publish-project-alist
          `("dotdoom"
            :components ("dotdoom-org" "dotdoom-static")
            ))
    

1.16.2. Firestarter

Since I switched to using Nix for R I needed a way to reload my system-wide config.nix firestarter is the best of the auto-exec in my opinion, and would probably replace a lot of my other hooks eventually as well.

(use-package! firestarter
  :init
  (firestarter-mode)
  :config
  (setq firestarter-default-type t)
)

1.17. Hooks

1.17.1. TODO Caveats

Move all the hooks to this section if possible.

1.17.2. Out of Focus Hook

Similar to neovim and its set autowrite and au FocusLost * update:

;; Save on focus lost (The frame's focus that is...)
;; (defun save-all ()
;;   (interactive)
;;   (save-some-buffers t))
;; (add-hook 'focus-out-hook 'save-all)

From here.

1.17.3. Before Save Hooks

  1. CC Mode

    Currently I only need to use the clang formatting hook here.

    ; The interactive thing is REQUIRED
    (defun haozeke/clang-format-buffer-smart-on-save ()
    (interactive)
      "Add auto-save hook for clang-format-buffer-smart."
      (add-hook 'before-save-hook 'haozeke/clang-format-buffer-conditional nil t))
    ; Disabled: using Doom format module with clang-format instead
    ;; (add-hook! (c-mode c++-mode cc-mode) #'haozeke/clang-format-buffer-smart-on-save)
    

1.17.4. Disable Auto RDM

This conflicts with the ArchLinux systemctl --user start rdm thing.

; rtags support was removed from Doom; this hook no longer exists
;; (remove-hook 'c-mode-common-hook #'+cc|init-rtags)

1.18. Troubleshooting

These are strictly temporary hacks to resolve problems until they are fixed upstream.

(after! doom-themes
  (remove-hook 'doom-load-theme-hook #'doom-themes-treemacs-config))

2. Sphinx and RsT

As mentioned in packages.html, we have some packages which make life easier.

(use-package! ox-rst
:after org)
(use-package! sphinx-mode)

3. Python Helpers

Basically this set's uvx up for most of the tooling.

(after! python
  ;; Use uvx ruff for formatting
  (set-formatter! 'ruff-format '("uvx" "ruff" "format" "--stdin-filename" "%S")
    :modes '(python-mode python-ts-mode))
  (setq-default flycheck-python-ruff-executable (executable-find "ruff"))
  )

4. R Helpers

This section is essentially to configure working with R above and beyond the default ess configuration supplied by doom-emacs.

4.0.1. R Markdown

Basically only poly-markdown for rmd files.

;; Load
(use-package! poly-R
:config
(map! (:localleader
      :map polymode-mode-map
      :desc "Export"   "e" 'polymode-export
      :desc "Errors" "$" 'polymode-show-process-buffer
      :desc "Weave" "w" 'polymode-weave
      ;; (:prefix ("n" . "Navigation")
      ;;   :desc "Next" "n" . 'polymode-next-chunk
      ;;   :desc "Previous" "N" . 'polymode-previous-chunk)
      ;; (:prefix ("c" . "Chunks")
      ;;   :desc "Narrow" "n" . 'polymode-toggle-chunk-narrowing
      ;;   :desc "Kill" "k" . 'polymode-kill-chunk
      ;;   :desc "Mark-Extend" "m" . 'polymode-mark-or-extend-chunk)
      ))
  )

4.0.2. DONE Rmd to Rorg

The idea is to replace md completely with org. Since polymode is pretty finicky for most of my org files, I will ensure it is only enabled for Rorg files.

(use-package! poly-org
:config
(add-to-list 'auto-mode-alist '("\\.org" . org-mode))
(add-to-list 'auto-mode-alist '("\\.Rorg" . poly-org-mode))
(map! (:localleader
      :map polymode-mode-map
      :desc "Export"   "E" 'polymode-export
      :desc "Errors" "$" 'polymode-show-process-buffer
      :desc "Weave" "w" 'polymode-weave
      ))
  )

4.0.3. Keybindings

(defun then_R_operator ()
  "R - %>% operator or 'then' pipe operator"
  (interactive)
  (just-one-space 1)
  (insert "%>%")
  (reindent-then-newline-and-indent))
(map! :leader
      :map (ess-mode-map, inferior-ess-mode-map)
      :desc "Insert pipe"  ">" 'then_R_operator)

5. Org LaTeX

Portions of this section are to be mirrored in the async init file since. That's also why here it's better to not use very doom specific code. I think it would be a lot better to just work these into a single literate block instead of maintaining two different sets of syntax.

5.0.1. Async Config

This is essentially the same, only some extra packages are added.

;;; autoExport.el --- For async exports -*- lexical-binding: t; -*-

(require 'package)
(setq package-enable-at-startup nil)
(package-initialize)

(defvar rg/async-emacs-dir
  (file-name-as-directory (expand-file-name "~/.config/emacs/"))
  "Emacs configuration directory for async Org export workers.")

(defvar rg/async-straight-dir
  (expand-file-name ".local/straight/" rg/async-emacs-dir)
  "Straight package root for async Org export workers.")

(defvar rg/async-straight-repos-dir
  (expand-file-name "repos/" rg/async-straight-dir)
  "Straight repository root for async Org export workers.")

(defvar rg/async-straight-build-dir
  (file-name-as-directory
   (or (car (file-expand-wildcards
             (expand-file-name
              (format "build-%d.%d" emacs-major-version emacs-minor-version)
              rg/async-straight-dir)))
       (car (last (sort (file-expand-wildcards
                         (expand-file-name "build-*" rg/async-straight-dir))
                        #'string<)))
       (expand-file-name "build/" rg/async-straight-dir)))
  "Straight build directory for async Org export workers.")

(defun rg/async-add-load-path (path)
  "Add PATH to `load-path' when it exists."
  (when (file-directory-p path)
    (add-to-list 'load-path (file-name-as-directory path))))

(defun rg/async-add-straight-package (package &optional repo)
  "Add Straight PACKAGE and optional REPO directories to `load-path'."
  (rg/async-add-load-path (expand-file-name package rg/async-straight-build-dir))
  (rg/async-add-load-path
   (expand-file-name (or repo package) rg/async-straight-repos-dir)))

(rg/async-add-straight-package "org" "org-mode")
(require 'org)
(require 'ox)
(require 'ox-koma-letter)
(require 'ox-beamer)

;; Org-Ref Stuff
(dolist (package '("org-ref" "dash" "s" "f" "hydra" "avy" "request"
                   "queue" "aio" "citeproc" "parsebib"
                   "biblio" "async" "htmlize" "pdf-tools"
                   "bibtex-completion"))
  (rg/async-add-straight-package package))
(rg/async-add-straight-package "dash" "dash.el")
(rg/async-add-straight-package "s" "s.el")
(rg/async-add-straight-package "f" "f.el")
(rg/async-add-straight-package "biblio" "biblio.el")
(rg/async-add-straight-package "request" "emacs-request")
(rg/async-add-straight-package "aio" "emacs-aio")
(rg/async-add-straight-package "htmlize" "emacs-htmlize")
(rg/async-add-straight-package "bibtex-completion" "helm-bibtex")
(require 'org-ref)

(load (expand-file-name
       "rg-compat.el"
       (file-name-directory (or load-file-name buffer-file-name)))
      nil t)

;; Path addtion
(let ((texlive-path
       (cond
        ((eq system-type 'gnu/linux)
         (concat (getenv "HOME") "/.local/share/texlive-20230827/bin/x86_64-linux"))
        ((eq system-type 'darwin)
         (concat (getenv "HOME") "/usr/local/texlive/2021/bin/universal-darwin")))))
  (when texlive-path
    (add-to-list 'exec-path texlive-path)
    (setenv "PATH" (concat (getenv "PATH") ":" texlive-path))
    ))

;; Functions
;; this function is used to append multiple elements to the list 'ox-latex
(defun append-to-list (list-var elements)
  "Append ELEMENTS to the end of LIST-VAR. The return value is the new value of LIST-VAR."
  (unless (consp elements) (error "ELEMENTS must be a list"))
  (let ((list (symbol-value list-var)))
    (if list
        (setcdr (last list) elements)
      (set list-var elements)))
(symbol-value list-var))
;; Feature parity with doom
(eval-after-load 'ox '(require 'ox-koma-letter))
(with-eval-after-load 'ox-latex
  ;; Compiler -- tectonic handles bibtex, package downloads, and multiple passes
  (setq org-latex-pdf-process (list "tectonic -X compile --synctex --keep-logs %f"))
  ;; engrave-faces replaces minted for code highlighting
  (setq org-latex-src-block-backend 'engraved)
  (setq org-latex-engraved-theme t) ;; use current Emacs theme
  (append-to-list
   'org-latex-classes
   '(("tufte-book"
      "\\documentclass[a4paper, sfsidenotes, openany, justified]{tufte-book}"
      ("\\part{%s}" . "\\part*{%s}")
      ("\\chapter{%s}" . "\\chapter*{%s}")
      ("\\section{%s}" . "\\section*{%s}")
      ("utf8" . "utf8x")
      ("\\subsection{%s}" . "\\subsection*{%s}"))))
  (add-to-list 'org-latex-classes
               '("koma-article" "\\documentclass{scrartcl}"
                 ("\\section{%s}" . "\\section*{%s}")
                 ("\\subsection{%s}" . "\\subsection*{%s}")
                 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
                 ("\\paragraph{%s}" . "\\paragraph*{%s}")
                 ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
  (add-to-list 'org-latex-classes
               '("koma-report" "\\documentclass{scrreprt}"))
)
(provide 'autoExport)
;;; autoExport.el ends here

5.0.2. Path Additions

Due to my recent switch to using tlmgr, I had to make some modifications to the emacs path.

(let ((texlive-path
       (cond
        ((eq system-type 'gnu/linux)
         (concat (getenv "HOME") "/.local/share/texlive-20230827/bin/x86_64-linux"))
        ((eq system-type 'darwin)
         (concat (getenv "HOME") "/usr/local/texlive/2021/bin/universal-darwin")))))
  (when texlive-path
    (add-to-list 'exec-path texlive-path)
    (setenv "PATH" (concat (getenv "PATH") ":" texlive-path))
    ))

5.0.3. Config

This is the part which is exported normally.

(eval-after-load 'ox '(require 'ox-koma-letter))
(with-eval-after-load 'ox-latex
  ;; Compiler -- tectonic handles bibtex, package downloads, and multiple passes
  (setq org-latex-pdf-process (list "tectonic -X compile --synctex --keep-logs %f"))
  ;; engrave-faces replaces minted for code highlighting
  (setq org-latex-src-block-backend 'engraved)
  (setq org-latex-engraved-theme t) ;; use current Emacs theme
  (append-to-list
   'org-latex-classes
   '(("tufte-book"
      "\\documentclass[a4paper, sfsidenotes, openany, justified]{tufte-book}"
      ("\\part{%s}" . "\\part*{%s}")
      ("\\chapter{%s}" . "\\chapter*{%s}")
      ("\\section{%s}" . "\\section*{%s}")
      ("utf8" . "utf8x")
      ("\\subsection{%s}" . "\\subsection*{%s}"))))
  (add-to-list 'org-latex-classes
               '("koma-article" "\\documentclass{scrartcl}"
                 ("\\section{%s}" . "\\section*{%s}")
                 ("\\subsection{%s}" . "\\subsection*{%s}")
                 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
                 ("\\paragraph{%s}" . "\\paragraph*{%s}")
                 ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
  (add-to-list 'org-latex-classes
               '("koma-report" "\\documentclass{scrreprt}"))
)

5.1. Shared Preferences

5.1.1. Compiler

Using tectonic for automatic package fetching, reproducible builds, and no texlive management overhead. Falls back to a single invocation with bibtex.

;; Compiler -- tectonic handles bibtex, package downloads, and multiple passes
(setq org-latex-pdf-process (list "tectonic -X compile --synctex --keep-logs %f"))

5.1.2. Packages

Using engrave-faces for source block highlighting in LaTeX export (faster than minted, no pygments dependency, works in batch mode).

;; engrave-faces replaces minted for code highlighting
(setq org-latex-src-block-backend 'engraved)
(setq org-latex-engraved-theme t) ;; use current Emacs theme

5.2. Export Templates

Most of the configuration is to be moved into the file snippets. However, class definitions and other packages are still to be loaded here. Though here in the config.el I could use doom semantics and might as well to keep things DRY, it appears that the async file needs to keep things in the old syntax.

5.2.1. KOMA Article

Inspired by the post here.

(add-to-list 'org-latex-classes
             '("koma-article" "\\documentclass{scrartcl}"
               ("\\section{%s}" . "\\section*{%s}")
               ("\\subsection{%s}" . "\\subsection*{%s}")
               ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
               ("\\paragraph{%s}" . "\\paragraph*{%s}")
               ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))

5.2.2. KOMA Report

Inspired by the post here.

(add-to-list 'org-latex-classes
             '("koma-report" "\\documentclass{scrreprt}"))

5.2.3. Tufte Book

This is really ad-hoc right now and from this reddit thread.

(append-to-list
 'org-latex-classes
 '(("tufte-book"
    "\\documentclass[a4paper, sfsidenotes, openany, justified]{tufte-book}"
    ("\\part{%s}" . "\\part*{%s}")
    ("\\chapter{%s}" . "\\chapter*{%s}")
    ("\\section{%s}" . "\\section*{%s}")
    ("utf8" . "utf8x")
    ("\\subsection{%s}" . "\\subsection*{%s}"))))

5.3. LaTeX Preview for Org mode

Basically I need to see math and physics. Originally borrowed from this stackexchange question.

  1. Process
    ;; Superseded by dvisvgm-tectonic process defined in Org Config section
    '(org-preview-latex-process-alist
      (quote
       ((dvipng :programs
         ("lualatex" "dvipng")
         :description "dvi > png" :message "you need to install the programs: latex and dvipng." :image-input-type "dvi" :image-output-type "png" :image-size-adjust
         (1.0 . 1.0)
         :latex-compiler
         ("lualatex -output-format dvi -interaction nonstopmode -output-directory %o %f")
         :image-converter
         ("dvipng -fg %F -bg %B -D %D -T tight -o %O %f"))
        (dvisvgm :programs
         ("latex" "dvisvgm")
         :description "dvi > svg" :message "you need to install the programs: latex and dvisvgm." :use-xcolor t :image-input-type "xdv" :image-output-type "svg" :image-size-adjust
         (1.7 . 1.5)
         :latex-compiler
         ("xelatex -no-pdf -interaction nonstopmode -output-directory %o %f")
         :image-converter
         ("dvisvgm %f -n -b min -c %S -o %O"))
        (imagemagick :programs
         ("latex" "convert")
         :description "pdf > png" :message "you need to install the programs: latex and imagemagick." :use-xcolor t :image-input-type "pdf" :image-output-type "png" :image-size-adjust
         (1.0 . 1.0)
         :latex-compiler
         ("xelatex -no-pdf -interaction nonstopmode -output-directory %o %f")
         :image-converter
         ("convert -density %D -trim -antialias %f -quality 100 %O")))))
    
  2. Packages

    These are required to view math properly.

5.4. Math support

This is from this reddit thread.

(map! :map cdlatex-mode-map
      :i "TAB" #'cdlatex-tab)

Also we need some more things.

(use-package! cdlatex
  :after (:any org-mode LaTeX-mode)
  :hook
  ((LaTeX-mode . turn-on-cdlatex)
   (org-mode . turn-on-org-cdlatex)))
(use-package! company-math
  :after (:any org-mode TeX-mode)
  :when (modulep! :completion company)
  :defer t
  :config
  (set-company-backend! 'org-mode 'company-math-symbols-latex)
  (set-company-backend! 'TeX-mode 'company-math-symbols-latex)
  (set-company-backend! 'org-mode 'company-latex-commands)
  (set-company-backend! 'TeX-mode 'company-latex-commands)
  (setq company-tooltip-align-annotations t)
  (setq company-math-allow-latex-symbols-in-faces t))

Similarly:

(use-package! company-auctex
  :when (modulep! :completion company)
  :defer t
  :init
  (add-to-list '+latex--company-backends #'company-auctex-environments nil #'eq)
  (add-to-list '+latex--company-backends #'company-auctex-macros nil #'eq))

We would also like to set up the math-symbol-list unicode input from here.

(use-package! math-symbol-lists
  :config
  (quail-define-package "math" "UTF-8" "Ω" t)
  (quail-define-rules ; add whatever extra rules you want to define here...
   ("\\from"    #X2190)
   ("\\to"      #X2192)
   ("\\lhd"     #X22B2)
   ("\\rhd"     #X22B3)
   ("\\unlhd"   #X22B4)
   ("\\unrhd"   #X22B5))
  (mapc (lambda (x)
          (if (cddr x)
              (quail-defrule (cadr x) (car (cddr x)))))
        (append math-symbol-list-basic math-symbol-list-extended math-symbol-list-subscripts math-symbol-list-superscripts)))

5.5. Prettier TeX buffers

From here. Reduces the size of inessential tex.

(defface endless/unimportant-latex-face
  '((t :height 0.7
     :inherit font-lock-comment-face))
  "Face used on less relevant math commands."
  :group 'LaTeX-math)

(setq font-latex-user-keyword-classes
      '(("mathunimportant"
         ("left" "right"
          "big" "Big"
          "bigl" "bigr"
          "Bigl" "Bigr"
          "biggl" "biggr"
          "Biggl" "Biggr"
          "," "." ";" "!")
         endless/unimportant-latex-face
         noarg)))

5.6. Babel Tabs

Evidently there was some sort of re-indentation going on during the export process which was breaking a lot of python, this should fix that: More generally, it is best set with # -*- org-src-preserve-indentation: t; org-edit-src-content: 0; -*- on a per-file basis, however given that the indentation is handled by the programming major mode, this is a good global setting as well.

(setq org-src-preserve-indentation t
      org-edit-src-content-indentation 0)

5.7. Pandoc Babel

As fully described in this post, I felt the need to export some common pandoc formats with babel.

5.7.1. Restructured Text

(defun org-babel-execute:rst (body params)
  "Execute a block of rst code with org-babel.
This function is called by `org-babel-execute-src-block'."
  (let* ((result-params (split-string (or (cdr (assoc :results params)) "")))
         (in-file (org-babel-temp-file "rst-"))
         (cmdline (cdr (assoc :cmdline params)))
         (to (cdr (assoc :to params)))
         (template (cdr (assoc :template params)))
         (cmd (concat "pandoc"
                      " -t  org"
                      " -i " (org-babel-process-file-name in-file)
                      " -f rst "
                      " " cmdline)))
    (with-temp-file in-file (insert body))
    (message cmd)
    (shell-command-to-string cmd))) ;; Send to results

(defun org-babel-prep-session:rst (session params)
  "Return an error because rst does not support sessions."
  (error "rst does not support sessions"))

5.7.2. Markdown HTML

A helper execution method mostly for better formatting with org-gcal, the method is described in this post.

(defun org-babel-execute:mdhtml (body params)
  "Execute a block of rst code with org-babel.
This function is called by `org-babel-execute-src-block'."
  (let* ((result-params (split-string (or (cdr (assoc :results params)) "")))
         (in-file (org-babel-temp-file "mdhtml-"))
         (cmdline (cdr (assoc :cmdline params)))
         (to (cdr (assoc :to params)))
         (template (cdr (assoc :template params)))
         (cmd (concat "pandoc"
                      " -t  html"
                      " -i " (org-babel-process-file-name in-file)
                      " -f gfm "
                      " " cmdline)))
    (with-temp-file in-file (insert body))
    (message cmd)
    (shell-command-to-string cmd))) ;; Send to results

(defun org-babel-prep-session:mdhtml (session params)
  "Return an error because mdhtml does not support sessions."
  (error "mdhtml does not support sessions"))

5.8. Flycheck Additions

These are basically meant to aid in development. The relevant linters are also added here.

5.8.1. MELPA Helpers

This includes settings for both flycheck and the packages it needs.

(use-package! flycheck-package
  :after flycheck
  :config (flycheck-package-setup))

6. Prose commands

(map! :leader
      (:prefix ("S" . "Prose")
       (:prefix ("s" . "Snapper")
        :desc "Format buffer" "f" #'rg/snapper-format-buffer
        :desc "Format region" "r" #'rg/snapper-format-region
        :desc "Check buffer" "c" #'rg/snapper-check-buffer
        :desc "Git diff" "d" #'rg/snapper-git-diff
        :desc "Watch" "w" #'rg/snapper-watch)
       (:prefix ("b" . "BibTeX")
        :desc "Insert citation" "i" #'citar-insert-citation
        :desc "Org cite" "c" #'org-cite-insert
        :desc "Open reference" "o" #'citar-open
        :desc "Refresh cache" "r" #'rg/zot-bib-refresh-cache
        :desc "Warm cache" "w" #'rg/bibtex-completion-warm-cache)
       (:prefix ("v" . "Vale")
        :desc "Buffer" "b" #'rg/vale-buffer
        :desc "Directory" "d" #'rg/vale-directory
        :desc "Project" "p" #'rg/vale-project
        :desc "Paths" "v" #'rg/vale-run
        :desc "Sync styles" "s" #'rg/vale-sync)
       :desc "Harper LSP" "h" #'rg/prose-eglot-ensure
       :desc "Health" "H" #'rg/doom-health-check
       :desc "Profile Org" "p" #'rg/profile-org-editing))

7. Vterm quick launchers

Named vterm buffers for common tasks.

(defun rg/vterm-named (name cmd)
  "Open a named vterm buffer and send CMD."
  (let ((buf-name (format "*vterm-%s*" name)))
    (unless (get-buffer buf-name)
      (let ((vterm-buffer-name buf-name))
        (vterm)
        (vterm-send-string cmd)
        (vterm-send-return)))
    (switch-to-buffer buf-name)))

(map! :leader
      (:prefix ("v" . "Vterm")
       :desc "Open vterm" "v" #'+vterm/here
       :desc "Project vterm" "p" #'+vterm/toggle))

8. Notes

8.1. noteYoda

This is largely inspired from this reddit comment. For clarity and extensibility this will be broken down into a per-package configuration. The heart of this is an rclone mega folder to manage all these transparently. With this setup links to the files are stored in zotero and managed by zotfile. Now described in this post.

8.1.1. Citar

(use-package! citar
  :commands (citar-insert-citation
             citar-insert-reference
             citar-open
             citar-capf-setup)
  :init
  (setq org-cite-global-bibliography (list zot_bib)
        org-cite-insert-processor 'citar
        org-cite-follow-processor 'citar
        org-cite-activate-processor 'citar
        citar-bibliography org-cite-global-bibliography)
  :hook ((org-mode . citar-capf-setup)
         (LaTeX-mode . citar-capf-setup)
         (latex-mode . citar-capf-setup))
  :config
  (rg/bibtex-configure-paths)
  (setq org-cite-global-bibliography (list zot_bib)
        citar-bibliography org-cite-global-bibliography
        citar-at-point-function 'embark-act))

(use-package! citar-embark
  :after (citar embark)
  :config
  (citar-embark-mode))

8.1.2. Org-Ref

This seems like an ubiquitous choice for working with org files and references, though quite a bit of the config here relates to helm-bibtex. Commented sections are set in my private config.

(use-package! org-ref
  :init
  (with-eval-after-load 'ox
    (defun my/org-ref-process-buffer--html (backend)
      "Preprocess `org-ref' citations to HTML format.

  Do this only if the export backend is `html' or a derivative of
  that."
      ;; `ox-hugo' is derived indirectly from `ox-html'.
      ;; ox-hugo <- ox-blackfriday <- ox-md <- ox-html
      (when (org-export-derived-backend-p backend 'html)
        (org-ref-process-buffer 'html)))
    (add-to-list 'org-export-before-parsing-hook #'my/org-ref-process-buffer--html))
  :config
  (rg/bibtex-configure-paths)
  (setq
   org-ref-get-pdf-filename-function 'org-ref-get-pdf-filename-helm-bibtex
   bibtex-completion-bibliography (list zot_bib)
   bibtex-completion-notes-path (expand-file-name "bibnotes.org" org_notes)
   org-ref-note-title-format "* TODO %y - %t\n :PROPERTIES:\n  :Custom_ID: %k\n  :NOTER_DOCUMENT: %F\n :ROAM_KEY: cite:%k\n  :AUTHOR: %9a\n  :JOURNAL: %j\n  :YEAR: %y\n  :VOLUME: %v\n  :PAGES: %p\n  :DOI: %D\n  :URL: %U\n :END:\n\n"
   org-ref-notes-directory org_notes
   org-ref-notes-function 'orb-edit-notes
   ))

Apparently, org-ref is also able to fetch pdf files when DOI or URL links are dragged onto the .bib file. However, since zotero will handle the metadata, this remains to be considered.

Ivy is used exclusively throughout doom, makes sense to use it here too, but I recently switched to helm. Turns out helm is probably faster for larger collections since it can be asynchronous. Basically, this is because using the minibuffer, as ivy does is a blocking action while the helm buffer may be opened asynchronously. Name aside, helm-bibtex also works for ivy. Basically meant to interface with bibliographies in general. However, since I'm using org-ref, I won't be configuring or loading that anymore.

8.1.3. Helm Bibtex

For some reason, org-ref-notes isn't working very nicely, so the setup above prioritizes the helm-bibtex note-taking setup.

(after! org-ref
  (setq
   bibtex-completion-notes-path org_notes
   bibtex-completion-bibliography zot_bib
   bibtex-completion-pdf-field "file"
   bibtex-completion-notes-template-multiple-files
   (concat
    "#+TITLE: ${title}\n"
    "#+ROAM_KEY: cite:${=key=}\n"
    "#+ROAM_TAGS: ${keywords}\n"
    "* TODO Notes\n"
    ":PROPERTIES:\n"
    ":Custom_ID: ${=key=}\n"
    ":NOTER_DOCUMENT: %(orb-process-file-field \"${=key=}\")\n"
    ":AUTHOR: ${author-abbrev}\n"
    ":JOURNAL: ${journaltitle}\n"
    ":DATE: ${date}\n"
    ":YEAR: ${year}\n"
    ":DOI: ${doi}\n"
    ":URL: ${url}\n"
    ":END:\n\n"
    )
   )
  )

8.1.4. Org-Roam

Will also setup the org-roam-bibtex thing here. As foretold in the last line, there are more settings for ORB. The template is modified from here.

(use-package! org-roam-bibtex
  :after (org-roam)
  :hook (org-roam-mode . org-roam-bibtex-mode)
  :config
  (setq org-roam-bibtex-preformat-keywords
        '("=key=" "title" "url" "file" "author-or-editor" "keywords"))
  (setq orb-templates
        '(("r" "ref" plain (function org-roam-capture--get-point)
           ""
           :file-name "${slug}"
           :head "#+TITLE: ${=key=}: ${title}\n#+ROAM_KEY: ${ref}\n#+ROAM_TAGS:

- keywords :: ${keywords}

\n* ${title}\n  :PROPERTIES:\n  :Custom_ID: ${=key=}\n  :URL: ${url}\n  :AUTHOR: ${author-or-editor}\n  :NOTER_DOCUMENT: %(orb-process-file-field \"${=key=}\")\n  :NOTER_PAGE: \n  :END:\n\n"

           :unnarrowed t))))

8.1.5. Org-Noter

I decided to use org-noter over the more commonly described interleave because it has better support for working with multiple documents linked to one file.

(use-package! org-noter
  :after (:any org pdf-view)
  :init
  (setq org-noter-supported-modes '(doc-view-mode pdf-view-mode))
  :config
  (setq
   ;; The WM can handle splits
   org-noter-notes-window-location 'other-frame
   ;; Please stop opening frames
   org-noter-always-create-frame nil
   ;; I want to see the whole file
   org-noter-hide-other nil
   ;; Everything is relative to the rclone mega
   org-noter-notes-search-path (list org_notes)
   )
  )

I have a rather involved setup in mind, so I have spun this section off from the rest. The basic idea is to use deft for short-to-long lookup notes, and org-capture templates with org-protocol for the rest. I am also considering notdeft since it might work better for what I want to achieve. Though it isn't really part of a note taking workflow, I also intend to use michel2 to sync my tasks…

8.2. Org Capture

I am not really sure how to use these correctly, but I have the bare minimum required for the Firefox browser extension (setup from here), and a random article thing.

8.2.1. Buffer Size

(set-popup-rule! "^CAPTURE-.*\\.org$" :size 0.5 :quit nil :select t :autosave t)

8.2.2. Functions

These are needed for org-capture alone for now.

;; Fix some link issues
(defun transform-square-brackets-to-round-ones(string-to-transform)
  "Transforms [ into ( and ] into ), other chars left unchanged."
  (concat
   (mapcar #'(lambda (c) (if (equal c ?\[) ?\( (if (equal c ?\]) ?\) c))) string-to-transform))
  )

8.2.3. Templates

This might get complicated but I am only trying to get the bare minimum for org-protocol right now. Will look into orca and doct.

;; Actually start using templates
(after! org-capture
  ;; Firefox
  (add-to-list 'org-capture-templates
               '("P" "Protocol" entry
                 (file+headline +org-capture-notes-file "Inbox")
                 "* %^{Title}\nSource: %u, %c\n #+BEGIN_QUOTE\n%i\n#+END_QUOTE\n\n\n%?"
                 :prepend t
                 :kill-buffer t))
  (add-to-list 'org-capture-templates
               '("L" "Protocol Link" entry
                 (file+headline +org-capture-notes-file "Inbox")
                 "* %? [[%:link][%(transform-square-brackets-to-round-ones \"%:description\")]]\n"
                 :prepend t
                 :kill-buffer t))
  ;; Misc
  (add-to-list 'org-capture-templates
               '("a"               ; key
                 "Article"         ; name
                 entry             ; type
                 (file+headline +org-capture-notes-file "Article")  ; target
                 "* %^{Title} %(org-set-tags)  :article: \n:PROPERTIES:\n:Created: %U\n:Linked: %a\n:END:\n%i\nBrief description:\n%?"  ; template
                 :prepend t        ; properties
                 :empty-lines 1    ; properties
                 :created t        ; properties
                 ))
  )
  1. HTML Parsing

    The standard capture method isn't too great, but this makes it better.

    (use-package! org-protocol-capture-html
      :after org-protocol
      :config
      (add-to-list 'org-capture-templates
                   '("w"
                     "Web site"
                     entry
                     (file+headline +org-capture-notes-file "Website")  ; target
                     "* %a :website:\n\n%U %?\n\n%:initial")
                   )
      )
    
    (setq org-roam-ref-capture-templates
          '(("r" "ref" plain (function org-roam--capture-get-point)
             "%?"
             :file-name "websites/${slug}"
             :head "#+SETUPFILE:./hugo_setup.org
    #+ROAM_KEY: ${ref}
    #+HUGO_SLUG: ${slug}
    #+TITLE: ${title}
    

Footnotes:

1

Kanged from here

2

This post has good notes

Date: 2020:04:09

Author: Rohit Goswami (HaoZeke) <rohit.goswami@aol.com>

Created: 2026-06-12 Fri 21:41

Validate