config.phundrak.com/docs/emacs/packages/org.org

1378 lines
52 KiB
Org Mode
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#+title: Emacs — Packages — Org Mode
#+setupfile: ../../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/org.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* Org-mode
#+name: general-keybindings-gen
#+header: :tangle no :exports none :results value :cache yes
#+begin_src emacs-lisp :var table=org-keybinds-babel prefix=""
(mapconcat (lambda (line)
(let* ((key (nth 0 line))
(function (nth 1 line))
(comment (or (nth 2 line) ""))
(package (or (nth 3 line) "")))
(format "\"%s%s\" %s"
prefix
key
(if (string= "" comment)
(if (member function '("" "nil")) "nil" (concat "#'" function))
(format "'(%s :wk %s%s)"
(if (member function '("" "nil")) ":ignore t" function)
(if (member function '("none" "nil")) "t" (concat "\"" comment "\""))
(if (string-blank-p package) "" (concat ":package " package)))))))
table
"\n")
#+end_src
Since recently, in order to make ~org-cite~ compile properly, we need
the ~citeproc~ package, a citation processor.
#+begin_src emacs-lisp
(use-package citeproc
:after (org)
:defer t
:straight (:build t))
#+end_src
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!
#+begin_src emacs-lisp
(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))
#+end_src
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.
#+begin_src emacs-lisp
(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))
#+end_src
This package is a small package Ive written that helps me when
writing conlanging documents, with features such as creating syntax
trees, converting translitterated text to its native script, etc…
#+begin_src emacs-lisp
(use-package conlanging
:straight (conlanging :build t
:type git
:repo "https://labs.phundrak.com/phundrak/conlanging.el")
:after org
:defer t)
#+end_src
Since very recently, the ~contrib/lisp/~ directory of org moved out of
the main repository to [[https://git.sr.ht/~bzg/org-contrib][this repository]]. On the other hand,
~contrib/scripts/~ moved to [[https://code.orgmode.org/bzg/worg/src/master/code][the worg repository]], but I dont need
it. The main reason I want ~org-contrib~ is due to ~ox-extra~ that allow
the usage of the ~:ignore:~ tag in org.
#+begin_src emacs-lisp
(use-package org-contrib
:after (org)
:defer t
:straight (:build t)
:init
(require 'ox-extra)
(ox-extras-activate '(latex-header-blocks ignore-headlines)))
#+end_src
** Agenda
#+name: org-agenda-files
#+begin_src emacs-lisp :tangle no
(setq org-agenda-files (list "~/org/agenda" "~/org/notes.org"))
#+end_src
#+begin_src emacs-lisp
(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"))))
#+end_src
** 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:
#+NAME: org-babel-languages-table
| C |
| emacs-lisp |
| gnuplot |
| latex |
| makefile |
| plantuml |
| python |
| sass |
| shell |
| sql |
#+NAME: org-babel-languages-gen
#+header: :cache yes :results replace
#+header: :var languages=org-babel-languages-table[,0]
#+BEGIN_SRC emacs-lisp :exports none :tangle no
(format "'(%s)"
(mapconcat (lambda ($language)
(format "(%s . t)" $language))
languages
"\n "))
#+END_SRC
#+RESULTS[b0a5bea13e6ba99525ad166ea5538e74ba4c6ddc]: org-babel-languages-gen
#+begin_example
'((C . t)
(emacs-lisp . t)
(gnuplot . t)
(latex . t)
(makefile . t)
(plantuml . t)
(python . t)
(sass . t)
(shell . t)
(sql . t))
#+end_example
The corresponding code is as follows:
#+NAME: org-babel-load-languages
#+BEGIN_SRC emacs-lisp :noweb yes :tangle no
(org-babel-do-load-languages
'org-babel-load-languages
<<org-babel-languages-gen()>>)
#+END_SRC
Some languages can run asynchronously with the help of ~ob-async~.
#+begin_src emacs-lisp
(use-package ob-async
:straight (:build t)
:defer t
:after (org ob))
#+end_src
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:
#+begin_src emacs-lisp
(use-package ob-latex-as-png
:after org
:straight (:build t))
#+end_src
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!
#+begin_src emacs-lisp
(use-package ob-restclient
:straight (:build t)
:defer t
:after (org ob)
:init
(add-to-list 'org-babel-load-languages '(restclient . t)))
#+end_src
** 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.
#+begin_src emacs-lisp
(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))
#+end_src
~electric-mode~ also bothers me a lot when editing org files, so lets deactivate it:
#+name: org-behavior-electric
#+begin_src emacs-lisp :tangle no
(add-hook 'org-mode-hook (lambda ()
(interactive)
(electric-indent-local-mode -1)))
#+end_src
As explained in my [[https://blog.phundrak.com/better-custom-ids-orgmode/][blog post]], org-mode is terrible with coming up with
meaningful IDs for its headings. I actually wrote a package for this!
#+begin_src emacs-lisp
(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))
#+end_src
** 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.
#+name: org-capture-target-files
#+begin_src emacs-lisp :tangle no
(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")
#+end_src
When ~org-capture~ is invoked, it will ask which template we wish to
use. In the table [[org-capture-shortcuts-table]], 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/.
#+name: org-capture-shortcuts-table
| Shortcut | Name | Title | Insertion mode | file | template |
|----------+---------------+-----------+----------------+-------------------------+--------------------------|
| e | Email | | | | |
| ew | Write Email | Emails | file+headline | org-default-notes-file | email.orgcaptmpl |
| j | Journal | | file+datetree | org-journal-file | journal.orgcaptmpl |
| l | Link | | | | |
| ll | General | | file+headline | org-default-notes-file | link.orgcaptmpl |
| ly | YouTube | | file+headline | org-default-notes-file | youtube.orgcaptmpl |
| L | Protocol Link | Link | file+headline | org-default-notes-file | protocol-link.orgcaptmpl |
| n | Notes | | | | |
| nc | Conlanging | Note | file+headline | org-conlanging-file | notes.orgcaptmpl |
| nn | General | | file+headline | org-default-notes-file | notes.orgcaptmpl |
| nN | Novel | Note | file+headline | org-novel-notes-file | notes.orgcaptmpl |
| nq | Quote | | file+headline | org-default-notes-file | notes-quote.orgcaptmpl |
| nw | Worldbuilding | Note | file+headline | org-wordbuilding-file | notes.orgcaptmpl |
| N | Novel | | | | |
| Ni | Ideas | | file+headline | org-novel-notes-file | notes.orgcaptmpl |
| p | Protocol | Link | file+headline | org-default-notes-file | protocol.orgcaptmpl |
| r | Resources | | | | |
| rc | Conlanging | Resources | file+headline | org-conlanging-file | resource.orgcaptmpl |
| re | Emacs | | file+headline | org-default-notes-file | resource.orgcaptmpl |
| ri | Informatique | | file+headline | org-default-notes-file | resource.orgcaptmpl |
| rl | Linguistics | | file+headline | org-default-notes-file | resource.orgcaptmpl |
| rL | Linux | | file+headline | org-default-notes-file | resource.orgcaptmpl |
| rw | Worldbuilding | Resources | file+headline | org-wordbuilding-file | resource.orgcaptmpl |
| t | Tasks | | | | |
| tb | Birthday | | file+headline | org-private-agenda-file | birthday.orgcaptmpl |
| te | Event | | file+headline | org-private-agenda-file | event.orgcaptmpl |
| th | Health | | file+headline | org-private-agenda-file | health.orgcaptmpl |
| ti | Informatique | | file+headline | org-private-agenda-file | informatique.orgcaptmpl |
All templates can be found [[https://labs.phundrak.com/phundrak/dotfiles/src/branch/master/org/capture][in my dotfiles repository]].
#+name: org-capture-shortcuts-gen
#+header: :exports none :cache yes :tangle no
#+begin_src emacs-lisp :var entries=org-capture-shortcuts-table
(mapconcat (lambda (entry)
(let ((key (nth 0 entry))
(name (nth 1 entry))
(title (nth 2 entry))
(ins-mode (nth 3 entry))
(file (nth 4 entry))
(template (nth 5 entry)))
(if (string= "" ins-mode)
(format "%S" `(,key ,name))
(format "(\"%s\" \"%s\" entry\n %S\n %S)"
key name
`(,(intern ins-mode) ,(intern file) ,(if (string= "file+datetree" ins-mode)
(intern "")
(if (string= title "")
name
title)))
`(file ,(concat "~/org/capture/" template))))))
entries
"\n")
#+end_src
#+RESULTS[9f565c3dd73becfad0a99c0cfaf4521762334b40]: org-capture-shortcuts-gen
#+begin_example
("e" "Email")
("ew" "Write Email" entry
(file+headline org-default-notes-file "Emails")
(file "~/org/capture/email.orgcaptmpl"))
("j" "Journal" entry
(file+datetree org-journal-file ##)
(file "~/org/capture/journal.orgcaptmpl"))
("l" "Link")
("ll" "General" entry
(file+headline org-default-notes-file "General")
(file "~/org/capture/link.orgcaptmpl"))
("ly" "YouTube" entry
(file+headline org-default-notes-file "YouTube")
(file "~/org/capture/youtube.orgcaptmpl"))
("L" "Protocol Link" entry
(file+headline org-default-notes-file "Link")
(file "~/org/capture/protocol-link.orgcaptmpl"))
("n" "Notes")
("nc" "Conlanging" entry
(file+headline org-conlanging-file "Note")
(file "~/org/capture/notes.orgcaptmpl"))
("nn" "General" entry
(file+headline org-default-notes-file "General")
(file "~/org/capture/notes.orgcaptmpl"))
("nN" "Novel" entry
(file+headline org-novel-notes-file "Note")
(file "~/org/capture/notes.orgcaptmpl"))
("nq" "Quote" entry
(file+headline org-default-notes-file "Quote")
(file "~/org/capture/notes-quote.orgcaptmpl"))
("nw" "Worldbuilding" entry
(file+headline org-wordbuilding-file "Note")
(file "~/org/capture/notes.orgcaptmpl"))
("N" "Novel")
("Ni" "Ideas" entry
(file+headline org-novel-notes-file "Ideas")
(file "~/org/capture/notes.orgcaptmpl"))
("p" "Protocol" entry
(file+headline org-default-notes-file "Link")
(file "~/org/capture/protocol.orgcaptmpl"))
("r" "Resources")
("rc" "Conlanging" entry
(file+headline org-conlanging-file "Resources")
(file "~/org/capture/resource.orgcaptmpl"))
("re" "Emacs" entry
(file+headline org-default-notes-file "Emacs")
(file "~/org/capture/resource.orgcaptmpl"))
("ri" "Informatique" entry
(file+headline org-default-notes-file "Informatique")
(file "~/org/capture/resource.orgcaptmpl"))
("rl" "Linguistics" entry
(file+headline org-default-notes-file "Linguistics")
(file "~/org/capture/resource.orgcaptmpl"))
("rL" "Linux" entry
(file+headline org-default-notes-file "Linux")
(file "~/org/capture/resource.orgcaptmpl"))
("rw" "Worldbuilding" entry
(file+headline org-wordbuilding-file "Resources")
(file "~/org/capture/resource.orgcaptmpl"))
("t" "Tasks")
("tb" "Birthday" entry
(file+headline org-private-agenda-file "Birthday")
(file "~/org/capture/birthday.orgcaptmpl"))
("te" "Event" entry
(file+headline org-private-agenda-file "Event")
(file "~/org/capture/event.orgcaptmpl"))
("th" "Health" entry
(file+headline org-private-agenda-file "Health")
(file "~/org/capture/health.orgcaptmpl"))
("ti" "Informatique" entry
(file+headline org-private-agenda-file "Informatique")
(file "~/org/capture/informatique.orgcaptmpl"))
#+end_example
The capture templates are set like so:
#+name: org-capture-templates
#+begin_src emacs-lisp :tangle no :results silent
(setq org-capture-templates
'(
<<org-capture-shortcuts-gen()>>))
#+end_src
** Custom functions
*** Emphasize text
Sometimes, I want to emphasize some text in my org-mode documents.
Its 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 Im 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 [[org-emphasis-character]] 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.
#+name: org-emphasis-character
| Emphasis | Character | Character code |
|----------------+-----------+----------------|
| bold | ~*~ | 42 |
| italic | ~/~ | 47 |
| underline | ~_~ | 95 |
| verbatim | ~=~ | 61 |
| code | ~~~ | 126 |
| strike-through | ~+~ | 43 |
#+name: org-create-emphasis-functions
#+header: :tangle no :exports results :cache yes
#+header: :wrap "src emacs-lisp :tangle no :exports code"
#+begin_src emacs-lisp :var emphasis-list=org-emphasis-character
(mapconcat (lambda (emphasis)
(let ((type (car emphasis))
(code (nth 2 emphasis)))
(format "(defun org-emphasize-%s ()
\"Emphasize as %s the current region.\"
(interactive)
(org-emphasize %s))"
type
type
code)))
emphasis-list
"\n")
#+end_src
#+RESULTS[dbd10cce4ae05a046838214784f0f4c16765e728]: org-create-emphasis-functions
#+begin_src emacs-lisp :tangle no :exports code
(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))
#+end_src
You can find the keybinds for these functions [[file:./org#keybindings][here]].
*** ~phundrak/toggle-org-src-window-split~
#+begin_src emacs-lisp
(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")))
#+end_src
** 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, lets disable it:
#+NAME: org-use-sub-superscripts
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-use-sub-superscripts (quote {}))
#+END_SRC
*** Epub
A backend for exporting files through org I like is ~ox-epub~ which, as
you can guess, exports org files to the [[https://www.w3.org/publishing/epub32/][Epub format]].
#+begin_src emacs-lisp
(use-package ox-epub
:after (org ox)
:straight (:build t))
#+end_src
*** Gemini
Gemini is a lightweight protocol for creating lightweight websites
that are basically text-only websites with maybe some images. Im
currently maintaining my own fork of Justin Abrahms =ox-gemini= which
fixes two issues I had with the original package.
#+begin_src emacs-lisp
(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))
#+end_src
*** HTML
On HTML exports, Org-mode tries to include a validation link for the
exported HTML. Lets disable that since I never use it.
#+NAME: org-html-validation
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-html-validation-link nil)
#+END_SRC
This package allows for live-previewing the HTML export of an org
buffer in an XWidget Webkit browser window. But when testing it, its
not great for large org files, I should keep its usage for smaller org
files.
#+begin_src emacs-lisp
(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))
#+end_src
*** Hugo
I manage [[https://blog.phundrak.com][my blog]] with [[https://gohugo.io/][Hugo]]. Although it natively supports the org
format, its not great compared to its markdown support. So, instead,
lets directly export our org files as markdown files and let Hugo do
the rest of the job for us!
#+begin_src emacs-lisp
(use-package ox-hugo
:defer t
:after ox
:straight t)
#+end_src
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.
#+begin_src emacs-lisp
(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)))))
#+end_src
*** 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.
#+NAME: org-latex-compiler
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-latex-compiler "xelatex"
org-latex-prefer-user-labels t)
#+END_SRC
A new backend that was introduced in org-mode for LaTeX source block
coloring is ~engraved~.
#+BEGIN_SRC emacs-lisp
(use-package engrave-faces
:straight (:build t))
#+END_SRC
#+name: org-latex-src-block-backend
#+begin_src emacs-lisp :tangle no
(require 'engrave-faces)
(setq org-latex-src-block-backend 'engraved)
#+end_src
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
#+NAME: org-latex-default-packages
#+BEGIN_SRC emacs-lisp :tangle no
(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}")
#+END_SRC
By the way, reference links in LaTeX should be written in this format,
since we are using ~cleveref~:
#+NAME: org-export-latex-hyperref-format
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-export-latex-hyperref-format "\\ref{%s}")
#+END_SRC
[[https://tectonic-typesetting.github.io/en-US/][Tectonic]] is awesome for processing LaTeX documents! Look how simple it
is!
#+NAME: org-latex-pdf-process
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-latex-pdf-process
'("tectonic -Z shell-escape --synctex --outdir=%o %f"))
#+END_SRC
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:
#+name: org-latex-logfiles-add-extensions
#+begin_src emacs-lisp :tangle no
(dolist (ext '("bbl" "lot"))
(add-to-list 'org-latex-logfiles-extensions ext t))
#+end_src
*** Reveal.js
#+NAME: org-re-reveal
#+begin_src emacs-lisp
(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"))
#+end_src
*** SSH Config
Yet another exporter I enjoy is [[https://github.com/dantecatalfamo/ox-ssh][~ox-ssh~]] with which I manage my
~$HOME/.ssh/config~ file. You wont find my org file for managing my
servers on my repos though.
#+begin_src emacs-lisp
(use-package ox-ssh
:after (ox org)
:straight (:build t))
#+end_src
** Keybindings
Be prepared, I have a lot of keybindings for org-mode! They are all
prefixed with a comma ~,~ in normal mode.
#+name: org-keybinds-various
| Key chord | Function | Description |
|-----------+---------------------+-------------|
| RET | org-ctrl-c-ret | |
| * | org-ctrl-c-star | |
| , | org-ctrl-c-ctrl-c | |
| ' | org-edit-special | |
| - | org-ctrl-c-minus | |
| a | org-agenda | |
| c | org-capture | |
| C | org-columns | |
| e | org-export-dispatch | |
| l | org-store-link | |
| p | org-priority | |
| r | org-reload | |
I then have a couple of babel-related functions.
#+name: org-keybinds-babel
| Key chord | Function | Description |
|-----------+-------------------------------------+-------------|
| b | nil | babel |
| b. | org-babel-transient/body | |
| bb | org-babel-execute-buffer | |
| bc | org-babel-check-src-block | |
| bC | org-babel-tangle-clean | |
| be | org-babel-execute-maybe | |
| bf | org-babel-tangle-file | |
| bn | org-babel-next-src-block | |
| bo | org-babel-open-src-block-result | |
| bp | org-babel-previous-src-block | |
| br | org-babel-remove-result-one-or-many | |
| bR | org-babel-goto-named-result | |
| bt | org-babel-tangle | |
| bi | org-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.
#+name: org-hydra-babel
#+begin_src emacs-lisp :tangle no
(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))
#+end_src
We next have keybindings related to org-modes agenda capabilities. We
can schedule a todo header for some dates, or set a deadline.
#+name: org-keybinds-dates
| Key chord | Function | Description |
|-----------+-------------------------+-------------|
| d | nil | dates |
| dd | org-deadline | |
| ds | org-schedule | |
| dt | org-time-stamp | |
| dT | org-time-stamp-inactive | |
Lets now define some keybinds for inserting stuff in our org buffer:
#+name: org-keybinds-insert
| Key chord | Function | Description |
|-----------+-------------------------------+-------------|
| i | nil | insert |
| ib | org-insert-structure-template | |
| id | org-insert-drawer | |
| ie | nil | emphasis |
| ieb | org-emphasize-bold | |
| iec | org-emphasize-code | |
| iei | org-emphasize-italic | |
| ies | org-emphasize-strike-through | |
| ieu | org-emphasize-underline | |
| iev | org-emphasize-verbatim | |
| iE | org-set-effort | |
| if | org-footnote-new | |
| ih | org-insert-heading | |
| iH | counsel-org-link | |
| ii | org-insert-item | |
| il | org-insert-link | |
| in | org-add-note | |
| ip | org-set-property | |
| is | org-insert-subheading | |
| it | org-set-tags-command | |
There isnt a lot of stuff I can jump to yet, but theres still some:
#+name: org-keybinds-jump
| Key chord | Function | Description |
|-----------+----------------------+-------------|
| j | nil | jump |
| ja | counsel-org-goto-all | |
| jh | counsel-org-goto | |
Tables get a bit more love:
#+name: org-keybinds-tables
| Key chord | Function | Description |
|-----------+--------------------------------------+-------------|
| t | nil | tables |
| tc | org-table-move-column-left | |
| tt | org-table-move-row-down | |
| ts | org-table-move-row-up | |
| tr | org-table-move-column-right | |
| ta | org-table-align | |
| te | org-table-eval-formula | |
| tf | org-table-field-info | |
| tF | org-table-edit-formulas | |
| th | org-table-convert | |
| tl | org-table-recalculate | |
| tp | org-plot/gnuplot | |
| tS | org-table-sort-lines | |
| tw | org-table-wrap-region | |
| tx | org-table-shrink | |
| tN | org-table-create-with-table.el | |
| td | nil | delete |
| tdc | org-table-delete-column | |
| tdr | org-table-kill-row | |
| ti | nil | insert |
| tic | org-table-insert-column | |
| tih | org-table-insert-hline | |
| tir | org-table-insert-row | |
| tiH | org-table-hline-and-move | |
| tt | nil | toggle |
| ttf | org-table-toggle-formula-debugger | |
| tto | org-table-toggle-coordinate-overlays | |
Finally, lets make enabling and disabling stuff accessible:
#+name: org-keybinds-toggles
| Key chord | Function | Description |
|-----------+--------------------------------------+-------------|
| T | nil | toggle |
| Tc | org-toggle-checkbox | |
| Ti | org-toggle-inline-images | |
| Tl | org-latex-preview | |
| Tn | org-num-mode | |
| Ts | phundrak/toggle-org-src-window-split | |
| Tt | org-show-todo-tree | |
| TT | org-todo | |
** LaTeX formats
:PROPERTIES:
:header-args:emacs-lisp: :tangle no :exports code :results silent
:END:
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:
#+NAME: org-latex-class-conlang
#+BEGIN_SRC emacs-lisp
'("conlang"
"\\documentclass{book}"
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
#+END_SRC
And here is the declaration of the ~beamer~ class:
#+NAME: org-latex-class-beamer
#+BEGIN_SRC emacs-lisp
`("beamer"
,(concat "\\documentclass[presentation]{beamer}\n"
"[DEFAULT-PACKAGES]"
"[PACKAGES]"
"[EXTRA]\n")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
#+END_SRC
Both these classes have to be added to ~org-latex-classes~ like so:
#+NAME: org-latex-classes
#+BEGIN_SRC emacs-lisp :noweb yes
(eval-after-load "ox-latex"
'(progn
(add-to-list 'org-latex-classes
<<org-latex-class-conlang>>)
(add-to-list 'org-latex-classes
<<org-latex-class-beamer>>)))
#+END_SRC
** Projects
:PROPERTIES:
:header-args:emacs-lisp: :tangle no :exports code :results silent
:END:
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:
#+NAME: org-publish-projects
#+BEGIN_SRC emacs-lisp :noweb yes :noweb-prefix no
<<org-proj-config-setup>>
(setq org-publish-project-alist
`(<<org-proj-config-html>>
<<org-proj-config-static>>
<<org-proj-config>>))
#+END_SRC
*** 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.
#+NAME: org-proj-config-setup
#+BEGIN_SRC emacs-lisp
(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.")
#+END_SRC
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.
#+NAME: org-proj-config-html
#+BEGIN_SRC emacs-lisp
("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)
#+END_SRC
We also have the component for all the static files needed to run the website
(mostly images tbh).
#+NAME: org-proj-config-static
#+BEGIN_SRC emacs-lisp
("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)
#+END_SRC
The project is then defined like so:
#+NAME: org-proj-config
#+BEGIN_SRC emacs-lisp
("config-website"
:components ("config-website-org"
"config-website-static"))
#+END_SRC
** 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.
#+begin_src emacs-lisp
(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))
#+end_src
#+begin_src emacs-lisp
(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))
#+end_src
** Org-ref and Bibtex configuration
#+begin_src emacs-lisp
(use-package reftex
:commands turn-on-reftex
:init (setq reftex-default-bibliography "~/org/bibliography/references.bib"
reftex-plug-into-AUCTeX t))
#+end_src
#+begin_src emacs-lisp
(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))
#+end_src
#+begin_src emacs-lisp
(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))
#+end_src
** 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
[[https://config.daviwil.com/emacs#org-present][from Daviwils]] with minor changes.
#+begin_src emacs-lisp
(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)))
#+end_src
** 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.
#+begin_src emacs-lisp
(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)
#+end_src
** 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!
#+begin_src emacs-lisp
(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))))
#+end_src
I have an issue with org-modes 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!
#+begin_src emacs-lisp
(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))
#+end_src
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!
#+begin_src emacs-lisp
(use-package org-fragtog
:defer t
:after org
:straight (:build t)
:hook (org-mode . org-fragtog-mode))
#+end_src
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.
#+begin_src emacs-lisp
(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))
#+end_src
~org-fancy-priorities~ change the priority of an org element such as ~#A~
to anything user-defined. Lets all-the-iconify this!
#+begin_src emacs-lisp
(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))))
#+end_src
/Org Outline Tree/ is a better way of managing my org files outline.
#+begin_src emacs-lisp
(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))
#+end_src
#+name: org-mode-visual-prettify-symbols
#+begin_src emacs-lisp
(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)))
#+end_src
** Misc
~org-tree-slide~ is a presentation tool for org-mode.
#+begin_src emacs-lisp
(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))
#+end_src
~org-roll~ is a simple package for tabletop RPGs for rolling dice.
#+begin_src emacs-lisp
(use-package org-roll
:defer t
:after org
:straight (:build t :type git :host github :repo "zaeph/org-roll"))
#+end_src