Find file
Fetching contributors…
Cannot retrieve contributors at this time
813 lines (742 sloc) 30.2 KB

EOS: Org Module

(provide 'eos-org)

Org-mode, The Ultimate Organization Tool

I use org-mode a ton, so it get’s its own page here.

A great lot of this was taken from, to which I owe almost all of the agenda configuration. The capture stuff and regular org settings are mine.

Also, in order to export nicely colored HTML of source code, we need htmlize

(install-pkgs '(htmlize))

First, the hook that gets run every time org-mode is started, to turn on certain modes

(defun eos/org-mode-hook ()
  (when (fboundp 'turn-on-auto-fill)
  (when (fboundp 'turn-on-flyspell)
  (when (fboundp 'yas-minor-mode)
    (yas-minor-mode 1))
  (when (fboundp 'my/enable-abbrev-mode)

  (diminish 'org-indent-mode)
  (diminish 'buffer-face-mode)
  ;; fix some bindings that org-mode overwrites
  (when (fboundp 'eyebrowse-next-window-config)
    (define-key org-mode-map (kbd "C-'") #'eyebrowse-next-window-config))
  (define-key org-mode-map (kbd "C-c C-x C-f") #'org-refile)
  (define-key org-mode-map (kbd "<C-tab>") #'other-window)
  (when (boundp 'org-agenda-mode-map)
    (define-key org-agenda-mode-map (kbd "C-c C-x C-f") #'org-agenda-refile)))

And now the huge org-mode configuration

(use-package org
  ;;  :ensure org-plus-contrib
  :bind (("C-c l" . org-store-link)
         ("C-c a" . org-agenda)
         ("C-c b" . org-iswitchb)
         ("C-c c" . org-capture)
         ("C-c M-p" . org-babel-previous-src-block)
         ("C-c M-n" . org-babel-next-src-block))
  :defer 30
    (use-package org-install)
    (use-package ob-core)
    ;; org-export
    (use-package ox)
    ;; Enable archiving things
    (use-package org-archive)
    (add-hook 'org-mode-hook #'hl-line-mode)
    (add-hook 'org-agenda-mode-hook #'hl-line-mode)
    (add-hook 'org-mode-hook #'eos/org-mode-hook)
    ;; enabled export backends
    ;; (use-package ox-rss)
    (when (boundp 'org-export-backends)
      (custom-set-variables '(org-export-backends '(ascii beamer html latex md))))
    ;; Allow's electric-pair-mode to surround things with = and ~ in org-mode
    (modify-syntax-entry ?~ "(~" org-mode-syntax-table)
    (modify-syntax-entry ?= "(=" org-mode-syntax-table)

    (setq org-directory (file-truename "~/org")
          ;; follow links by pressing ENTER on them
          org-return-follows-link t
          ;; allow changing between todo stats directly by hotkey
          org-use-fast-todo-selection t
          ;; syntax highlight code in source blocks
          org-src-fontify-natively t
          ;; for the leuven theme, fontify the whole heading line
          org-fontify-whole-heading-line t
          ;; force UTF-8
          org-export-coding-system 'utf-8
          ;; don't use ido completion (I use helm)
          org-completion-use-ido nil
          ;; don't start up org files with indentation
          ;; (same as #+STARTUP: noindent)
          org-startup-indented t
          ;; *don't* hide things like = and / for emphasis markers
          org-hide-emphasis-markers nil
          ;; don't indent source code
          org-edit-src-content-indentation 0
          ;; don't adapt indentation
          org-adapt-indentation nil
          ;; preserve the indentation inside of source blocks
          org-src-preserve-indentation t
          ;; Imenu should use 3 depth instead of 2
          org-imenu-depth 3
          ;; Use inline footnotes by default
          org-footnote-define-inline t
          ;; put state change log messages into a drawer
          org-log-into-drawer t
          ;; special begin/end of line to skip tags and stars
          org-special-ctrl-a/e t
          ;; special keys for killing a headline
          org-special-ctrl-k t
          ;; don't adjust subtrees that I copy
          org-yank-adjusted-subtrees nil
          ;; try to be smart when editing hidden things
          org-catch-invisible-edits 'smart
          ;; blank lines are removed when exiting the code edit buffer
          org-src-strip-leading-and-trailing-blank-lines t
          ;; how org-src windows are set up when hitting C-c '
          org-src-window-setup 'current-window
          ;; Overwrite the current window with the agenda
          org-agenda-window-setup 'current-window
          ;; Use 100 chars for the agenda width
          org-agenda-tags-column -100
          ;; Use full outline paths for refile targets - we file directly with IDO
          org-refile-use-outline-path t
          ;; Targets complete directly with IDO
          org-outline-path-complete-in-steps nil
          ;; Allow refile to create parent tasks with confirmation
          org-refile-allow-creating-parent-nodes 'confirm
          ;; leave this many empty lines in collapsed view
          org-cycle-separator-lines 1
          ;; don't run stuff automatically on export
          org-export-babel-evaluate nil
          ;; export tables as CSV instead of tab-delineated
          org-table-export-default-format "orgtbl-to-csv"
          ;; start up showing images
          org-startup-with-inline-images t
          ;; use #+ATTR: if defined, or real width otherwise
          org-image-actual-width nil
          ;; always enable noweb, results as code and exporting both
          (cons '(:noweb . "yes")
                (assq-delete-all :noweb org-babel-default-header-args))
          (cons '(:exports . "both")
                (assq-delete-all :exports org-babel-default-header-args))
          ;; I don't want to be prompted on every code block evaluation
          org-confirm-babel-evaluate nil
          ;; Mark entries as done when archiving
          org-archive-mark-done t
          ;; Where to put headlines when archiving them
          org-archive-location "%s_archive::* Archived Tasks"
          ;; Sorting order for tasks on the agenda
          '((agenda habit-down
            (todo priority-down category-up effort-up)
            (tags priority-down category-up effort-up)
            (search priority-down category-up))
          ;; Enable display of the time grid so we can see the marker for the
          ;; current time
          '((daily today remove-match)
            #("----------------" 0 16 (org-heading t))
            (0900 1100 1300 1500 1700))
          ;; keep the agenda filter until manually removed
          org-agenda-persistent-filter t
          ;; show all occurrences of repeating tasks
          org-agenda-repeating-timestamp-show-all t
          ;; always start the agenda on today
          org-agenda-start-on-weekday nil
          ;; Use sticky agenda's so they persist
          org-agenda-sticky t
          ;; show 4 agenda days
          org-agenda-span 4
          ;; Do not dim blocked tasks
          org-agenda-dim-blocked-tasks nil
          ;; include the diary in the agenda
          org-agenda-include-diary t
          ;; Compact the block agenda view
          org-agenda-compact-blocks t
          ;; Show all agenda dates - even if they are empty
          org-agenda-show-all-dates t
          ;; Change the default column mode display to show clock sum
          org-columns-default-format "%50ITEM(Task) %2PRIORITY %10CLOCKSUM %TAGS"
          ;; Agenda org-mode files
          org-agenda-files `(,(file-truename "~/org/")
                             ,(file-truename "~/org/")
                             ,(file-truename "~/org/")
                             ,(file-truename "~/org/")
                             ,(file-truename "~/org/")
                             ,(file-truename "~/org/")))

    ;; Org todo keywords
    (setq org-todo-keywords
          '((sequence "TODO(t)" "|" "DONE(d)")
            (sequence "TODO(t)"
                      "|" "DONE(d)")
            (sequence "TODO(t)" "INPROGRESS(i)" "|" "CANCELLED(c@/!)")
            (sequence "TODO(t)" "STARTED(s)" "|" "CANCELLED(c@/!)")))
    ;; Org faces
    (setq org-todo-keyword-faces
          '(("TODO" :foreground "red" :weight bold)
            ("MEETING" :foreground "red" :weight bold)
            ("STARTED" :foreground "blue violet" :weight bold)
            ("INPROGRESS" :foreground "deep sky blue" :weight bold)
            ("SOMEDAY" :foreground "purple" :weight bold)
            ("NEEDSREVIEW" :foreground "#edd400" :weight bold)
            ("DONE" :foreground "forest green" :weight bold)
            ("WAITING" :foreground "orange" :weight bold)
            ("HOLD" :foreground "magenta" :weight bold)
            ("CANCELLED" :foreground "forest green" :weight bold)))
    ;; add or remove tags on state change
    (setq org-todo-state-tags-triggers
          '(("CANCELLED" ("CANCELLED" . t))
            ("WAITING" ("WAITING" . t))
            ("HOLD" ("WAITING") ("HOLD" . t))
            (done ("WAITING") ("HOLD"))
            ("TODO" ("WAITING") ("CANCELLED") ("HOLD"))
            ("INPROGRESS" ("WAITING") ("CANCELLED") ("HOLD"))
            ("STARTED" ("WAITING") ("CANCELLED") ("HOLD"))
            ("DONE" ("WAITING") ("CANCELLED") ("HOLD"))))
    ;; refile targets all level 1 and 2 headers in current file and agenda files
    (setq org-refile-targets '((nil :maxlevel . 2)
                               (org-agenda-files :maxlevel . 2)))
    ;; quick access to common tags
    (setq org-tag-alist
          '(("oss" . ?o)
            ("home" . ?h)
            ("work" . ?w)
            ("xpack" . ?x)
            ("book" . ?b)
            ("support" . ?s)
            ("docs" . ?d)
            ("emacs" . ?e)
            ("noexport" . ?n)
            ("recurring" . ?r)))
    ;; capture templates
    (setq org-capture-templates
          '(("t" "Todo" entry (file "~/org/")
             "* TODO %?\n")
            ("m" "Meeting" entry (file+headline "~/org/" "Meetings")
             "* %?\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n")
            ("M" "Email" entry (file "~/org/")
             "* TODO [#B] %?\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n%a\n")
            ("n" "Notes" entry (file+headline "~/org/" "Notes")
             "* %? :NOTE:\n")
            ("e" "Emacs note" entry
             (file+headline "~/org/" "Emacs Links")
             "* %? :NOTE:\n")
            ("j" "Journal" entry (file+datetree "~/org/")
             "* %?\n%U\n")
            ("b" "Book/Bibliography" entry
             (file+headline "~/org/" "Refile")
             "* %?%^{TITLE}p%^{AUTHOR}p%^{TYPE}p")))
    ;; Custom agenda command definitions
    (setq org-agenda-custom-commands
          '(("N" "Notes" tags "NOTE"
             ((org-agenda-overriding-header "Notes")
              (org-tags-match-list-sublevels t)))
            (" " "Agenda"
             ((agenda "" nil)
              ;; All items with the "REFILE" tag, everything in
              ;; automatically gets that applied
              (tags "REFILE"
                    ((org-agenda-overriding-header "Tasks to Refile")
                     (org-tags-match-list-sublevels nil)))
              ;; All "INPROGRESS" todo items
              (todo "INPROGRESS"
                    ((org-agenda-overriding-header "Current work")))
              ;; All "STARTED" todo items
              (todo "STARTED"
                    ((org-agenda-overriding-header "Started tasks")))
              ;; All headings with the "support" tag
              (tags "support/!"
                    ((org-agenda-overriding-header "Support cases")))
              ;; All "NEESREVIEW" todo items
              (todo "NEEDSREVIEW"
                    ((org-agenda-overriding-header "Waiting on reviews")))
              ;; All "WAITING" items without a "support" tag
              (tags "WAITING-support"
                    ((org-agenda-overriding-header "Waiting for something")))
              ;; All TODO items
              (todo "TODO"
                    ((org-agenda-overriding-header "Task list")
                      '(time-up priority-down category-keep))))
              ;; Everything on hold
              (todo "HOLD"
                    ((org-agenda-overriding-header "On-hold")))
              ;; All headings with the "recurring" tag
              (tags "recurring/!"
                    ((org-agenda-overriding-header "Recurring"))))

    ;; Exclude DONE state tasks from refile targets
    (defun eos/verify-refile-target ()
      "Exclude todo keywords with a done state from refile targets"
      (not (member (nth 2 (org-heading-components)) org-done-keywords)))
    (setq org-refile-target-verify-function 'eos/verify-refile-target)

    ;; org-mode bindings
    (define-key org-mode-map (kbd "C-c t") 'org-todo)
    (define-key org-mode-map (kbd "RET") 'org-return-indent)

    ;; org-babel stuff
    (use-package ob-clojure
      :ensure clojure-mode)
    (use-package ob-elasticsearch
      :ensure es-mode)

     '((emacs-lisp . t)
       (elasticsearch . t)
       (clojure . t)
       (dot . t)
       (sh . t)
       (js . t)
       (haskell . t)
       (ruby . t)
       (python . t)
       (gnuplot . t)
       (plantuml . t)
       (ditaa . t)
       (latex . t)))

    ;; this is where Fedora installs it, YMMV
    (setq org-plantuml-jar-path "/usr/share/java/plantuml.jar")

    ;; Use org.css from the :wq website for export document stylesheets
    (setq org-html-head-include-default-style nil)

    ;; ensure this variable is defined
    (unless (boundp 'org-babel-default-header-args:sh)
      (setq org-babel-default-header-args:sh '()))

    ;; add a default shebang header argument shell scripts
    (add-to-list 'org-babel-default-header-args:sh
                 '(:shebang . "#!/usr/bin/env bash"))

    ;; add a default shebang header argument for python
    (add-to-list 'org-babel-default-header-args:python
                 '(:shebang . "#!/usr/bin/env python"))

    (defun eos/org-inline-css-hook (exporter)
      "Insert custom inline css to automatically set the
   background of code to whatever theme I'm using's background"
      (when (eq exporter 'html)
        (let* ((my-pre-bg (face-background 'default))
               (my-pre-fg (face-foreground 'default)))
          ;;(setq org-html-head-include-default-style nil)
             "<style type=\"text/css\">\n pre.src {background-color: %s; color: %s;}</style>\n"
             my-pre-bg my-pre-fg))))))

    ;; Uncomment to automatically set background color to theme background
    ;; (add-hook 'org-export-before-processing-hook #'eos/org-inline-css-hook)

    (use-package org-id
      (setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id)

      (defun eos/org-custom-id-get (&optional pom create prefix)
        "Get the CUSTOM_ID property of the entry at point-or-marker POM.
   If POM is nil, refer to the entry at point. If the entry does
   not have an CUSTOM_ID, the function returns nil. However, when
   CREATE is non nil, create a CUSTOM_ID if none is present
   already. PREFIX will be passed through to `org-id-new'. In any
   case, the CUSTOM_ID of the entry is returned."
        (org-with-point-at pom
          (let ((id (org-entry-get nil "CUSTOM_ID")))
             ((and id (stringp id) (string-match "\\S-" id))
              (setq id (org-id-new (concat prefix "h")))
              (org-entry-put pom "CUSTOM_ID" id)
              (org-id-add-location id (buffer-file-name (buffer-base-buffer)))

      (defun eos/org-add-ids-to-headlines-in-file ()
        "Add CUSTOM_ID properties to all headlines in the current
   file which do not already have one. Only adds ids if the
   `auto-id' option is set to `t' in the file somewhere. ie,
   #+OPTIONS: auto-id:t"
          (goto-char (point-min))
          (when (re-search-forward "^#\\+OPTIONS:.*auto-id:t" (point-max) t)
            (org-map-entries (lambda () (eos/org-custom-id-get (point) 'create))))))

      ;; automatically add ids to saved org-mode headlines
      (add-hook 'org-mode-hook
                (lambda ()
                  (add-hook 'before-save-hook
                            (lambda ()
                              (when (and (eq major-mode 'org-mode)
                                         (eq buffer-read-only nil))

This makes the bullets into fancy Unicode bullets, rather than ASCII ‘*’ values. Depending on the theme, it may look better or worse

(use-package org-bullets
  :ensure t
  (setq org-bullets-bullet-list '("" "" "" "" "" "" ""))
  (add-hook 'org-mode-hook #'org-bullets-mode))

exporting to Github-flavored markdown

By and large, 90% of the exports I do are to Github’s markdown. Usually to share for an issue. So there’s a nice exporter that does this for me: ox-gfm

(use-package ox-gfm
  :ensure t
  (when (boundp 'org-export-backends)
    (customize-set-variable 'org-export-backends
                            (cons 'gfm org-export-backends))))

exporting to tufte html

I wrote a project to do this, but it is not yet available on MELPA.

(if (file-exists-p "~/src/elisp/ox-tufte")
      (add-to-list 'load-path "~/src/elisp/ox-tufte")
      (require 'ox-tufte))
  (use-package ox-tufte
    :ensure t
    :init (require 'ox-tufte)))


Now, my org-mode clocking configuration:

First, a function to use for clocking in

(defun eos/org-clock-in ()
  (org-clock-in '(4)))

(global-set-key (kbd "<f11>") #'eos/org-clock-in)
(global-set-key (kbd "<f12>") #'org-clock-out)
(use-package org
;;  :ensure org-plus-contrib
  :bind (("C-c I" . eos/org-clock-in)
         ("C-c O" . org-clock-out))
  ;; Insinuate it everywhere
  ;; Show lot of clocking history so it's easy to pick items off the C-F11 list
  (setq org-clock-history-length 23
        ;; Resume clocking task on clock-in if the clock is open
        org-clock-in-resume t
        ;; Separate drawers for clocking and logs
        org-drawers '("PROPERTIES" "CLOCK" "LOGBOOK" "RESULTS" "HIDDEN")
        ;; Save clock data and state changes and notes in the LOGBOOK drawer
        org-clock-into-drawer t
        ;; Sometimes I change tasks I'm clocking quickly -
        ;; this removes clocked tasks with 0:00 duration
        org-clock-out-remove-zero-time-clocks t
        ;; Clock out when moving task to a done state
        org-clock-out-when-done t
        ;; Save the running clock and all clock history when exiting Emacs, load it on startup
        org-clock-persist t
        ;; Prompt to resume an active clock
        org-clock-persist-query-resume t
        ;; Enable auto clock resolution for finding open clocks
        org-clock-auto-clock-resolution #'when-no-clock-is-running
        ;; Include current clocking task in clock reports
        org-clock-report-include-clocking-task t
        ;; don't use pretty things for the clocktable
        org-pretty-entities nil
        ;; If idle for more than 5 minutes, resolve the things
        org-clock-idle-time 15
        ;; some default parameters for the clock report
        '(:maxlevel 10 :fileskip0 t :score agenda :block thismonth :compact t :narrow 60)))


Publishing org-mode files to my hosting provider:
(use-package org
;;  (require 'ox-rss)
;;  (require 'ox-icalendar)
  (setq org-publish-project-alist
        `(;; Main website at
           :base-directory ,(file-truename "~/org/writequit/")
           :base-extension "org"
           :publishing-directory "/"
           :publishing-function org-html-publish-to-tufte-html
           :with-toc nil
           :html-preamble t
           "<link rel=\"alternate\" type=\"application/rss+xml\"
                title=\"RSS feed for\">")
           :base-directory ,(file-truename  "~/org/writequit")
           :base-extension "org"
           :publishing-directory "/"
           :publishing-function org-rss-publish-to-rss
           :html-link-home ""
           :exclude ".*"
           :include ("")
           :html-link-use-abs-url t)
           :base-directory ,(file-truename  "~/org/writequit/images")
           :base-extension "png\\|jpg\\|gif"
           :publishing-directory "/"
           :publishing-function org-publish-attachment)
           :base-directory ,(file-truename  "~/org/writequit/files")
           :base-extension "*"
           :publishing-directory "/"
           :publishing-function org-publish-attachment)
          ("writequit" :components ("writequit-org"

          ;; Denver emacs site
           :base-directory ,(file-truename "~/org/denver-emacs-meetup/")
           :base-extension "org\\|html"
           :publishing-function org-html-publish-to-html
           :with-toc nil
           :html-preamble t)

          ;; Org-mode files for ~/.emacs.d/
           :base-directory ,(file-truename "~/.emacs.d/../")
           :base-extension "org\\|html"
           :publishing-function org-html-publish-to-html
           :with-toc t
           :html-preamble t)

          ;; Org-mode files for EOS itself
           :base-directory ,(file-truename "~/eos/")
           :base-extension "org"
           :publishing-function org-html-publish-to-html
           :with-toc t
           :html-preamble t)

          ;; Org-mode files for ~/org files
           :base-directory ,(file-truename "~/org/")
           :base-extension "org\\|html"
           :publishing-function org-html-publish-to-tufte-html
           :with-toc t
           :html-preamble t)
           :base-directory ,(file-truename "~/org/images")
           :base-extension "png\\|jpg"
           :publishing-function org-publish-attachment)
          ("org" :components ("org-org" "org-images"))

          ;; Org-mode for the ~/org/es files
           :base-directory ,(file-truename "~/org/es/")
           :base-extension "org\\|html"
           :publishing-function org-html-publish-to-html
           :with-toc t
           :html-preamble t)
           :base-directory ,(file-truename "~/org/es/")
           :base-extension "css\\|pdf\\|sh\\|es\\|zsh\\|py\\|org"
           :publishing-function org-publish-attachment)
           :base-directory ,(file-truename "~/org/es/images")
           :base-extension "png\\|jpg"
           :publishing-function org-publish-attachment)
           :components ("org-es-org" "org-es-files" "org-es-images"))

          ;; Org-mode for the ~/org/es/design files
           :base-directory ,(file-truename "~/org/es/design")
           :base-extension "org\\|html"
           :publishing-function org-html-publish-to-tufte-html
           :with-toc t
           :html-preamble t)
           :base-directory ,(file-truename "~/org/es/design")
           :base-extension "css\\|pdf\\|sh\\|es\\|zsh\\|py\\|org"
           :publishing-function org-publish-attachment)
           :base-directory ,(file-truename "~/org/es/design/images")
           :base-extension "png\\|jpg"
           :publishing-function org-publish-attachment)
           :components ("org-es-design-org"

          ;; Org-mode for the ~/org/es/presentations files
           :base-directory ,(file-truename "~/org/es/presentations")
           :base-extension "org\\|html"
           :publishing-function org-html-publish-to-html
           :with-toc t
           :html-preamble t)
           :base-directory ,(file-truename "~/org/es/presentations")
           :base-extension "css\\|pdf\\|sh\\|es\\|zsh\\|py\\|org"
           :publishing-function org-publish-attachment)
           :base-directory ,(file-truename "~/org/es/presentations/images")
           :base-extension "png\\|jpg"
           :publishing-function org-publish-attachment)
           :components ("org-es-presentations-org"

Then, when I’m editing ~/org/es/, I can hit C-c C-e P f and export the file to show up in

Tools used from within org-mode

I tend to use quite a few different tools from org buffers, so let’s install the modes required:

(use-package gnuplot
  :ensure t)

(use-package gnuplot-mode
  :ensure t)

Diary, keeping track of appointments in Emacs

(setq diary-file "~/diary")

Presentations in Org-mode

There are a bunch of different ways to present things

Presentations with beamer

Beamer is actually built-into org-mode, but requires a few extra libraries I wanted to document here:

  • texlive
  • texlive-latex
  • texlive-wrapfig
  • texlive-ulem
  • texlive-capt-of
  • texlive-minted
(use-package ox-latex
  (add-to-list 'org-latex-packages-alist '("" "minted" nil))
  (setq org-latex-listings 'minted)
   '("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
     "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
     "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f")))

Presentations with org-present

A simple presentation mode for org-mode

(use-package org-present
;;  :ensure t
  :defer 20
  (add-hook 'org-present-mode-hook
            (lambda ()
  (add-hook 'org-present-mode-quit-hook
            (lambda ()

Presentations with epresent

I’m taking over ownership of this after the last maintainer didn’t touch it for a year, so I load it from a custom path

(if (file-exists-p "~/src/elisp/epresent/")
      (add-to-list 'load-path "~/src/elisp/epresent/")
      (require 'epresent))
  (use-package epresent :ensure t))

Presentations with org-reveal

(if (file-exists-p "~/src/elisp/org-reveal/")
      (add-to-list 'load-path "~/src/elisp/org-reveal/")
      (require 'ox-reveal))
  (use-package ox-reveal :ensure t))