Org-mode

Since recently, in order to make org-cite compile properly, we need the citeproc package, a citation processor.

(use-package citeproc
  :after (org)
  :defer t
  :straight (:build t))

Org is the main reason I am using Emacs. It is an extremely powerful tool when you want to write anything that is not necessarily primarily programming-related, though it absolutely can be! Org can be a replacement for anything similar to LibreOffice Writer, LibreOffice Calc, and LibreOffice Impress. It is a much more powerful (and older) version of Markdown which can be exported to LaTeX and HTML at least, rendering writing web pages and technical, scientific documents much simpler than writing manually HTML and LaTeX code, especially when a single document source is meant to be exported for both formats. And since org is an Emacs package, that also means it can be greatly extended however we like!

(use-package org
  :straight t
  :defer t
  :after engrave-faces
  :commands (orgtbl-mode)
  :hook ((org-mode . visual-line-mode)
         (org-mode . org-num-mode))
  :custom-face
  (org-macro ((t (:foreground "#b48ead"))))
  :init
  (auto-fill-mode -1)
  :config
  <<org-hydra-babel>>
  (require 'ox-beamer)
  (require 'org-protocol)
  (setq org-hide-leading-stars             nil
        org-hide-macro-markers             t
        org-ellipsis                       " ⤵"
        org-image-actual-width             600
        org-redisplay-inline-images        t
        org-display-inline-images          t
        org-startup-with-inline-images     "inlineimages"
        org-pretty-entities                t
        org-fontify-whole-heading-line     t
        org-fontify-done-headline          t
        org-fontify-quote-and-verse-blocks t
        org-startup-indented               t
        org-startup-align-all-tables       t
        org-use-property-inheritance       t
        org-list-allow-alphabetical        t
        org-M-RET-may-split-line           nil
        org-src-window-setup               'split-window-below
        org-src-fontify-natively           t
        org-src-tab-acts-natively          t
        org-src-preserve-indentation       t
        org-log-done                       'time
        org-directory                      "~/org"
        org-default-notes-file             (expand-file-name "notes.org" org-directory))
  (with-eval-after-load 'oc
   (setq org-cite-global-bibliography '("~/org/bibliography/references.bib")))
  <<org-agenda-files>>
  <<org-behavior-electric>>
  <<org-capture-target-files>>
  <<org-capture-templates>>
  <<org-create-emphasis-functions()>>
  <<org-babel-load-languages>>
  <<org-use-sub-superscripts>>
  <<org-latex-compiler>>
  <<org-latex-src-block-backend>>
  <<org-latex-default-packages>>
  <<org-export-latex-hyperref-format>>
  <<org-latex-pdf-process>>
  <<org-latex-logfiles-add-extensions>>
  <<org-re-reveal>>
  <<org-html-validation>>
  <<org-latex-classes>>
  <<org-publish-projects>>
  <<org-mode-visual-prettify-symbols>>
  :general
  (phundrak/evil
    :keymaps 'org-mode-map
    :packages 'org
    "RET" 'org-open-at-point)
  (phundrak/major-leader-key
    :keymaps 'org-mode-map
    :packages 'org
    <<general-keybindings-gen(table=org-keybinds-various)>>
    <<general-keybindings-gen(table=org-keybinds-babel)>>
    <<general-keybindings-gen(table=org-keybinds-dates)>>
    <<general-keybindings-gen(table=org-keybinds-insert)>>
    <<general-keybindings-gen(table=org-keybinds-jump)>>
    <<general-keybindings-gen(table=org-keybinds-tables)>>
    <<general-keybindings-gen(table=org-keybinds-toggles)>>)
  <<org-capture-keybinds>>
  (phundrak/major-leader-key
    :packages 'org
    :keymaps 'org-src-mode-map
    "'" #'org-edit-src-exit
    "k" #'org-edit-src-abort))

The main feature from evil-org that I love is how easy it is to modify some keybindings for keyboards layouts that do not have hjkl, such as the bépo layout (or Dvorak or Colemak if you are into that). But it also adds a ton of default keybindings which are just much more comfortable than the default ones you get with evil and org naked.

(use-package evil-org
  :straight (:build t)
  :after (org)
  :hook (org-mode . evil-org-mode)
  :config
  (setq-default evil-org-movement-bindings
                '((up    . "s")
                  (down  . "t")
                  (left  . "c")
                  (right . "r")))
  (evil-org-set-key-theme '(textobjects navigation calendar additional shift operators))
  (require 'evil-org-agenda)
  (evil-org-agenda-set-keys))

This package is a small package I’ve written that helps me when writing conlanging documents, with features such as creating syntax trees, converting translitterated text to its native script, etc…

(use-package conlanging
  :straight (conlanging :build t
                        :type git
                        :repo "https://labs.phundrak.com/phundrak/conlanging.el")
  :after org
  :defer t)

Since very recently, the contrib/lisp/ directory of org moved out of the main repository to this repositoryopen in new window. On the other hand, contrib/scripts/ moved to the worg repositoryopen in new window, but I don’t need it. The main reason I want org-contrib is due to ox-extra that allow the usage of the :ignore: tag in org.

(use-package org-contrib
  :after (org)
  :defer t
  :straight (:build t)
  :init
  (require 'ox-extra)
  (ox-extras-activate '(latex-header-blocks ignore-headlines)))

Agenda

(setq org-agenda-files (list "~/org/agenda" "~/org/notes.org"))
(use-package org-caldav
  :straight (:build t)
  :defer t
  :config
  (setq org-caldav-url "https://nextcloud.phundrak.com/remote.php/dav/calendars/phundrak"
        org-icalendar-timezone "Europe/Paris"
        org-caldav-calendars
        `((:calendar-id "personal" :files ("~/org/agenda/private.org")
           :inbox "~/org/agenda/private.org")
          (:calendar-id "contact_birthdays" :files ("~/org/agenda/birthdays.org")
           :inbox "~/org/agenda/birthdays.org"))))

Babel

One of the amazing features of org-mode is its literary programming capacities by running code blocks from within Org-mode itself. But for that, only a couple of languages are supported directly by Org-mode itself, and they need to be activated. Here are the languages I activated in my Org-mode configuration:

| C | | emacs-lisp | | gnuplot | | latex | | makefile | | plantuml | | python | | sass | | shell | | sql |

The corresponding code is as follows:

(org-babel-do-load-languages
 'org-babel-load-languages
 '((C . t)
   (emacs-lisp . t)
   (gnuplot . t)
   (latex . t)
   (makefile . t)
   (plantuml . t)
   (python . t)
   (sass . t)
   (shell . t)
   (sql . t))
 )

Some languages can run asynchronously with the help of ob-async.

(use-package ob-async
  :straight (:build t)
  :defer t
  :after (org ob))

A package I use from time to time is ob-latex-as-png which allows me to easily convert a LaTeX snippet into a PNG, regardless of the exporter I use afterwards. Its installation is pretty simple:

(use-package ob-latex-as-png
  :after org
  :straight (:build t))

A nice thing to have when working with REST APIs is to have a REST client. Even better if it can work inside org-mode!

(use-package ob-restclient
  :straight (:build t)
  :defer t
  :after (org ob)
  :init
  (add-to-list 'org-babel-load-languages '(restclient . t)))

Behavior

A useful package I like is toc-org which creates automatically a table of contents. My main usage for this however is not just to create a table of content of my files to quickly jump around my file (I have counsel-org-goto for that), but it is for creating table of contents for org files that will be hosted and viewable on GitHub.

(use-package toc-org
  :after (org markdown-mode)
  :straight (:build t)
  :init
  (add-to-list 'org-tag-alist '("TOC" . ?T))
  :hook (org-mode . toc-org-enable)
  :hook (markdown-mode . toc-org-enable))

electric-mode also bothers me a lot when editing org files, so let’s deactivate it:

(add-hook 'org-mode-hook (lambda ()
                           (interactive)
                           (electric-indent-local-mode -1)))

As explained in my blog postopen in new window, org-mode is terrible with coming up with meaningful IDs for its headings. I actually wrote a package for this!

(use-package org-unique-id
  :straight (org-unique-id :build t
                           :type git
                           :host github
                           :repo "Phundrak/org-unique-id")
  :defer t
  :after org
  :init (add-hook 'before-save-hook #'org-unique-id-maybe))

Capture

Org capture is an amazing tool for taking quick notes, be it simple text, links, resources, or reminders. They are all organised is specified org files which are described below.

(defvar org-conlanging-file "~/org/conlanging.org")
(defvar org-notes-file "~/org/notes.org")
(defvar org-journal-file "~/org/journal.org")
(defvar org-linguistics-file "~/org/linguistics.org")
(defvar org-novel-file "~/org/novel.org")
(defvar org-agenda-file "~/org/agenda/private.org")
(defvar org-school-file "~/org/agenda/school.org")
(defvar org-worldbuilding-file "~/org/worldbuilding.org")

When org-capture is invoked, it will ask which template we wish to use. In the table 2, the key column represents which keychord we need to hit, titled with name, we need to hit in order to use the template, inserted in the designated file in the manner described by insertion mode.

ShortcutNameTitleInsertion modefiletemplate
eEmail
ewWrite EmailEmailsfile+headlineorg-default-notes-fileemail.orgcaptmpl
jJournalfile+datetreeorg-journal-filejournal.orgcaptmpl
lLink
llGeneralfile+headlineorg-default-notes-filelink.orgcaptmpl
lyYouTubefile+headlineorg-default-notes-fileyoutube.orgcaptmpl
LProtocol LinkLinkfile+headlineorg-default-notes-fileprotocol-link.orgcaptmpl
nNotes
ncConlangingNotefile+headlineorg-conlanging-filenotes.orgcaptmpl
nnGeneralfile+headlineorg-default-notes-filenotes.orgcaptmpl
nNNovelNotefile+headlineorg-novel-notes-filenotes.orgcaptmpl
nqQuotefile+headlineorg-default-notes-filenotes-quote.orgcaptmpl
nwWorldbuildingNotefile+headlineorg-wordbuilding-filenotes.orgcaptmpl
NNovel
NiIdeasfile+headlineorg-novel-notes-filenotes.orgcaptmpl
pProtocolLinkfile+headlineorg-default-notes-fileprotocol.orgcaptmpl
rResources
rcConlangingResourcesfile+headlineorg-conlanging-fileresource.orgcaptmpl
reEmacsfile+headlineorg-default-notes-fileresource.orgcaptmpl
riInformatiquefile+headlineorg-default-notes-fileresource.orgcaptmpl
rlLinguisticsfile+headlineorg-default-notes-fileresource.orgcaptmpl
rLLinuxfile+headlineorg-default-notes-fileresource.orgcaptmpl
rwWorldbuildingResourcesfile+headlineorg-wordbuilding-fileresource.orgcaptmpl
tTasks
tbBirthdayfile+headlineorg-private-agenda-filebirthday.orgcaptmpl
teEventfile+headlineorg-private-agenda-fileevent.orgcaptmpl
thHealthfile+headlineorg-private-agenda-filehealth.orgcaptmpl
tiInformatiquefile+headlineorg-private-agenda-fileinformatique.orgcaptmpl

All templates can be found in my dotfiles’ repositoryopen in new window.

The capture templates are set like so:

(setq org-capture-templates
      '(
        <<org-capture-shortcuts-gen()>>))

Custom functions

Emphasize text

Sometimes, I want to emphasize some text in my org-mode documents. It’s very possible to just go to the beginning of the chosen text, add the marker, then go to the end of the text than needs emphasis and add another marker, and I’m sure most people are fine with that. But I also like being able to select a region and hit a keybind to emphasize it that way. The table 3 lists the emphasis characters in org-mode, their role, and the character code of each emphasis character. From that, creating functions that emphasize a selected text is quite easy.

EmphasisCharacterCharacter code
bold*42
italic/47
underline_95
verbatim=61
code~126
strike-through+43
(defun org-emphasize-bold ()
  "Emphasize as bold the current region."
  (interactive)
  (org-emphasize 42))
(defun org-emphasize-italic ()
  "Emphasize as italic the current region."
  (interactive)
  (org-emphasize 47))
(defun org-emphasize-underline ()
  "Emphasize as underline the current region."
  (interactive)
  (org-emphasize 95))
(defun org-emphasize-verbatim ()
  "Emphasize as verbatim the current region."
  (interactive)
  (org-emphasize 61))
(defun org-emphasize-code ()
  "Emphasize as code the current region."
  (interactive)
  (org-emphasize 126))
(defun org-emphasize-strike-through ()
  "Emphasize as strike-through the current region."
  (interactive)
  (org-emphasize 43))

You can find the keybinds for these functions here.

phundrak/toggle-org-src-window-split

(defun phundrak/toggle-org-src-window-split ()
  "This function allows the user to toggle the behavior of
`org-edit-src-code'. If the variable `org-src-window-setup' has
the value `split-window-right', then it will be changed to
`split-window-below'. Otherwise, it will be set back to
`split-window-right'"
  (interactive)
  (if (equal org-src-window-setup 'split-window-right)
      (setq org-src-window-setup 'split-window-below)
    (setq org-src-window-setup 'split-window-right))
  (message "Org-src buffers will now split %s"
           (if (equal org-src-window-setup 'split-window-right)
               "vertically"
             "horizontally")))

Exporters

I want to disable by default behaviour of ^ and _ for only one character, making it compulsory to use instead ^{} and _{} respectively. This is due to my frequent usage of the underscore in my org files as a regular character and not a markup one, especially when describing phonetics evolution. So, let’s disable it:

(setq org-use-sub-superscripts (quote {}))

Epub

A backend for exporting files through org I like is ox-epub which, as you can guess, exports org files to the Epub formatopen in new window.

(use-package ox-epub
  :after (org ox)
  :straight (:build t))

Gemini

Gemini is a lightweight protocol for creating lightweight websites that are basically text-only websites with maybe some images. I’m currently maintaining my own fork of Justin Abrahms’ ox-gemini which fixes two issues I had with the original package.

(use-package ox-gemini
  :defer t
  :straight (ox-gemini :build t
                       :fork (:type git
                              :host nil
                              :repo "https://labs.phundrak.com/phundrak/ox-gemini"))
  :after (ox org))

HTML

On HTML exports, Org-mode tries to include a validation link for the exported HTML. Let’s disable that since I never use it.

(setq org-html-validation-link nil)

This package allows for live-previewing the HTML export of an org buffer in an XWidget Webkit browser window. But when testing it, it’s not great for large org files, I should keep its usage for smaller org files.

(use-package preview-org-html-mode
  :defer t
  :after (org)
  :straight (preview-org-html-mode :build t
                                   :type git
                                   :host github
                                   :repo "jakebox/preview-org-html-mode")
  :general
  (phundrak/major-leader-key
   :keymaps 'org-mode-map
   :packages 'preview-org-html-mode
   :infix "P"
   ""  '(:ignore t :which-key "preview")
   "h" #'preview-org-html-mode
   "r" #'preview-org-html-refresh
   "p" #'preview-org-html-pop-window-to-frame)
  :config
  (setq preview-org-html-refresh-configuration 'save))

Hugo

I manage my blogopen in new window with Hugoopen in new window. Although it natively supports the org format, it’s not great compared to its markdown support. So, instead, let’s directly export our org files as markdown files and let Hugo do the rest of the job for us!

(use-package ox-hugo
  :defer t
  :after ox
  :straight t)

I also have a function for publishing my blog once I exported my articles with ox-hugo. It will compile blog into a public/ directory and copy its content over to my remote server.

(defun phundrak/blog-publish ()
  "Publish my blog through Hugo to my remote server."
  (interactive)
  (let* ((default-directory (expand-file-name "~/org/blog"))
         (public-path       (concat default-directory "/public"))
         (target-path       "/rsync:Tilo:/home/phundrak/www/phundrak.com/blog"))
    (compile "hugo")
    (let ((files (mapcar (lambda (file)
                           (f-relative file public-path))
                         (f-files public-path nil t))))
      (dolist (file files)
        (copy-file (concat public-path "/" file)
                   (concat target-path "/" file)
                   t nil t)))))

LaTeX

When it comes to exports, I want the LaTeX and PDF exports to be done with XeTeX only. I also want LaTeX exports to use my labels rather than org-generated labels.

(setq org-latex-compiler "xelatex"
      org-latex-prefer-user-labels t)

A new backend that was introduced in org-mode for LaTeX source block coloring is engraved.

(use-package engrave-faces
  :straight (:build t))
(require 'engrave-faces)
(setq org-latex-src-block-backend 'engraved)

The default packages break my LaTeX exports: for some reason, images are not loaded and exported in PDFs, so I needed to redefine the default packages excluding the one that broke my exports; namely, I need to remove inputenc, fontenc and grffile. I also added some default packages:

  • cleveref for better references to various elements.
  • svg for inserting SVG files in PDF outputs
  • booktabs for nicer tables
  • and tabularx for tabulars with adjustable columns
(dolist (package '(("AUTO" "inputenc" t ("pdflatex"))
                   ("T1"   "fontenc"  t ("pdflatex"))
                   (""     "grffile"  t)))
  (delete package org-latex-default-packages-alist))

(dolist (package '(("AUTO" "babel" nil ("pdflatex"))
                   ("AUTO" "polyglossia" nil ("xelatex" "lualatex"))
                   ("capitalize" "cleveref")
                   (""           "booktabs")
                   (""           "tabularx")))
  (add-to-list 'org-latex-default-packages-alist package t))

(setq org-latex-reference-command "\\cref{%s}")

By the way, reference links in LaTeX should be written in this format, since we are using cleveref:

(setq org-export-latex-hyperref-format "\\ref{%s}")

Tectonicopen in new window is awesome for processing LaTeX documents! Look how simple it is!

(setq org-latex-pdf-process
      '("tectonic -Z shell-escape --synctex --outdir=%o %f"))

Finally, org-mode is supposed to automatically clean logfiles after it exports an org file to LaTeX. However, it misses a few, so I need to add their extension like so:

(dolist (ext '("bbl" "lot"))
  (add-to-list 'org-latex-logfiles-extensions ext t))

Reveal.js

(use-package org-re-reveal
  :defer t
  :after org
  :straight (:build t)
  :init
  (add-hook 'org-mode-hook (lambda () (require 'org-re-reveal)))
  :config
  (setq org-re-reveal-root "https://cdn.jsdelivr.net/npm/reveal.js"
        org-re-reveal-revealjs-version "4"))

SSH Config

Yet another exporter I enjoy is ox-sshopen in new window with which I manage my $HOME/.ssh/config file. You won’t find my org file for managing my servers on my repos though.

(use-package ox-ssh
  :after (ox org)
  :straight (:build t))

Keybindings

Be prepared, I have a lot of keybindings for org-mode! They are all prefixed with a comma , in normal mode.

Key chordFunctionDescription
RETorg-ctrl-c-ret
*org-ctrl-c-star
,org-ctrl-c-ctrl-c
org-edit-special
-org-ctrl-c-minus
aorg-agenda
corg-capture
Corg-columns
eorg-export-dispatch
lorg-store-link
porg-priority
rorg-reload

I then have a couple of babel-related functions.

Key chordFunctionDescription
bnilbabel
b.org-babel-transient/body
bborg-babel-execute-buffer
bcorg-babel-check-src-block
bCorg-babel-tangle-clean
beorg-babel-execute-maybe
bforg-babel-tangle-file
bnorg-babel-next-src-block
boorg-babel-open-src-block-result
bporg-babel-previous-src-block
brorg-babel-remove-result-one-or-many
bRorg-babel-goto-named-result
btorg-babel-tangle
biorg-babel-view-src-block-info

The org-babel-transient hydra allows me to quickly navigate between code blocks and interact with them. This code block was inspired by one you can find in Spacemacs.

(defhydra org-babel-transient ()
  "
^Navigate^                    ^Interact
^^^^^^^^^^^------------------------------------------
[_t_/_s_] navigate src blocs  [_x_] execute src block
[_g_]^^   goto named block    [_'_] edit src block
[_z_]^^   recenter screen     [_q_] quit
"
  ("q" nil :exit t)
  ("t" org-babel-next-src-block)
  ("s" org-babel-previous-src-block)
  ("g" org-babel-goto-named-src-block)
  ("z" recenter-top-bottom)
  ("x" org-babel-execute-maybe)
  ("'" org-edit-special :exit t))

We next have keybindings related to org-mode’s agenda capabilities. We can schedule a todo header for some dates, or set a deadline.

Key chordFunctionDescription
dnildates
ddorg-deadline
dsorg-schedule
dtorg-time-stamp
dTorg-time-stamp-inactive

Let’s now define some keybinds for inserting stuff in our org buffer:

Key chordFunctionDescription
inilinsert
iborg-insert-structure-template
idorg-insert-drawer
ienilemphasis
ieborg-emphasize-bold
iecorg-emphasize-code
ieiorg-emphasize-italic
iesorg-emphasize-strike-through
ieuorg-emphasize-underline
ievorg-emphasize-verbatim
iEorg-set-effort
iforg-footnote-new
ihorg-insert-heading
iHcounsel-org-link
iiorg-insert-item
ilorg-insert-link
inorg-add-note
iporg-set-property
isorg-insert-subheading
itorg-set-tags-command

There isn’t a lot of stuff I can jump to yet, but there’s still some:

Key chordFunctionDescription
jniljump
jacounsel-org-goto-all
jhcounsel-org-goto

Tables get a bit more love:

Key chordFunctionDescription
tniltables
tcorg-table-move-column-left
ttorg-table-move-row-down
tsorg-table-move-row-up
trorg-table-move-column-right
taorg-table-align
teorg-table-eval-formula
tforg-table-field-info
tForg-table-edit-formulas
thorg-table-convert
tlorg-table-recalculate
tporg-plot/gnuplot
tSorg-table-sort-lines
tworg-table-wrap-region
txorg-table-shrink
tNorg-table-create-with-table.el
tdnildelete
tdcorg-table-delete-column
tdrorg-table-kill-row
tinilinsert
ticorg-table-insert-column
tihorg-table-insert-hline
tirorg-table-insert-row
tiHorg-table-hline-and-move
ttniltoggle
ttforg-table-toggle-formula-debugger
ttoorg-table-toggle-coordinate-overlays

Finally, let’s make enabling and disabling stuff accessible:

Key chordFunctionDescription
Tniltoggle
Tcorg-toggle-checkbox
Tiorg-toggle-inline-images
Tlorg-latex-preview
Tnorg-num-mode
Tsphundrak/toggle-org-src-window-split
Ttorg-show-todo-tree
TTorg-todo

LaTeX formats

I currently have two custom formats for my Org-mode exports: one for general use (initially for my conlanging files, hence its conlang name), and one for beamer exports.

Below is the declaration of the conlang LaTeX class:

'("conlang"
  "\\documentclass{book}"
  ("\\chapter{%s}" . "\\chapter*{%s}")
  ("\\section{%s}" . "\\section*{%s}")
  ("\\subsection{%s}" . "\\subsection*{%s}")
  ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))

And here is the declaration of the beamer class:

`("beamer"
  ,(concat "\\documentclass[presentation]{beamer}\n"
           "[DEFAULT-PACKAGES]"
           "[PACKAGES]"
           "[EXTRA]\n")
  ("\\section{%s}" . "\\section*{%s}")
  ("\\subsection{%s}" . "\\subsection*{%s}")
  ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))

Both these classes have to be added to org-latex-classes like so:

(eval-after-load "ox-latex"
  '(progn
     (add-to-list 'org-latex-classes
                  '("conlang"
                    "\\documentclass{book}"
                    ("\\chapter{%s}" . "\\chapter*{%s}")
                    ("\\section{%s}" . "\\section*{%s}")
                    ("\\subsection{%s}" . "\\subsection*{%s}")
                    ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
     (add-to-list 'org-latex-classes
                  `("beamer"
                    ,(concat "\\documentclass[presentation]{beamer}\n"
                             "[DEFAULT-PACKAGES]"
                             "[PACKAGES]"
                             "[EXTRA]\n")
                    ("\\section{%s}" . "\\section*{%s}")
                    ("\\subsection{%s}" . "\\subsection*{%s}")
                    ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))))

Projects

Another great features of Org-mode is the Org projects that allow the user to easily publish a bunch of org files to a remote location. Here is the current declaration of my projects, which will be detailed later:

(defvar phundrak//projects-config-target
  "/ssh:Tilo:~/www/phundrak.com/config"
  "Points to where exported files for config.phundrak.com should be put.")
(defvar phundrak//projects-config-source
  "~/org/config/"
  "Points to where the sources for config.phundrak.com are.")
(defvar phundrak//projects-config-language
  "en"
  "Language of the website config.phundrak.com.")
(defvar phundrak//projects-config-recursive
  t
  "Defines whether subdirectories should be parsed for config.phundrak.com.")
(setq org-publish-project-alist
      `(("config-website-html"
 :base-directory ,phundrak//projects-config-source
 :base-extension "org"
 :publishing-directory ,phundrak//projects-config-target
 :recursive ,phundrak//projects-config-recursive
 :language ,phundrak//projects-config-language
 :publishing-function org-html-publish-to-html
 :headline-levels 5
 :auto-sitemap t
 :auto-preamble t)
        ("config-website-static"
 :base-directory ,phundrak//projects-config-source
 :base-extension "png\\|jpg\\|gif\\|webp\\|svg\\|jpeg\\|ttf\\|woff\\|txt\\|epub\\|md"
 :publishing-directory ,phundrak//projects-config-target
 :recursive ,phundrak//projects-config-recursive
 :language ,phundrak//projects-config-language
 :publishing-function org-publish-attachment)
        ("config-website"
 :components ("config-website-org"
              "config-website-static"))))

Configuration website

This is my configuration for exporting my dotfiles to my website in a web format only. No PDFs or anything, just HTML. Please note that I do not use that often anymore, I much prefer the automatic script that I have which deploys through my Drone instance my website on git pushes.

And before we get into the actual configuration, I would like to introduce a couple of variables. This is a bit more verbose than if I declared everything manually, but now I can change all three values at the same time without a hasle.

(defvar phundrak//projects-config-target
  "/ssh:Tilo:~/www/phundrak.com/config"
  "Points to where exported files for config.phundrak.com should be put.")
(defvar phundrak//projects-config-source
  "~/org/config/"
  "Points to where the sources for config.phundrak.com are.")
(defvar phundrak//projects-config-language
  "en"
  "Language of the website config.phundrak.com.")
(defvar phundrak//projects-config-recursive
  t
  "Defines whether subdirectories should be parsed for config.phundrak.com.")

Now, here is my configuration. In this snippet, my org files located in my source directory get exported in the HTML format and published to my target directory on my remote server through RSYNC via TRAMP. A sitemap is automatically generated, which comes in handy with the online sitemap that is available through the navigation bar.

("config-website-html"
 :base-directory ,phundrak//projects-config-source
 :base-extension "org"
 :publishing-directory ,phundrak//projects-config-target
 :recursive ,phundrak//projects-config-recursive
 :language ,phundrak//projects-config-language
 :publishing-function org-html-publish-to-html
 :headline-levels 5
 :auto-sitemap t
 :auto-preamble t)

We also have the component for all the static files needed to run the website (mostly images tbh).

("config-website-static"
 :base-directory ,phundrak//projects-config-source
 :base-extension "png\\|jpg\\|gif\\|webp\\|svg\\|jpeg\\|ttf\\|woff\\|txt\\|epub\\|md"
 :publishing-directory ,phundrak//projects-config-target
 :recursive ,phundrak//projects-config-recursive
 :language ,phundrak//projects-config-language
 :publishing-function org-publish-attachment)

The project is then defined like so:

("config-website"
 :components ("config-website-org"
              "config-website-static"))

Org-roam

After hearing about it for so many years and thinking I really should install it one day, 2023 is finally the year I installed org-roam! For those unaware of it, org-roam is a Zettelkasten-style knowledge management system based on org-mode.

(use-package org-roam
  :straight (:build t)
  :defer t
  :custom
  (org-roam-directory (expand-file-name "org/roam/" (getenv "HOME")))
  (org-roam-completion-everywhere t)
  :config
  (org-roam-db-autosync-mode 1)
  :general
  (phundrak/major-leader-key
    :keymaps 'org-mode-map
    :packages '(org org-roam)
    "h"   #'org-id-get-create
    "r"   '(:ignore t :which-key "roam")
    "ra"  '(:ignore t :which-key "alias")
    "raa" #'org-roam-alias-add
    "rar" #'org-roam-alias-remove))
(use-package org-roam-ui
  :straight (:build t)
  :defer t
  :after org-roam
  :config
  (setq org-roam-ui-sync-theme t
        org-roam-ui-follow t
        org-roam-ui-update-on-save t
        org-roam-ui-open-on-start t))

Org-ref and Bibtex configuration

(use-package reftex
  :commands turn-on-reftex
  :init (setq reftex-default-bibliography "~/org/bibliography/references.bib"
              reftex-plug-into-AUCTeX     t))
(use-package org-ref
  ;; :after (org ox-bibtex pdf-tools)
  :after org
  :defer t
  :straight (:build t)
  :custom-face
  (org-ref-cite-face ((t (:weight bold))))
  :init
  (setq org-ref-completion-library    'org-ref-ivy-cite
        org-latex-logfiles-extensions '("lof" "lot" "aux" "idx" "out" "log" "fbd_latexmk"
                                        "toc" "nav" "snm" "vrb" "dvi" "blg" "brf" "bflsb"
                                        "entoc" "ps" "spl" "bbl" "pygtex" "pygstyle"))
  (add-hook 'org-mode-hook (lambda () (require 'org-ref)))
  :config
  (setq bibtex-completion-pdf-field    "file"
        bibtex-completion-notes-path   "~/org/bibliography/notes/"
        bibtex-completion-bibliography "~/org/bibliography/references.bib"
        bibtex-completion-library-path "~/org/bibliography/bibtex-pdfs/"
        bibtex-completion-pdf-symbol   "⌘"
        bibtex-completion-notes-symbol "✎")
  :general
  (phundrak/evil
   :keymaps 'bibtex-mode-map
   :packages 'org-ref
   "C-t" #'org-ref-bibtex-next-entry
   "C-s" #'org-ref-bibtex-previous-entry
   "gt"  #'org-ref-bibtex-next-entry
   "gs"  #'org-ref-bibtex-previous-entry)
  (phundrak/major-leader-key
   :keymaps '(bibtex-mode-map)
   :packages 'org-ref
   ;; Navigation
   "t" #'org-ref-bibtex-next-entry
   "s" #'org-ref-bibtex-previous-entry

   ;; Open
   "b" #'org-ref-open-in-browser
   "n" #'org-ref-open-bibtex-notes
   "p" #'org-ref-open-bibtex-pdf

   ;; Misc
   "h" #'org-ref-bibtex-hydra/body
   "i" #'org-ref-bibtex-hydra/org-ref-bibtex-new-entry/body-and-exit
   "s" #'org-ref-sort-bibtex-entry

   "l" '(:ignore t :which-key "lookup")
   "la" #'arxiv-add-bibtex-entry
   "lA" #'arxiv-get-pdf-add-bibtex-entry
   "ld" #'doi-utils-add-bibtex-entry-from-doi
   "li" #'isbn-to-bibtex
   "lp" #'pubmed-insert-bibtex-from-pmid)
  (phundrak/major-leader-key
   :keymaps 'org-mode-map
   :pakages 'org-ref
   "ic" #'org-ref-insert-link
   "iL" #'org-ref-insert-ref-link
   "ir" #'org-ref-insert-link-hydra/body
   "iB" #'org-ref-bibtex-hydra/body))
(use-package ivy-bibtex
  :defer t
  :straight (:build t)
  :config
  (setq bibtex-completion-pdf-open-function #'find-file)
  :general
  (phundrak/leader-key
    :keymaps '(bibtex-mode-map)
    :packages 'ivy-bibtex
    "m" #'ivy-bibtex))

Org-present

org-present allows its user to create presentations through org-mode, which is really nice! However, most of my configuration will be stolen from Daviwil’sopen in new window with minor changes.

(defun my/org-present-prepare-slide ()
  (org-overview)
  (org-show-entry)
  (org-show-children)
  (org-present-hide-cursor))

(defun my/org-present-init ()
  (setq header-line-format " ")
  (org-display-inline-images)
  (my/org-present-prepare-slide))

(defun my/org-present-quit ()
  (setq header-line-format nil)
  (org-present-small)
  (org-present-show-cursor))

(defun my/org-present-prev ()
  (interactive)
  (org-present-prev)
  (my/org-present-prepare-slide))

(defun my/org-present-next ()
  (interactive)
  (org-present-next)
  (my/org-present-prepare-slide))

(use-package org-present
  :after org
  :defer t
  :straight (:build t)
  :general
  (phundrak/major-leader-key
    :packages 'org-present
    :keymaps 'org-mode-map
    "P" #'org-present)
  (phundrak/evil
    :states 'normal
    :packages 'org-present
    :keymaps 'org-present-mode-keymap
    "+" #'org-present-big
    "-" #'org-present-small
    "<" #'org-present-beginning
    ">" #'org-present-end
    "«" #'org-present-beginning
    "»" #'org-present-end
    "c" #'org-present-hide-cursor
    "C" #'org-present-show-cursor
    "n" #'org-present-next
    "p" #'org-present-prev
    "r" #'org-present-read-only
    "w" #'org-present-read-write
    "q" #'org-present-quit)
  :hook ((org-present-mode      . my/org-present-init)
         (org-present-mode-quit . my/org-present-quit)))

Tangle config org files on save

Something really, really useful is tangling all my configuration files on save. For this, a dedicated function will do the trick.

(defun my/tangle-config-file ()
  (when (and (eq major-mode 'org-mode)
             (f-ancestor-of-p (f-full "~/.nosync/org/config") default-directory))
    (org-babel-tangle)))

(add-hook 'after-save-hook #'my/tangle-config-file)

Visual Configuration

While most modes of Emacs are dedicated to development, and therefore are much more comfortable with a fixed-pitch font, more literary modes such as org-mode are much more enjoyable if you have a variable pitch font enabled. BUT, these modes can also require some fixed-pitch fonts for some elements of the buffer, such as code blocks with org-mode. mixed-pitch comes to the rescue!

(use-package mixed-pitch
  :after org
  :straight (:build t)
  :hook
  (org-mode           . mixed-pitch-mode)
  (emms-browser-mode  . mixed-pitch-mode)
  (emms-playlist-mode . mixed-pitch-mode)
  :config
  (add-hook 'org-agenda-mode-hook (lambda () (mixed-pitch-mode -1))))

I have an issue with org-mode’s emphasis markers: I find them ugly. I can of course hide them if I simply set org-hide-emphasis-markers to t, but it makes editing hard since I never know whether I am before or after the emphasis marker when editing near the beginning/end of an emphasized region. org-appear fixes this issue so that it shows the emphasis markers only when the cursor is in the emphasized region, otherwise they will remain hidden! Very cool!

(use-package org-appear
  :after org
  :straight (:build t)
  :hook (org-mode . org-appear-mode)
  :config
  (setq org-appear-autoemphasis   t
        org-hide-emphasis-markers t
        org-appear-autolinks      t
        org-appear-autoentities   t
        org-appear-autosubmarkers t)
  (run-at-time nil nil #'org-appear--set-elements))

Similarly, LaTeX fragments previews are nice and all, but if I have my cursor on it, I want to see the LaTeX source code and modify it, not just the generated image!

(use-package org-fragtog
  :defer t
  :after org
  :straight (:build t)
  :hook (org-mode . org-fragtog-mode))

Org-modern modernizes a bit the appearance of org buffers, including tables, source blocks, and tags, and it applies settings similar to org-superstar which I used to use.

(use-package org-modern
  :straight (:build t)
  :after org
  :defer t
  :custom (org-modern-table nil)
  :hook (org-mode . org-modern-mode)
  :hook (org-agenda-finalize . org-modern-agenda))

org-fancy-priorities change the priority of an org element such as #A to anything user-defined. Let’s all-the-iconify this!

(use-package org-fancy-priorities
  :after (org all-the-icons)
  :straight (:build t)
  :hook (org-mode        . org-fancy-priorities-mode)
  :hook (org-agenda-mode . org-fancy-priorities-mode)
  :config
  (setq org-fancy-priorities-list `(,(all-the-icons-faicon "flag"     :height 1.1 :v-adjust 0.0)
                                    ,(all-the-icons-faicon "arrow-up" :height 1.1 :v-adjust 0.0)
                                    ,(all-the-icons-faicon "square"   :height 1.1 :v-adjust 0.0))))

Org Outline Tree is a better way of managing my org files’ outline.

(use-package org-ol-tree
  :after (org avy)
  :defer t
  :straight (org-ol-tree :build t
                         :host github
                         :type git
                         :repo "Townk/org-ol-tree")
  :general
  (phundrak/major-leader-key
    :packages 'org-ol-tree
    :keymaps 'org-mode-map
    "O" #'org-ol-tree))
(add-hook 'org-mode-hook
          (lambda ()
            (dolist (pair '(("[ ]"         . ?☐)
                            ("[X]"         . ?☑)
                            ("[-]"         . ?❍)
                            ("#+title:"    . ?📕)
                            ("#+TITLE:"    . ?📕)
                            ("#+author:"   . ?✎)
                            ("#+AUTHOR:"   . ?✎)
                            ("#+email:"    . ?📧)
                            ("#+EMAIL:"    . ?📧)
                            ("#+include"   . ?⭳)
                            ("#+INCLUDE"   . ?⭳)
                            ("#+begin_src" .)
                            ("#+BEGIN_SRC" .)
                            ("#+end_src"   .)
                            ("#+END_SRC"   .)))
              (add-to-list 'prettify-symbols-alist pair))
            (prettify-symbols-mode)))

Misc

org-tree-slide is a presentation tool for org-mode.

(use-package org-tree-slide
  :defer t
  :after org
  :straight (:build t)
  :config
  (setq org-tree-slide-skip-done nil)
  :general
  (phundrak/evil
    :keymaps 'org-mode-map
    :packages 'org-tree-slide
    "<f8>" #'org-tree-slide-mode)
  (phundrak/major-leader-key
    :keymaps 'org-tree-slide-mode-map
    :packages 'org-tree-slide
    "d" (lambda () (interactive (setq org-tree-slide-skip-done (not org-tree-slide-skip-done))))
    "p" #'org-tree-slide-move-next-tree
    "n" #'org-tree-slide-move-previous-tree
    "t" #'org-tree-slide-move-next-tree
    "s" #'org-tree-slide-move-previous-tree
    "u" #'org-tree-slide-content))

org-roll is a simple package for tabletop RPGs for rolling dice.

(use-package org-roll
  :defer t
  :after org
  :straight (:build t :type git :host github :repo "zaeph/org-roll"))