Org-Mode

Org-mode might the emacs killer app. This file holds some extra settings which were not set in the use-package statement in init.el.

TODO General settings

Some general settings for org. Clean up the use-package definition

(use-package org
  :init ; loaded before package is initialized
  ;; The background color of my org source code blocks needs to be defined before
  ;; org is loaded.
  (defface org-block-begin-line
    '((t (:foreground "#99968b" :background "#303030" :box (:style released-button) :extend t)))
    "Face used for the line delimiting the begin of source blocks.")
  (defface org-block-end-line
    '((t (:foreground "#99968b" :background "#303030" :box (:style released-button) :extend t)))
    "Face used for the line delimiting the end of source blocks.")
  :config
  (require 'org-tempo)
  (setq-default
   org-return-follows-link t
   org-image-actual-width '(800)
   org-highlight-latex-and-related '(latex script entities))
  (add-hook 'org-mode-hook #'org-indent-mode)
  (add-hook 'org-mode-hook #'visual-line-mode)
  (add-hook 'org-mode-hook #'flyspell-mode)
  (set-face-attribute 'org-drawer nil
    :inherit 'font-lock-keyword-face)

  ;; change some keys to be a little more like LaTeX
  (defun do.org/insert-math ()
    (interactive)
    (insert "\\(\\)")
    (backward-char 2))

  (defun do.org/insert-today-inactive ()
    "Insert today's date as inactive time stamp."
    (interactive)
    (org-insert-time-stamp (org-current-time) nil t))

  (defun do.org/time-stamp-inactive ()
    "Insert an inactive timestamp of the user's choosing."
    (interactive)
    (org-time-stamp nil t))

  (defalias 'ts #'do.org/time-stamp-inactive)

  ;; non-breaking spaces
  <<do.org/non-breaking-spaces>>

  ;; fix `electric-pair-mode'
  <<do.org/fix-electric-pair>>

  :bind
  (("C-c l" . #'org-store-link)
   ("C-c t" . #'do.org/insert-today-inactive)
   :map org-mode-map
   ("$" . do.org/insert-math)
   ("~" . do.org/insert-nbsp)))

(use-package org-contrib
  :ensure t)

fixing `electric-pair-mode'

(defun do-org/fix-electric-pair ()
  ;; TODO
    )

Syntax highlighting in Code Blocks

Very important if your config file is a .org document… Also, add native <tab> behavior in source blocks.

(setq
 org-src-fontify-natively t
 org-src-tab-acts-natively t)

We also want this in LaTeX output!

(setq org-latex-listings 'minted)

Blogging

Define a small template for new blog posts. Use with <b TAB

February 03 2020 this does not work anymore in org > 9.2…

(add-to-list 'org-structure-template-alist
             '("b" "#+TITLE: ?
#+AUTHOR: Dennis Ogbe
#+EMAIL: [email protected]
#+DATE:
#+STARTUP: showall
#+STARTUP: inlineimages
#+BEGIN_PREVIEW\n\n#+END_PREVIEW\n"))

HTML Export

For HTML output, we want to be able to set a custom stylesheet.

(setq org-html-htmlize-output-type 'css)

We need the htmlize package for that

(use-package htmlize
  :ensure t
  :commands (htmlize-buffer
             htmlize-file
             htmlize-many-files
             htmlize-many-files-dired
             htmlize-region))

The following code reads some CSS and adds it as a string to the HTML header that will be embedded in every .org file that is exported.

When exporting an org-file to my blog, this variable will be overridden and instead I will point to the relevant .css files. For "standalone" HTML files, I want to embed the CSS into the HTML header. The snippet below essentially just sets the variable org-html-head.

(defvar do.org.css/css-header-dir "~/repos/blog/res"
  "Directory containing the org css header files for HTML export.")

(defvar do.org.css/css-header-files '("code.css" "main.css")
  "Filenames of CSS files in `do.org.css/css-header-dir' to be
    included in the HTML export header.")

(let* ((css-dir (let* ((fullpath (file-name-as-directory (expand-file-name do.org.css/css-header-dir))))
                  (if (file-exists-p fullpath)
                           fullpath nil)))
       (css-files do.org.css/css-header-files)
       (csstidy "csstidy")
       (csstidy-args " --template=highest --silent=true"))
  (if (and css-dir (executable-find csstidy))
      (setq org-html-head
            (with-temp-buffer
              (insert "<style type=\"text/css\">\n")
              (dolist (file css-files)
                (let* ((fullpath (concat css-dir file)))
                  (when (file-exists-p fullpath)
                         (insert (shell-command-to-string
                                  (concat csstidy " " fullpath csstidy-args))))))
              (insert "</style>")
              (buffer-string)))
    (message "Org config: Not setting `org-html-head'.")))

org-latex settings

For some reason, explained here, we need to run pdflatex with the -shell-escape flag. This is getting too complicated, so we're just going to run latexmk from org.

(setq org-latex-pdf-process (list "latexmk -pdflatex='pdflatex -interaction nonstopmode' -shell-escape -pdf -bibtex -f %f"))
(setq org-latex-with-hyperref
      "\\hypersetup{
colorlinks=true,
citecolor=red,
filecolor=blue,
linkcolor=red,
urlcolor=blue,
pdfauthor={%a},
pdftitle={%t},
pdfkeywords={%k},
pdfsubject={%d},
pdfcreator={%c},
pdflang={%L}}\n")
(setq org-latex-prefer-user-labels t)

If we want to export to a documentclass other than article, we need to add its structure to the following list. To use that class, we can then put the following in the org-mode file header: #+LATEX_CLASS: <class>. To add options to the class, we add the following: #+LATEX_CLASS_OPTIONS: [op1, op2,...].

(require 'ox-latex)
(add-to-list 'org-latex-classes
             '("IEEEtran"
               "\\documentclass{IEEEtran}"
               ("\\section{%s}" . "\\section*{%s}")
               ("\\subsection{%s}" . "\\subsection*{%s}")
               ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
               ("\\paragraph{%s}" . "\\paragraph*{%s}")))

We add some templates for some common math environments

(add-to-list 'org-structure-template-alist
             '("prop"  "#+begin_proposition ?\n\n#+end_proposition"))
(add-to-list 'org-structure-template-alist
             '("thm"  "#+begin_theorem ?\n\n#+end_theorem"))
(add-to-list 'org-structure-template-alist
             '("lem"  "#+begin_lemma ?\n\n#+end_lemma"))
(add-to-list 'org-structure-template-alist
             '("pf"  "#+begin_proof ?\n\n#+end_proof"))

Non-breaking spaces

Entering "~" in org-mode buffers enters a literal tilde character and not the non-breaking space that I usually want. To get around this, we can insert "non-breaking-space" org entity. Unfortunately, having \nbsp{} littered around org-mode buffers is super ugly, so we use prettify-symbols-mode to correct this eyesore.

This is straightforward, but the default behavior of prettify-symbols-mode does not match occurrences like as\nbsp{}cite:citation, where the space is butting up to other strings on both sides. So we have to fix that too.

(defun do.org/prettify-symbols-compose-predicate (start end _match)
  "Explicitly allow any occurrence of the non-breaking space to be composed."
  (let ((result (prettify-symbols-default-compose-p start end _match)))
    (or result (string-equal (buffer-substring start end) "\\nbsp{}"))))

(defun do.org/prettify-symbols-setup ()
  "Set up `prettify-symbols-mode' for `org-mode' buffers."
  (make-variable-buffer-local 'prettify-symbols-unprettify-at-point)
  (setq prettify-symbols-unprettify-at-point 'right-edge)
  (setq prettify-symbols-compose-predicate #'do.org/prettify-symbols-compose-predicate)
  (setq prettify-symbols-alist `(("\\nbsp{}" . ,(string-to-char "~"))))
  (prettify-symbols-mode 1))

(add-hook 'org-mode-hook #'do.org/prettify-symbols-setup)

(defun do.org/insert-nbsp ()
  "Bind this to the ~ (tilde) character to insert non-breaking
spaces on `org-mode' for LaTeX export."
  (interactive)
  (insert "\\nbsp{}"))

Default Applications

Org opens PDFs by default in gv… change that to evince. Also open HTML in Chrome.

(let ((pdf-reader (if (boundp 'do.minimal/pdf-reader)
                      do.minimal/pdf-reader
                    "evince")))
(setq org-file-apps `((auto-mode . emacs)
                      ("\\.x?html?\\'" . "firefox %s")
                      ("\\.pdf\\'" . ,(concat pdf-reader " \"%s\""))
                      ("\\.pdf::\\([0-9]+\\)\\'" . ,(concat pdf-reader " \"%s\" -p %1"))
                      ("\\.pdf.xoj" . "xournal %s"))))

org-babel

Babel lets the user run code inside an org-mode document. I feel like this can come in handy one day.

Active Babel languages

(org-babel-do-load-languages
 'org-babel-load-languages
 '((python . t)
   (emacs-lisp . t)
   (matlab . t)
   (octave . t)
   (latex . t)
   (js . t)
   (shell . t)
   (C . t)
   (ditaa . t)))

org-babel settings

(setq org-babel-matlab-with-emacs-link nil)
(setq org-confirm-babel-evaluate nil)
(setq org-export-babel-evaluate t)
;;; display/update images in the buffer after I evaluate
(add-hook 'org-babel-after-execute-hook 'org-display-inline-images 'append)

ditaa

Ditaa is a small tool that takes ASCII art and renders it as neat diagrams. Combined with org, I can sketch out ideas directly in an org buffer using the emacs Artist mode.

(setq org-ditaa-jar-path (concat initel-directory "random/ditaa/ditaa0_9.jar"))

Windmove and org-mode clashes

Make windmove (and framemove) play nice with org.

(add-hook 'org-shiftup-final-hook 'windmove-up)
(add-hook 'org-shiftleft-final-hook 'windmove-left)
(add-hook 'org-shiftdown-final-hook 'windmove-down)
(add-hook 'org-shiftright-final-hook 'windmove-right)

YaSnippet and org

backtab is already used in org-mode. Let's use C-<tab> instead.

(define-key org-mode-map (kbd "C-<tab>") 'yas-expand)

org-download

(use-package org-download
  :ensure t
  :init
  (setq org-download-screenshot-method "xclip -selection clipboard -t image/png -o > %s")
  (setq org-download-method 'directory)
  (defalias 'insert-screenshot 'org-download-screenshot)
  :config
  (add-hook 'dired-mode-hook 'org-download-enable))

Execute a code block on startup

Sometimes I want to execute a code block in an org file as soon as it is started. This can be done as follows. We first need the following function.

(defun do.org/execute-startup-block ()
  "Go to the startup block and execute it. It must be named 'do-org-startup-code'."
  (interactive)
  ;; only run this once. some modes (looking at you, org-ref) run
  ;; `hack-local-variables' again. we want our code to be executed only once on
  ;; buffer creation.
  (unless (bound-and-true-p do.org/startup-was-run-p)
    (org-babel-goto-named-src-block "do-org-startup-code")
    (let ((org-babel-after-execute-hook nil))
      (org-babel-execute-src-block))
    (org-global-cycle)
    (setq-local do.org/startup-was-run-p t)))

We can identify the code block to execute on startup by giving it the name do-org-startup-code, i.e., we add a #+NAME: do-org-startup-code in the line before #+begin_src.

Then to execute, we need to set the :eval local variable to call our function, which visits the block and runs it. This might look like this:

FILENAME -*- mode: org; eval: (do.org/execute-startup-block) -*-

or the corresponding multiline comment form at the end of a file.