#+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 <> (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"))) <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> :general (phundrak/evil :keymaps 'org-mode-map :packages 'org "RET" 'org-open-at-point) (phundrak/major-leader-key :keymaps 'org-mode-map :packages 'org <> <> <> <> <> <> <>) <> (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 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… #+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 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. #+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 <>) #+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 let’s 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 Let me describe a keybind to invoke org-capture from anywhere within Emacs. #+name: org-capture-keybinds #+begin_src emacs-lisp :tangle no (phundrak/leader-key :packages 'org :infix "o" "" '(:ignore t :which-key "org") "c" #'org-capture) #+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 '( <>)) #+end_src ** 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 [[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, let’s 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. I’m 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 (: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. Let’s 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, it’s 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, 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! #+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 won’t 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-mode’s 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 | | Let’s 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 isn’t a lot of stuff I can jump to yet, but there’s 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, let’s 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 <>) (add-to-list 'org-latex-classes <>))) #+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 <> (setq org-publish-project-alist `(<> <> <>)) #+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/leader-key :packages '(org org-roam) :infix "o" "r" '(:ignore t :which-key "roam") "rb" '(org-mark-ring-goto :which-key "back") "rB" #'org-roam-buffer-toggle "rn" '(:ignore t :which-key "nodes") "rnf" #'org-roam-node-find "rni" #'org-roam-node-insert "rno" #'org-roam-node-open "rnr" #'org-roam-node-random "rnv" #'org-roam-node-visit "rs" '(:ignore t :which-key "sync") "rsa" #'org-roam-db-autosync-mode "rsc" #'org-roam-db-clear-all "rsd" #'org-roam-db-diagnose-node "rss" #'org-roam-db-sync "ru" '(:ignore t :which-key "ui") "rua" #'org-roam-ui-add-to-local-graph "ruo" #'org-roam-ui-open) (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 Daviwil’s]] 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 ** 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-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! #+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 :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. Let’s 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 "" #'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