Arthur Andersen

Emacs.d

Emacs Configuration

Emacs

This document describes my personal emacs configuration.

Many parts I have copied together from various sources. Among others I found these pretty informative and helpful:

General

Personal Information
(setq user-full-name "Arthur Andersen"
      user-mail-address "arthur@andersen.berlin")
Configure ELPA and use-package

First require the package package with the correct package archives.

(require 'package)
melpahttp://melpa.milkbox.net/packages/
elpahttp://elpa.gnu.org/packages/
orghttp://orgmode.org/elpa/
(setq package-archives (mapcar '(lambda (archive)
				    (let ((name (nth 0 archive))
					  (url (nth 1 archive)))
				      `(,name . ,url)))
				 archives))

(package-initialize)

Since everything is based on use-package I refresh package contents if use-package is not installed and afterwards make sure to have it installed and required.

(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(eval-when-compile
  (require 'use-package))
General Dependencies

Some of the dependencies need to be installed.

(add-to-list 'load-path "~/.emacs.d/vendor")

(use-package alert :ensure t)
(use-package markup :ensure t)
(use-package popup :ensure t)
(use-package s :ensure t)
(use-package f :ensure t)
(use-package kv :ensure t)
(use-package ht :ensure t)
(use-package noflet :ensure t)
(use-package bind-key :ensure t)
(use-package which-key
  :ensure t
  :config
  (which-key-mode)
  (which-key-setup-side-window-right-bottom)
  (setq which-key-side-window-location 'left))
Diminish modes
(use-package diminish :ensure t)
(diminish 'auto-fill-function)
(diminish 'auto-revert-mode)
EasyPG

Use GPG encrypted authinfo file. This way we don’t save the credentials in plain text.

(setq auth-sources '((:source "/home/arthur/.authinfo.gpg")))

Functions

Hook Into Modes

A helper to easily hook a given func into multiple modes.

(defmacro leoc/hook-into-modes (func modes)
  "Add FUNC to list of MODES."
  (declare (indent 1))
  `(dolist (mode-hook ,modes)
     (add-hook mode-hook ,func)))

Look and Feel

Some systems behave differently than others…

(defconst *is-mac* (eq system-type 'darwin))
(defconst *is-cocoa-emacs* (and *is-mac* (eq window-system 'ns)))
(defconst *is-linux* (eq system-type 'gnu/linux))
(defconst *is-x11* (eq window-system 'x))
(defconst *is-windows* (eq system-type 'windows-nt))
(setq visible-bell nil
      truncate-partial-width-windows nil)
Minimize UI

Make sure that we do not see a splash screen each time we start Emacs.

(setq inhibit-startup-message t)

Remove the menubar, toolbar and the scrollbar.

(if (fboundp 'menu-bar-mode) (menu-bar-mode -1))
(if (fboundp 'tool-bar-mode) (tool-bar-mode -1))
(if (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))
Use Custom Color Theme

I use my custom theme summered-emacs which is a warm color theme and provides two variants:

  • light on dark
  • dark on light
(add-to-list 'load-path "~/.emacs.d/vendor/summered-theme")
(load (expand-file-name "vendor/summered-theme/summered-dark-theme.el" user-emacs-directory))
(load-theme 'summered-dark t)

This color theme should be enabled globally and with maximum decoration.

(setq color-theme-is-global t
      font-lock-maximum-decoration t)
Use Translucent Background

I like my emacs windows to be a little translucent, so I see my wallpaper to gleam through.

(defun leoc/transparency (value &optional frame)
  "Sets the transparency of the frame window. 0=transparent/100=opaque"
  (interactive "nTransparency Value 0 - 100 opaque:")
  (let ((frame (or frame (selected-frame))))
    (set-frame-parameter frame 'alpha value)))

(defun leoc/set-frame-transparency (&optional frame)
  (leoc/transparency 98 frame))

(add-hook 'after-make-frame-functions 'leoc/set-frame-transparency)
(add-hook 'after-init-hook 'leoc/set-frame-transparency)
Disable Tooltip Mode
(tooltip-mode -1)
Disable Blinking Cursor
(blink-cursor-mode -1)
Zoom Frame Easily

For external monitors it’s always good to be able to quickly change the font size.

(use-package zoom-frm
  :requires zoom-frm
  :bind
  (("C-M-*" . zoom-frm-in)
   ("C-M-_" . zoom-frm-out)))
Empower Mode-Line

Before I used a custom mode-line format, but that is too much work to actually maintain. Powerline is a clean enough custom mode-line, so why not go with it.

(use-package powerline
  :ensure t
  :init
  (setq powerline-default-separator 'wave)

  (defun leoc/powerline-theme ()
    "Setup the default mode-line."
    (interactive)
    (setq-default mode-line-format
		    '("%e"
		      (:eval
		       (let* ((active (powerline-selected-window-active))
			      (mode-line-buffer-id (if active 'mode-line-buffer-id 'mode-line-buffer-id-inactive))
			      (mode-line (if active 'mode-line 'mode-line-inactive))
			      (face1 (if active 'powerline-active1 'powerline-inactive1))
			      (face2 (if active 'powerline-active2 'powerline-inactive2))
			      (separator-left (intern (format "powerline-%s-%s"
							      (powerline-current-separator)
							      (car powerline-default-separator-dir))))
			      (separator-right (intern (format "powerline-%s-%s"
							       (powerline-current-separator)
							       (cdr powerline-default-separator-dir))))
			      (lhs (list (powerline-raw "%*" mode-line 'l)
					 (powerline-raw " " mode-line)
					 (funcall separator-left mode-line face2)
					 (powerline-raw "%l" face2 'l)
					 (powerline-raw ":" face2)
					 (powerline-raw "%c" face2 'r)
					 (funcall separator-left face2 mode-line)
					 ;; (when powerline-display-mule-info
					 ;; 	 (powerline-raw mode-line-mule-info mode-line 'l))
					 (powerline-buffer-id mode-line-buffer-id)
					 (when (and (boundp 'which-func-mode) which-func-mode)
					   (powerline-raw which-func-format nil 'l))
					 (powerline-raw " ")
					 (funcall separator-left mode-line face1)
					 (when (and (boundp 'erc-track-minor-mode) erc-track-minor-mode)
					   (powerline-raw erc-modified-channels-object face1 'l))
					 (powerline-major-mode face1 'l)
					 (powerline-process face1)
					 (powerline-minor-modes face1 'l)
					 (powerline-narrow face1 'l)
					 (powerline-raw " " face1)
					 (funcall separator-left face1 face2)
					 (powerline-vc face2 'r)
					 (when (bound-and-true-p nyan-mode)
					   (powerline-raw (list (nyan-create)) face2 'l))))
			      (rhs (list (powerline-raw global-mode-string face2 'r)
					 (funcall separator-right face2 face1)
					 (unless window-system
					   (powerline-raw (char-to-string #xe0a1) face1 'l))
					 (when powerline-display-buffer-size
					   (powerline-buffer-size face1 'l))
					 (powerline-raw " " face1)
					 (funcall separator-right face1 mode-line)
					 (powerline-raw " ")
					 (powerline-raw "%6p" mode-line 'r)
					 (when powerline-display-hud
					   (powerline-hud face2 face1)))))
			 (concat (powerline-render lhs)
				 (powerline-fill face2 (powerline-width rhs))
				 (powerline-render rhs)))))))

  (leoc/powerline-theme)
  )

Browse Url

I am using chromium as web browser.

(setq browse-url-browser-function 'browse-url-generic
      browse-url-generic-program "chromium")

Editor

Single character response to yes or no questions is much faster:

(defalias 'yes-or-no-p 'y-or-n-p)

Transparently open compressed files:

(auto-compression-mode t)

Show keystrokes in progress:

(setq echo-keystrokes 0.1)

Allow pasting selection outside of Emacs.

(setq x-select-enable-clipboard t)

Show active region.

(transient-mark-mode 1)
(make-variable-buffer-local 'transient-mark-mode)
(put 'transient-mark-mode 'permanent-local t)
(setq-default transient-mark-mode t)

Remove text in active region if inserting text.

(delete-selection-mode 1)

Always display line and column numbers.

(setq line-number-mode t)
(setq column-number-mode t)

Lines should be 80 characters wide, not 72.

(setq fill-column 80)

Easily navigate sillycased words.

(use-package subword-mode
  :defer t
  :init (add-hook 'prog-mode-hook 'subword-mode))

(with-eval-after-load 'subword
  (diminish 'subword-mode))

Make sure there is a newline in the end of each file.

(setq require-final-newline t)

Improve emacs cursor movement speed.

(setq auto-window-vscroll t)
Case Handling
(defun leoc/capitalize-dwim ()
  (interactive)
  (if (region-active-p)
      (save-excursion (capitalize-region (region-beginning) (region-end)))
    (capitalize-word 1)))

(defun leoc/upcase-dwim ()
  (interactive)
  (if (region-active-p)
      (save-excursion (upcase-region (region-beginning) (region-end)))
    (upcase-word 1)))

(defun leoc/downcase-dwim ()
  (interactive)
  (if (region-active-p)
      (save-excursion (downcase-region (region-beginning) (region-end)))
    (downcase-word 1)))

(bind-key "M-S-l" 'leoc/downcase-dwim)
(bind-key "M-S-u" 'leoc/upcase-dwim)
(bind-key "M-S-c" 'leoc/capitalize-dwim)
Align by Regular Expression

Sometimes I want to align multiple lines by a certain character, string or regular expression. The function align-regexp comes in handy here. I simply mark a region, hit C-x a type the string I want to be aligned et voila!

(global-set-key (kbd "C-x a") 'align-regexp)
Move Line
(defun leoc/move-line-up ()
  "Move up the current line."
  (interactive)
  (transpose-lines 1)
  (previous-line 2))

(defun leoc/move-line-down ()
  "Move down the current line."
  (interactive)
  (next-line 1)
  (transpose-lines 1)
  (previous-line 1))
Duplicate Line or Region
(defun leoc/duplicate-current-line-or-region (arg)
  "Duplicates the current line or region ARG times.
If there's no region, the current line will be duplicated."
  (interactive "p")
  (save-excursion
    (if (region-active-p)
        (leoc/duplicate-region arg)
      (leoc/duplicate-current-line arg))))

(defun leoc/duplicate-region (num &optional start end)
  "Duplicates the region bounded by START and END NUM times.
If no START and END is provided, the current region-beginning and
region-end is used. Adds the duplicated text to the kill ring."
  (interactive "p")
  (let* ((start (or start (region-beginning)))
         (end (or end (region-end)))
         (region (buffer-substring start end)))
    (kill-ring-save start end)
    (goto-char start)
    (dotimes (i num)
      (insert region))))

(defun leoc/duplicate-current-line (num)
  "Duplicate the current line NUM times."
  (interactive "p")
  (when (eq (point-at-eol) (point-max))
    (goto-char (point-max))
    (newline)
    (forward-char -1))
  (leoc/duplicate-region num (point-at-bol) (1+ (point-at-eol))))

(bind-key "C-c d" 'leoc/duplicate-current-line-or-region)
New Line Above, Below and Beyond
(defun leoc/open-line-below ()
  (interactive)
  (end-of-line)
  (newline)
  (indent-for-tab-command))

(defun leoc/open-line-above ()
  (interactive)
  (beginning-of-line)
  (newline)
  (forward-line -1)
  (indent-for-tab-command))

(bind-key "C-o" 'leoc/open-line-below)
(bind-key "M-o" 'leoc/open-line-above)
Toggle Quotes
(global-set-key (kbd "C-z") 'toggle-quotes)
(defun current-quotes-char ()
  (nth 3 (syntax-ppss)))

(defalias 'point-is-in-string-p 'current-quotes-char)

(defun move-point-forward-out-of-string ()
  (while (point-is-in-string-p) (forward-char)))

(defun move-point-backward-out-of-string ()
  (while (point-is-in-string-p) (backward-char)))

(defun alternate-quotes-char ()
  (if (eq ?' (current-quotes-char)) ?\" ?'))

(defun toggle-quotes ()
  (interactive)
  (if (point-is-in-string-p)
      (let ((old-quotes (char-to-string (current-quotes-char)))
            (new-quotes (char-to-string (alternate-quotes-char)))
            (start (make-marker))
            (end (make-marker)))
        (save-excursion
          (move-point-forward-out-of-string)
          (backward-delete-char 1)
          (set-marker end (point))
          (insert new-quotes)
          (move-point-backward-out-of-string)
          (delete-char 1)
          (insert new-quotes)
          (set-marker start (point))
          (replace-string new-quotes (concat "\\" new-quotes) nil start end)
          (replace-string (concat "\\" old-quotes) old-quotes nil start end)))
    (error "Point isn't in a string")))
Sentence Ending

Sentences do not need double spaces to end.

(set-default 'sentence-end-double-space nil)
Hardcore Emacs

Some features should be disabled to promote other use of functionality. For instance:

Disable marking regions with Shift:

(setq shift-select-mode nil)

Unset unholy keys.

(global-unset-key [up])
(global-unset-key [down])
(global-unset-key [left])
(global-unset-key [right])
(global-unset-key [M-left])
(global-unset-key [M-right])
Auto-Refresh

Auto-refresh buffers.

(global-auto-revert-mode 1)

Also auto-refresh dired, but be quiet about it.

(setq global-auto-revert-non-file-buffers t)
(setq auto-revert-verbose nil)
Backup Files
(defvar backups-dir (expand-file-name "backups" user-emacs-directory)
  "Specifies the directory to save backups in.")
(setq backup-directory-alist `((".*" . ,backups-dir)))
(unless (file-exists-p backups-dir)
  (make-directory backups-dir t))
(setq make-backup-files t               ; backup of a file the first time it is saved.
      backup-by-copying t               ; don't clobber symlinks
      version-control t                 ; version numbers for backup files
      delete-old-versions t             ; delete excess backup files silently
      delete-by-moving-to-trash t
      kept-old-versions 6               ; oldest versions to keep when a new numbered backup is made (default: 2)
      kept-new-versions 9               ; newest versions to keep when a new numbered backup is made (default: 2)
      )
Auto Save

Write auto-save files to custom directory.

(defvar auto-saves-dir (expand-file-name "auto-saves" user-emacs-directory)
  "Specifies the directory to save auto-saves in.")
(unless (file-exists-p auto-saves-dir)
  (make-directory auto-saves-dir t))
(setq auto-save-file-name-transforms `((".*" ,auto-saves-dir t))
      auto-save-default t     ; auto-save every buffer that visits a file
      auto-save-timeout 20    ; number of seconds idle time before auto-save (default: 30)
      auto-save-interval 200  ; number of keystrokes between auto-saves (default: 300)
      )
Temporary Files

Change the temporary file directory.

(defvar tmp-dir (expand-file-name "tmp" user-emacs-directory)
  "Specifies the temp directory.")
(unless (file-exists-p tmp-dir)
  (make-directory tmp-dir t))
(setq temporary-file-directory tmp-dir)
Set Coding System to UTF-8
(set-language-environment 'utf-8)
(set-default-coding-systems 'utf-8)
(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
Bookmarks

Write bookmarks to specific file.

(setq bookmark-default-file (concat user-emacs-directory "bookmarks")
      bookmark-save-flag 1)
Smooth Scrolling
Save History
(setq history-length 1000)
(use-package savehist
  :init (savehist-mode)
  :config
  (progn
    (savehist-mode t)
    (setq savehist-additional-variables '(search ring regexp-search-ring)
          savehist-autosave-interval 60
          savehist-save-minibuffer-history t)))
Recent File
(use-package recentf
  :defer t
  :init (recentf-mode)
  :config
  (setq recentf-max-saved-items 200
        recentf-auto-cleanup 300
        recentf-exclude (list "/\\.git/.*\\'" ; Git contents
                              "/elpa/.*\\'"   ; Package files
                              ".*\\.gz\\'"
                              "TAGS"
                              ".*-autoloads\\.el\\'"
                              "ido.last")))
Uniquify Buffer Names
(use-package uniquify
  :config
  (setq uniquify-buffer-name-style 'forward
        uniquify-separator "/"
        uniquify-after-kill-buffer-p t
        uniquify-ignore-buffers-re "^\\*"))
Ediff
(setq ediff-diff-options "-w"
      ediff-split-window-function 'split-window-horizontally
      ediff-window-setup-function 'ediff-setup-windows-plain)
Whitespace

Whitespace should be visible immediately. The whitespace package helps displaying whitespace.

(use-package whitespace
  :diminish whitespace-mode
  :bind ("C-c T w" . whitespace-mode)
  :init (leoc/hook-into-modes #'whitespace-mode '(prog-mode-hook))
  :config
  (setq whitespace-style '(face
                           lines-tail
                           tabs
                           tab-mark
                           empty
                           trailing)
        whitespace-global-modes '(not go-mode)))

Also whitespace should be cleaned up automatically. To make sure, we are not needlessly cleaning up whitespace in other peoples messed up files, whitespace cleanup mode should only be activated, when the file was initially clean.

(use-package whitespace-cleanup-mode
  :ensure t
  :diminish whitespace-cleanup-mode
  :bind (("C-c T W" . whitespace-cleanup-mode)
         ("C-c e w" . whitespace-cleanup))
  :init (leoc/hook-into-modes #'whitespace-cleanup-mode
          '(prog-mode-hook text-mode-hook))
  :config
  (progn
    (setq whitespace-cleanup-mode-only-if-initially-clean t)
    (add-to-list 'whitespace-cleanup-mode-ignore-modes 'go-mode)))
Auto-Save Buffer

When switching windows, file buffers should be saved automatically.

(defadvice switch-to-buffer (before save-buffer-now activate)
  (when buffer-file-name (save-buffer)))
(defadvice other-window (before other-window-now activate)
  (when buffer-file-name (save-buffer)))
Browse Kill Ring
(use-package browse-kill-ring
  :disabled t
  :ensure t
  :bind ("M-C-y" . browse-kill-ring)
  :config
  (setq browse-kill-ring-show-preview nil
        browse-kill-ring-quit-action 'save-and-restore))
Ibuffer
(use-package ibuffer
  :bind ([remap list-buffers] . ibuffer)
  :init (add-hook 'ibuffer-mode-hook 'ibuffer-auto-mode)
  :config
  (progn
    (use-package ibuf-ext
      :config (setq ibuffer-show-empty-filter-groups nil))))

(use-package ibuffer-projectile
  :ensure t
  :defer t
  :init (with-eval-after-load 'ibuffer
          (defun leoc/ibuffer-group-buffers ()
            (setq ibuffer-filter-groups
                  (append
                   '(("IRC" (mode . erc-mode))
                     ("Help" (or (name . "\\*Help\\*")
                                 (name . "\\*Apropos\\*")
                                 (name . "\\*info\\*")))
                     ("Emacs" (or (name . "^\\*scratch\\*$")
                                  (name . "^\\*Messages\\*$")
                                  (name . "^\\*Completions\\*$")
                                  (name . "^\\*Backtrace\\*$")
                                  (mode . inferior-emacs-lisp-mode)))
                     ("root" (filename . "^/sudo:root.*"))
                     ("Org" (mode . org-mode)))
                   (ibuffer-projectile-generate-filter-groups)))
            (unless (eq ibuffer-sorting-mode 'filename/process)
              (ibuffer-do-sort-by-filename/process)))
          (add-hook 'ibuffer-hook
                    #'leoc/ibuffer-group-buffers)))
Yank Indent Mode
(defvar yank-indent-modes '(LaTeX-mode
                            TeX-mode
                            c++-mode
                            c-mode
                            cperl-mode
                            css-mode
                            emacs-lisp-mode
                            java-mode
                            jde-mode
                            js2-mode
                            ruby-mode
                            lisp-interaction-mode
                            perl-mode
                            prog-mode
                            sql-mode
                            tcl-mode)
  "Modes in which to indent regions that are yanked (or yank-popped)")

(defvar yank-indent-ignore-modes '(coffee-mode)
  "Modes in which not to indent regions that are yanked (or yank-popped)")

(defvar yank-advised-indent-threshold 1000
  "Threshold (# chars) over which indentation does not automatically occur.")

(defun yank-advised-indent-function (beg end)
  "Do indentation, as long as the region isn't too large."
  (if (<= (- end beg) yank-advised-indent-threshold)
      (indent-region beg end nil)))

(defadvice yank (after yank-indent activate)
  "If current mode is one of 'yank-indent-modes, indent yanked text (with prefix arg don't indent)."
  (if (and (not (ad-get-arg 0))
           (member major-mode yank-indent-modes)
           (not (member major-mode yank-indent-ignore-modes)))
      (let ((transient-mark-mode nil))
        (yank-advised-indent-function (region-beginning) (region-end)))))

(defadvice yank-pop (after yank-pop-indent activate)
  "If current mode is one of 'yank-indent-modes, indent yanked text (with prefix arg don't indent)."
  (if (and (not (ad-get-arg 0))
           (member major-mode yank-indent-modes)
           (not (member major-mode yank-indent-ignore-modes)))
      (let ((transient-mark-mode nil))
        (yank-advised-indent-function (region-beginning) (region-end)))))

(defun yank-unindented ()
  (interactive)
  (yank t))

Packages

Flycheck
(use-package flycheck
  :ensure t
  :bind ("C-c l e" . list-flycheck-errors)
  :commands (flycheck-get-checker-for-buffer
             flycheck-may-enable-mode)
  :init
  (add-hook 'after-init-hook #'global-flycheck-mode)
  :config
  (progn
    (defun leoc/flycheck-mode-on-safe ()
      (when (and (flycheck-may-enable-mode)
                 (flycheck-get-checker-for-buffer))
        (flycheck-mode)))
    (advice-add 'flycheck-mode-on-safe :override
                #'leoc/flycheck-mode-on-safe)))
Git

The best Git interface I have seen so far is Magit.

(use-package magit
  :ensure t
  :bind
  (("C-x g" . magit-status)
   :map magit-status-mode-map
   ("C-x C-k" . leoc/magit-kill-file-on-line)
   ("q" . leoc/magit-quit-session)
   ("W" . leoc/magit-toggle-whitespace))
  :config
  (progn
    (setq magit-auto-revert-mode nil)

    (defadvice magit-status (around magit-fullscreen activate)
      (unless (get-register :magit-fullscreen)
        (window-configuration-to-register :magit-fullscreen))
      ad-do-it
      (delete-other-windows))

    (defun leoc/magit-kill-file-on-line ()
      "Show file on current magit line and prompt for deletion."
      (interactive)
      (magit-visit-item)
      (delete-current-buffer-file)
      (magit-refresh))

    (defun leoc/magit-quit-session ()
      "Restores the previous window configuration and kills the magit buffer"
      (interactive)
      (kill-buffer)
      (jump-to-register :magit-fullscreen)
      (set-register :magit-fullscreen nil))

    (defun leoc/magit-toggle-whitespace ()
      (interactive)
      (if (member "-w" magit-diff-options)
          (leoc/magit-dont-ignore-whitespace)
        (leoc/magit-ignore-whitespace)))

    (defun leoc/magit-ignore-whitespace ()
      (interactive)
      (add-to-list 'magit-diff-options "-w")
      (magit-refresh))

    (defun leoc/magit-dont-ignore-whitespace ()
      (interactive)
      (setq magit-diff-options (remove "-w" magit-diff-options))
      (magit-refresh))))

The only things left are some modes to edit git-specific files.

(use-package gitconfig-mode :ensure t)
(use-package gitignore-mode :ensure t)
(use-package git-commit :ensure t)
(use-package git-timemachine
  :ensure t
  :bind ("C-c v t" . git-timemachine-toggle))

To have inline information about not committed changes I use diff-hl.

(use-package diff-hl
  :ensure t
  :defer t
  :init
  (progn
    (add-hook 'prog-mode-hook 'diff-hl-mode)
    (add-hook 'dired-mode-hook 'diff-hl-dired-mode)))
Gist
(use-package yagist
  :ensure t
  :bind(("C-c G c" . yagist-region-or-buffer)
        ("C-c G p" . yagist-region-or-buffer-private)
        ("C-c G l" . yagist-list))
  :config (setq yagist-view-gist t))

Editing

Show Parenthesis

Highlight matching parentheses when the point is on them.

(show-paren-mode 1)
Spell-Checking with FlySpell
(use-package flyspell
  :defer t
  :bind (:map flyspell-mode-map
              ("M-\t" . nil)
              ("C-:" . flyspell-auto-correct-word)
              ("C-." . ispell-word))
  :config
  (progn
    (defun leoc/flyspell-switch-dictionary ()
      (interactive)
      (let* ((dic ispell-current-dictionary)
             (change (if (string= dic "deutsch8") "english" "deutsch8")))
        (ispell-change-dictionary change)
        (message "Dictionary switched from %s to %s" dic change)))

    (setq flyspell-use-meta-tab nil
          flyspell-issue-welcome-flag nil
          flyspell-issue-message-flag nil)))
Edit File as Super User
(defun sudo-edit (&optional arg)
  (interactive "p")
  (if (or arg (not buffer-file-name))
      (find-file (concat "/sudo:root@localhost:" (ido-read-file-name "File: ")))
    (find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name))))
Multiple Cursors
(use-package multiple-cursors
  :ensure t
  :demand t
  :config
  (bind-key* "M-n" 'mc/mark-next-like-this)
  (bind-key* "M-p" 'mc/mark-previous-like-this)
  (bind-key* "C-x C-m" 'mc/mark-all-dwim)
  (bind-key* "C-c b i" 'mc/insert-numbers)
  (bind-key* "C-c b h" 'mc-hide-unmatched-lines-mode)
  (bind-key* "C-c b a" 'mc/mark-all-like-this)
  (bind-key* "C-c b d" 'mc/mark-all-symbols-like-this-in-defun)
  (bind-key* "C-c b r" 'mc/reverse-regions)
  (bind-key* "C-c b s" 'mc/sort-regions)
  (bind-key* "C-c b l" 'mc/edit-lines)
  (bind-key* "C-c b C-a" 'mc/edit-beginnings-of-lines)
  (bind-key* "C-c b C-e" 'mc/edit-ends-of-lines))
Expand Region
(use-package expand-region
  :ensure t
  :bind (("C-=" . er/expand-region)
         ("C-M-m" . er/expand-region)))
Remote Files via Tramp

Tramp is a package that comes with Emacs and allows working with remote files and remote directories.

(use-package tramp
  :defer t
  :config
  (progn
    (setq my-tramp-ssh-completions
          '((tramp-parse-sconfig "~/.ssh/config")))

    (setq tramp-backup-directory-alist backup-directory-alist
          tramp-auto-save-directory (locate-user-emacs-file "tramp-auto-save"))
    (setq tramp-default-proxies-alist
          '(("thujone" "root" "/sshx:arthur@thujone:")
            ((regexp-quote (system-name)) nil nil)
            (nil "\\`root\\'" "/ssh:%h:")))))
Very Large Files
(use-package vlf
  :ensure t
  :config
  (progn
    (require 'vlf-setup)
    (setq vlf-application 'dont-ask)))
Isearch with Regular Expressiond by Default
(bind-key "C-s" 'isearch-forward-regexp)
(bind-key "C-r" 'isearch-backward-regexp)
(bind-key "C-M-s" 'isearch-forward)
(bind-key "C-M-r" 'isearch-backward)
Indent Region or Buffer
(defun indent-buffer ()
  (interactive)
  (indent-region (point-min) (point-max)))

(defun indent-region-or-buffer ()
  "Indents a region if selected, otherwise the whole buffer."
  (interactive)
  (save-excursion
    (if (region-active-p)
        (progn
          (indent-region (region-beginning) (region-end))
          (message "Indented selected region."))
      (progn
        (indent-buffer)
        (message "Indented buffer.")))))
Easily Build RegExps with re-builder
(use-package re-builder
  :ensure t
  :defer t
  :config
  (progn
    (setq reb-re-syntax 'string)))
Speed Things Up With Snippets
(use-package yasnippet
  :ensure t
  :defer t
  :mode ("\\.yasnippet$" . yasnippet-mode)
  :diminish yas-minor-mode
  :init
  (yas-global-mode 1)
  :config
  (progn
    (setq yas-verbosity 0
          yas/snippet-dirs `(,(expand-file-name "snippets" user-emacs-directory))
          yas/expand-only-for-last-commands '(self-insert-command yas/exit-all-snippets yas/abort-snippet yas/skip-and-clear-or-delete-char yas/next-field-or-maybe-expand)
          ;; No dropdowns please, yas
          yas/prompt-functions '(yas/ido-prompt yas/completing-prompt)
          ;; Wrap around region
          yas/wrap-around-region t)

    (defun yas/goto-end-of-active-field ()
      (interactive)
      (let* ((snippet (car (yas/snippets-at-point)))
             (position (yas/field-end (yas/snippet-active-field snippet))))
        (if (= (point) position)
            (move-end-of-line)
          (goto-char position))))

    (defun yas/goto-start-of-active-field ()
      (interactive)
      (let* ((snippet (car (yas/snippets-at-point)))
             (position (yas/field-start (yas/snippet-active-field snippet))))
        (if (= (point) position)
            (move-beginning-of-line)
          (goto-char position))))

    (define-key yas/keymap (kbd "C-e") 'yas/goto-end-of-active-field)
    (define-key yas/keymap (kbd "C-a") 'yas/goto-start-of-active-field)
    (define-key yas/keymap (kbd "<return>") 'yas/exit-all-snippets)))
Auto Completion
(use-package company
  :ensure t
  :demand t
  :diminish company-mode
  :bind (("C-<tab>" . company-complete)
         :map company-active-map
         ("C-n" . company-select-next)
         ("C-p" . company-select-previous)
         ("<tab>" . company-complete-selection)
         ("C-j" . company-complete-selection))
  :config
  (progn
    (add-hook 'prog-mode-hook 'company-mode)

    (setq company-idle-delay 0.5
          company-tooltip-limit 10
          company-minimum-prefix-length 2
          company-show-numbers t
          company-global-modes '(not magit-status-mode))

    (use-package company-dabbrev
      :config
      (setq company-dabbrev-downcase nil))

    (use-package company-quickhelp
      :ensure t
      :init
      (with-eval-after-load 'company
        (company-quickhelp-mode)))))
Be Smart About Parenthesis Pairs
(use-package smartparens
  :ensure t
  :config
  (smartparens-global-mode))

Navigation

Switching Buffers Back And Forth
(bind-key "C-S-<left>" 'previous-buffer)
(bind-key "C-S-<right>" 'next-buffer)
Switching Windows Back And Forth
(bind-key "C-x O" '(lambda () (interactive) (other-window -1)))
(bind-key "C-x C-o" '(lambda () (interactive) (other-window 2)))
File Navigation with Dired

Dired helps me using this beautiful files I love so dearly.

(use-package dired
  :bind (("C-x C-j" . dired-jump)
         ("C-x 4 C-j" . dired-jump-other-window)
         :map dired-mode-map
         ("C-x C-k" . dired-do-delete)
         ("C-o" . leoc/dired-open-externally)
         ("C-c C-o" . dired-omit-mode))
  :config
  (progn
    (require 'dired-x)

    (setq dired-omit-verbose nil)

    (defun leoc/dired-open-externally ()
      (interactive)
      (let* ((file-list (dired-get-marked-files))
             (proceed-p (if (<= (length file-list) 5)
                            t
                          (y-or-n-p "Open more than 5 files?"))))
        (when proceed-p
          (cond
           (*is-windows*
            (mapc (lambda (file-path)
                    (w32-shell-execute "open" (replace-regexp-in-string "/" "\\" file-path t t)))
                  file-list))
           (*is-mac*
            (mapc (lambda (file-path)
                    (shell-command (format "open \"%s\"" file-path)))
                  file-list))
           (*is-linux*
            (mapc (lambda (file-path)
                    (let (process-connection-type)
                      (start-process "" nil "xdg-open" file-path)))
                  file-list))))))

    (setq dired-auto-revert-buffer t
          dired-listing-switches "-alhF --group-directories-first -v"
          dired-omit-files "^\\.[^.].*$")

    (dolist (fun '(dired-do-rename
                   dired-create-directory
                   wdired-abort-changes))
      (eval `(defadvice ,fun (after revert-buffer activate)
               (revert-buffer))))

    (defun leoc/dired-mode-defaults ()
      "Configure the dired-mode buffer accordingly."
      (dired-omit-mode 1)
      (dired-hide-details-mode)
      (diff-hl-dired-mode))
    (add-hook 'dired-mode-hook 'leoc/dired-mode-defaults)))

Emacs provides transparent archive support out of the box, but dired-atool gives flexible tools to pack and unpack archives.

(use-package dired-atool
  :ensure t
  :init
  (dired-atool-setup)
  :bind (:map dired-mode-map
              ("z" . dired-atool-do-unpack)
              ("Z" . dired-atool-do-pack)))
Streamline Popup Windows

Popwin helps to control all those secondary windows and buffers that pop up while using those various modes we love so dearly. You can define special display configurations based on the buffers name that pops up.

(use-package popwin
  :ensure t
  :config
  (progn
    (popwin-mode)
    (bind-key "C-z" popwin:keymap)

    (defun leoc/get-popwin-height (&optional size)
      (let* ((default-values (cond ((>= (display-pixel-height) 1000) '(30 20 15))
                                   ((and (< (display-pixel-height) 1000)
                                         (>= (display-pixel-height) 900)) '(25 20 15))
                                   ((< (display-pixel-height) 900) '(20 15 10)))))
        (cond ((eq size 'small) (nth 2 default-values))
              ((eq size 'medium) (nth 1 default-values))
              (:else (nth 0 default-values)))))

    (setq popwin:special-display-config
          `((help-mode :height ,(leoc/get-popwin-height) :stick t)
            ("*Completions*" :noselect t)
            ("*compilation*" :noselect t :height ,(leoc/get-popwin-height))
            ("*Messages*")
            ("*Occur*" :noselect t)
            ("\\*helm.*" :noselect nil :regexp t  :height ,(leoc/get-popwin-height 'big))
            ("\\*Slime Description.*" :noselect t :regexp t :height ,(leoc/get-popwin-height))
            ("*magit-commit*" :noselect t :height ,(leoc/get-popwin-height) :width 80 :stick t)
            ("COMMIT_EDITMSG" :noselect t :height ,(leoc/get-popwin-height) :width 80 :stick t)
            ("*magit-diff*" :noselect t :height ,(leoc/get-popwin-height) :width 80)
            ("*magit-edit-log*" :noselect t :height ,(leoc/get-popwin-height 'small) :width 80)
            ("*magit-process*" :noselect t :height ,(leoc/get-popwin-height 'small) :width 80)
            ("\\*Slime Inspector.*" :regexp t :height ,(leoc/get-popwin-height))
            ("*Ido Completions*" :noselect t :height ,(leoc/get-popwin-height))
            ("\\*ansi-term\\*.*" :regexp t :height ,(leoc/get-popwin-height))
            ("*shell*" :height ,(leoc/get-popwin-height))
            (".*overtone.log" :regexp t :height ,(leoc/get-popwin-height))
            ("*gists*" :height ,(leoc/get-popwin-height))
            ("*sldb.*":regexp t :height ,(leoc/get-popwin-height))
            ("*Gofmt Errors*" :noselect t)
            ("\\*godoc" :regexp t :height ,(leoc/get-popwin-height))
            ("*Shell Command Output*" :noselect t)
            ("*cider-doc*" :height ,(leoc/get-popwin-height 'medium) :stick t)
            ("\\*cider-repl " :regexp t :height ,(leoc/get-popwin-height 'medium) :stick t)
            ("*Kill Ring*" :height ,(leoc/get-popwin-height))
            ("*project-status*" :noselect t)
            ("*pytest*" :noselect t)
            ("*Python*" :stick t)
            ("*Python Doc*" :noselect t)
            ("*jedi:doc*" :noselect t)
            ("*Registers*" :noselect t)
            ("*ielm*" :stick t)
            ("*Flycheck errors*" :stick t :noselect t)
            ("*processing-compilation*" :noselect t)
            ("*anaconda-doc*" :noselect t)
            ("*company-documentation*" :noselect t :height ,(leoc/get-popwin-height 'small))
            ("*wclock*" :noselect t :height ,(leoc/get-popwin-height 'small))
            ("*cscope*" :height ,(leoc/get-popwin-height 'medium))
            ("*xref*" :height ,(leoc/get-popwin-height 'medium))))))
Handle Projects with Projectile
(use-package projectile
  :ensure t
  :demand t
  :init
  (projectile-global-mode)
  :diminish projectile-mode
  :config
  (setq projectile-remember-window-configs t
        projectile-switch-project-action 'projectile-dired
        projectile-indexing-method 'git
        projectile-completion-system 'ido))
Helm
Find Occurences via Helm Swoop
(use-package helm-swoop
  :ensure t
  :bind (("C-c h o" . helm-swoop)))
Go To Symbol in File
(use-package helm-imenu
  :ensure helm
  :bind (("C-c h i" . helm-imenu)))
Find Files via locate
(use-package helm-locate
  :ensure helm
  :bind (("C-c h l" . helm-locate)))
Find Documentation Entries via Helm
(use-package helm-dash
  :ensure t)
Find Files in Project

With helm we can find files within our projectile projects.

(use-package helm-projectile
   :defer t
   :ensure t
   :demand t
   :init
   (progn
     (define-key projectile-command-map (kbd "g") #'helm-projectile-grep)
     (define-key projectile-command-map (kbd "s") #'helm-projectile-ag)))
Grep Through Files with ag
(use-package helm-ag :ensure t)
Improved Completing Read with Ido

The package ido (Interactively Do Things) provides better completing reads, showing candidates interactively.

(use-package ido
  :demand t
  :config
  (progn
    (ido-mode 1)
    (ido-everywhere 1)

    (setq ido-enable-prefix nil
          ido-enable-flex-matching t
          ido-case-fold nil
          ido-create-new-buffer 'always
          ido-auto-merge-work-directories-length -1
          ido-max-prospects 10
          ido-use-filename-at-point nil
          ido-default-file-method 'selected-window
          ido-max-directory-size 100000)
    (set-default 'imenu-auto-rescan t)

    (add-hook 'ido-setup-hook
              '(lambda ()
                 (define-key ido-common-completion-map (kbd "C-n") 'ido-next-match)
                 (define-key ido-common-completion-map (kbd "C-p") 'ido-prev-match)
                 (define-key ido-file-completion-map (kbd "C-w") 'ido-delete-backward-updir)
                 (define-key ido-file-completion-map (kbd "C-x C-w") 'ido-copy-current-file-name)))))

The package ido-ubiquitous replaces stock emacs completion with ido completion wherever it is possible to do so without breaking things.

(use-package ido-completing-read+
  :ensure t
  :config
  (ido-ubiquitous-mode))

I find it much better to see the results of ido-mode in a vertical manner. Vertical mode is much more friendly to the eye…

(use-package ido-vertical-mode
  :ensure t
  :init
  (ido-vertical-mode 1))

Fuzzy Matching à la Sublime Text makes some things easier too.

(use-package flx-ido
  :ensure t
  :init
  (flx-ido-mode 1)
  :config
  (setq ido-use-faces nil
        ido-enable-flex-matching t))

Smex is a M-x enhancement for Emacs. Built on top of IDO, it provides a convenient interface to your recently and most frequently used commands. And to all the other commands, too.

(use-package smex
  :ensure t
  :bind (([remap execute-extended-command] . smex)
         ("M-X" . smex-major-mode-commands)))
Jumping around windows & buffers

Going to a line is traditionally bound to M-g M-g. I use the prefix M-g to bind the avy package, which provides means to jump to char, word, line and much more.

BindingFunction
M-g javy-goto-char
M-g lavy-goto-line
M-g uavy-goto-word-0
(use-package avy
  :ensure t
  :bind (("M-g j" . avy-goto-char)
         ("M-g l" . avy-goto-line)
         ("M-g u" . avy-goto-word-0)))
Temporary Window Configurations
;; (defvar frame-winset-mode-line "")
;; (put 'frame-winset-mode-line 'risky-local-variable t)

;; (unless (memq 'frame-winset-mode-line global-mode-string)
;;   (setq global-mode-string (append '(frame-winset-mode-line)
;;                                    global-mode-string)))

;; (defface frame-winset-active-face
;;   '((t (:foreground "yellow" :bold 't)))
;;   "Winset mode line color"
;;   :group 'faces)

;; (defface frame-winset-inactive-face
;;   '((t (:foreground "gray")))
;;   "Winset mode line color"
;;   :group 'faces)

(defun frame-winset-update-mode-line ()
  "Set the modeline accordingly to the current state."
  (let ((current-index (frame-parameter nil 'window-configuration-index)))
    (setq frame-winset-mode-line
          (loop for element in '("[" 0 1 2 3 4 5 6 7 8 "]")
                collect (let ((element-string (format "%s " (if (stringp element)
                                                               element
                                                              (+ 1 element)))))
                          (if (eq element current-index)
                              (propertize element-string
                                          'face 'frame-winset-active-face)
                            (propertize element-string
                                        'face 'frame-winset-inactive-face)))))
  (force-mode-line-update)))

(defun window-toggle-maximize ()
  "Make the current window the maximum and go back."
  (interactive)
  (let ((last-window-configuration (frame-parameter nil 'temp-buffer-save)))
    (if last-window-configuration
        (progn
          (set-window-configuration last-window-configuration)
          (set-frame-parameter nil 'temp-buffer-save nil))
        (progn
          (set-frame-parameter nil 'temp-buffer-save (current-window-configuration))
          (delete-other-windows)))))

(defun substitute-nth (n value list)
  "Substitute the element at N by VALUE in given LIST."
  (loop for i from 0
        for j in list
        collect (if (= i n) value j)))

(set-frame-parameter nil 'window-configurations '(nil nil nil nil nil nil nil nil nil))
(set-frame-parameter nil 'window-configuration-index 0)

(defun window-setup-frame (frame)
  "Set the frame parameters of FRAME needed for fast window configuration switching."
  (set-frame-parameter frame 'window-configurations '(nil nil nil nil nil nil nil nil nil))
  (set-frame-parameter frame 'window-configuration-index 0))
(add-hook 'after-make-frame-functions 'window-setup-frame)

(defun window-switch-to-configuration (index)
  "Switch to a frame local window configuration with INDEX."
  (let* ((index (- index 1))
         (current-index (frame-parameter nil 'window-configuration-index))
         (configurations (frame-parameter nil 'window-configurations))
         (new-configurations (substitute-nth current-index (current-window-configuration) configurations)))
    (unless (eq index current-index)
      (set-frame-parameter nil 'window-configurations new-configurations)
      (set-frame-parameter nil 'window-configuration-index index)
      (if (nth index configurations)
          (set-window-configuration (nth index configurations))
        (delete-other-windows))
      (frame-winset-update-mode-line))))

(global-set-key (kbd "M-1") '(lambda () (interactive) (window-switch-to-configuration 1)))
(global-set-key (kbd "M-2") '(lambda () (interactive) (window-switch-to-configuration 2)))
(global-set-key (kbd "M-3") '(lambda () (interactive) (window-switch-to-configuration 3)))
(global-set-key (kbd "M-4") '(lambda () (interactive) (window-switch-to-configuration 4)))
(global-set-key (kbd "M-5") '(lambda () (interactive) (window-switch-to-configuration 5)))
(global-set-key (kbd "M-6") '(lambda () (interactive) (window-switch-to-configuration 6)))
(global-set-key (kbd "M-7") '(lambda () (interactive) (window-switch-to-configuration 7)))
(global-set-key (kbd "M-8") '(lambda () (interactive) (window-switch-to-configuration 8)))
(global-set-key (kbd "M-9") '(lambda () (interactive) (window-switch-to-configuration 9)))
(global-set-key (kbd "M-0") '(lambda () (interactive) (window-toggle-maximize)))
Speedbar As Sidebar

Speedbar is a sidebar that shows the file tree.

(use-package speedbar
  :config
  (setq speedbar-use-images nil ; Only use ASCII characters
        speedbar-update-flag nil ; Do not update automatically.
        speedbar-show-unknown-files t ; Show all files in speedbar, such as Ruby and Java files.
        ))
Custom Keymap
(define-prefix-command 'leoc-map)
(global-set-key (kbd "C-ß") 'leoc-map)

(define-key leoc-map (kbd "m") 'mu4e)
(define-key leoc-map (kbd "c") 'mu4e-compose-new)

Programming

(use-package which-func
  :init
  (which-func-mode 1))
Appearance
(defun leoc/prog-mode-defaults ()
  "Sets custom programming defaults."
  (set (make-local-variable 'comment-auto-fill-only-comments) t)
  (auto-fill-mode t)

  (font-lock-add-keywords
   nil '(("\\<\\(FIX\\|TODO\\|FIXME\\|HACK\\|REFACTOR\\):"
          1 font-lock-warning-face t)))
  (font-lock-add-keywords
   nil '(("\\(KC_TRNS\\)"
          1 font-lock-comment-face t))))
(add-hook 'prog-mode-hook 'leoc/prog-mode-defaults)
Documentation
Dash
(use-package helm-dash :ensure t)
Languages / Environments
Web
HTML
Haml-mode

Haml (HTML Abstraction Markup Language) is a templating system to avoid writing the inline code in a web document and make HTML easy and clean. Haml gives the flexibility to have some dynamic content in HTML. Similar to other web languages like PHP, ASP, JSP and template systems like eRuby, Haml also embeds some code that gets executed during runtime and generates HTML code in order to provide some dynamic content. In order to run Haml code, files need to have .haml extension. These files are similar to .erb or eRuby files which also help to embed Ruby code while developing a web application.

(use-package haml-mode
  :ensure t
  :mode "\\.hamlc?\\'")
Emmet-mode

Emmet-mode provides ZenCoding-features for Emacs.

(use-package emmet-mode
  :ensure t
  :defer 1
  :config
  (add-hook 'rjsx-mode-hook 'emmet-mode)
  (add-hook 'sgml-mode-hook 'emmet-mode)
  (add-hook 'css-mode-hook  'emmet-mode)
  (setq emmet-move-cursor-between-quotes t)
  (setq emmet-self-closing-tag-style " /"))
Stylesheets

For stylesheets I use a variety of preprocessors, which have some similar settings. Mainly the indentation and the use of rainbow-mode, which shows the colors directly within the buffer.

(defun leoc/css-defaults ()
  (setq css-indent-offset 2)
  (rainbow-mode))

Basic CSS mode should activate those settings.

(add-hook 'css-mode-hook 'leoc/css-defaults)

SCSS mode combines functionality for SASS and SCSS syntax.

(use-package scss-mode
  :ensure t
  :defer t
  :init
  (progn
    (add-hook 'scss-mode-hook 'leoc/css-defaults)
    (add-hook 'scss-mode-hook
              #'(lambda ()
                  (setq scss-compile-at-save nil)))))

Stylus is an interesting preprocessor combinding multiple paradigms for writing complex stylesheets.

(use-package stylus-mode
  :ensure t
  :defer t
  :init
  (add-hook 'stylus-mode-hook 'leoc/css-defaults))
JavaScript
(flycheck-def-config-file-var flycheck-jscs javascript-jscs ".jscsrc" :safe #'stringp)
(flycheck-define-checker javascript-jscs
  "A JavaScript code style checker."
  :command ("jscs" "--reporter" "checkstyle"
            (config-file "--config" flycheck-jscs)
            source)
  :error-parser flycheck-parse-checkstyle
  :modes (js-mode js2-mode js3-mode jsx-mode rjsx-mode)
  :next-checkers (javascript-jshint))
(add-to-list 'flycheck-checkers 'javascript-jscs)
(defun leoc/js-mode-defaults ()
  (run-import-js)
  (add-hook 'after-save-hook #'import-js-fix nil t)
  (electric-indent-mode -1)
  (setq js2-basic-offset 2
        js2-highlight-level 3
        js2-bounce-indent-p t
        tab-width 2
        indent-tabs-mode nil
        js2-strict-missing-semi-warning nil))

(use-package js2-mode
  :ensure t
  :interpreter (("node" . js2-mode))
  :mode (("\\.js?\\'" . js2-mode))
  :config
  (add-hook 'js2-mode-hook 'leoc/js-mode-defaults))
(defun leoc/rjsx-mode-defaults ()
  (leoc/js-mode-defaults)
  (setq emmet-expand-jsx-className? t))

(use-package rjsx-mode
  :ensure t
  :interpreter (("node" . rjsx-mode))
  :mode (("\\.jsx?\\'" . rjsx-mode))
  :bind (("C-c i" . import-js-import))
  :config
  (add-hook 'rjsx-mode-hook 'leoc/rjsx-mode-defaults))
(use-package prettier-js
    :ensure t
    :config
    (setq prettier-js-args '(
                          "--trailing-comma" "es5"
                          "--single-quote" "true"
                          "--print-width" "100"
                          ))
    (add-hook 'js2-mode-hook 'prettier-js-mode)
    (add-hook 'rjsx-mode-hook 'prettier-js-mode))
(use-package import-js :ensure t)
CoffeeScript
(defun leoc/coffee-mode-defaults ()
  "Set coffee-mode defaults."
  (electric-indent-mode -1)
  (setq coffee-tab-width 2
        tab-width 2
        coffee-js-mode 'js2-mode
        tab-stop-list '(2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60)))

(use-package coffee-mode
  :ensure t
  :config
  (add-hook 'coffee-mode-hook 'leoc/coffee-mode-defaults))
Ruby
(use-package rinari :ensure t :defer t)
(use-package bundler :ensure t :defer t)
(use-package ruby-end
  :ensure t
  :defer t
  :diminish ruby-end-mode)
(use-package inf-ruby :ensure t :defer t)
(use-package rvm :ensure t :defer t)
(use-package robe
  :ensure t
  :defer t
  :init
  (progn
    (add-hook 'ruby-mode-hook 'robe-mode)
    (eval-after-load 'company
      '(push 'company-robe company-backends))

    (defadvice inf-ruby-console-auto (before activate-rvm-for-robe activate)
      (rvm-activate-corresponding-ruby))))
(use-package rubocop
  :ensure t
  :defer t
  :diminish rubocop-mode
  :init
  (add-hook 'ruby-mode-hook 'rubocop-mode))
Python
(use-package python-mode
  :ensure t
  :config
  (flycheck-add-next-checker 'python-flake8 'python-pylint))
LISP

Paredit is a great mode to work with LISPs parenthesis.

(use-package paredit :ensure t)
(use-package rainbow-delimiters
  :ensure t
  :defer t
  :diminish rainbow-delimiters-mode
  :init
  (leoc/hook-into-modes #'rainbow-delimiters-mode
    '(text-mode-hook prog-mode-hook)))
Clojure
(use-package cider :ensure t)
(use-package clojure-mode :ensure t)
ClojureScript
Emacs Lisp
(use-package lisp-mode
  :defer t
  :mode (("\\.el$" . emacs-lisp-mode)
         ("/Cask$" . emacs-lisp-mode))
  :init
  (setq initial-major-mode 'emacs-lisp-mode)
  :config
  (progn

    (defun leoc/elisp-eval-region ()
      (interactive)
      (if (region-active-p)
          (progn
            (eval-region (region-beginning)
                         (region-end))
            (deactivate-mark))
        (eval-expression)))

    (defun leoc/elisp-register-elc-delete-on-save ()
      "If you're saving an elisp file, likely the .elc is no longer valid."
      (make-local-variable 'after-save-hook)
      (add-hook 'after-save-hook
                '(lambda ()
                   (when (file-exists-p (concat buffer-file-name "c"))
                     (delete-file (concat buffer-file-name "c"))))))

    (defun leoc/elisp-defaults ()
      (turn-on-eldoc-mode)
      (leoc/elisp-register-elc-delete-on-save)
      (paredit-mode +1))

    (leoc/hook-into-modes #'leoc/elisp-defaults
      '(emacs-lisp-mode-hook ielm-mode-hook lisp-interaction-mode-hook)))

  (define-key emacs-lisp-mode-map (kbd "C-c C-c") 'leoc/elisp-eval-region))
Litable

Litable evaluates lisp code on the fly and shows evaluation results inline.

(use-package litable
  :ensure t
  :demand t
  :bind (:map litable-mode-map
         ("C-c l a" . litable-accept-as-pure)))
SLIME like Navigation
(use-package elisp-slime-nav
  :ensure t
  :defer t
  :diminish elisp-slime-nav-mode
  :init
  (leoc/hook-into-modes #'elisp-slime-nav-mode
    '(emacs-lisp-mode-hook ielm-mode-hook)))
Code Evaluation

It is quite helpful to evaluate inline Elisp code. Even in other language buffers I can hit C-c C-r which evaluates the preceding expression and replaced it with its return value.

Among other things this gets handy when:

  • executing keyboard macros counting up
  • concatenating strings within multiple-cursors mode
(defun leoc/eval-and-replace ()
  "Replace the preceding sexp with its value."
  (interactive)
  (backward-kill-sexp)
  (condition-case nil
      (prin1 (eval (read (current-kill 0)))
             (current-buffer))
    (error (message "Invalid expression")
           (insert (current-kill 0)))))

(global-set-key (kbd "C-c C-r") 'leoc/eval-and-replace)
Serialization Formats
YAML

I love the quick navigation through org-mode outlines. With the outline-minor-mode we can achieve something similar with the YAML mode. That means cycling through visibility and other fancy outline navigation features:

(use-package outline-magic :ensure t)
(use-package yaml-mode
  :ensure t
  :config
  (progn
    (add-hook 'yaml-mode-hook 'leoc/yaml-outline-hook)

    (defun leoc/yaml-outline-level ()
      (let (buffer-invisibility-spec)
        (save-excursion
          (skip-chars-forward " \\-")
          (/ (current-column) 2))))

    (defun leoc/yaml-outline-hook ()
      (interactive)
      (setq outline-regexp "^[ \\t]*\\([^#:]+\\):\\( ?&[A-Za-z0-9]+\\)?$")
      (setq outline-level 'leoc/yaml-outline-level)

      (outline-minor-mode t)
      (hide-body)
      (show-paren-mode 1)
      (define-key yaml-mode-map [tab] 'outline-cycle)
      (define-key outline-minor-mode-map [M-S-tab] 'indent-for-tab-command)
      (define-key outline-minor-mode-map [M-down] 'outline-move-subtree-down)
      (define-key outline-minor-mode-map [M-up] 'outline-move-subtree-up))))
JSON
(use-package json-mode :ensure t :defer t)
Java
 (use-package eclim
   :ensure t
   :config
   (progn
     (require 'eclim)
     (require 'eclimd)

     (use-package company-emacs-eclim
       :ensure t
       :config
	(with-eval-after-load 'company
         (require 'company-emacs-eclim)))

     (setq eclim-eclipse-dirs '("~/.eclipse")
           eclim-executable (expand-file-name "~/.eclipse/eclim")
           eclim-auto-save t
           eclimd-executable (expand-file-name "~/.eclipse/eclimd")
           eclimd-default-workspace (expand-file-name "~/projects"))

     (global-eclim-mode)

     (defun leoc/java-eclim-defaults ()
       (eclim-mode)
       (company-emacs-eclim-setup)
       ;; Adjust to the Eclipse styling.
       (setq c-basic-offset 4
             tab-width 4
             indent-tabs-mode nil)
       ;; Because eclim mode needs to save the buffer on completion I
       ;; do not want to clean up the whitespaces automatically before
       ;; saving, it simply annoys when your completion expands on a
       ;; different position then you were before.
       (set (make-local-variable 'before-save-hook) nil)
       ;; That´s why I overwrite the binding for saving the buffer.
       ;; Only clean up before saving when I hit C-x C-s.
       (local-set-key (kbd "C-x C-s")
                      '(lambda ()
                         (interactive)
                         (cleanup-buffer-safe)
                         (save-buffer)))
       ;; Setup usual bindings for jumping to declaration and popping
       ;; the mark again.
       (local-set-key (kbd "M-.") 'eclim-java-find-declaration)
       (local-set-key (kbd "M-,") 'pop-tag-mark))))
Lua
(use-package lua-mode :ensure t :defer t)
Cucumber

The package feature-mode provides everything I need for working with files in the Gerkhin syntax.

(use-package feature-mode :ensure t)
XML
(use-package nxml-mode
  :config
  (setq nxml-child-indent 2
        nxml-attribute-indent 2
        nxml-auto-insert-xml-declaration-flag nil
        nxml-bind-meta-tab-to-complete-flag t
        nxml-slash-auto-complete-flag t))
Markdown
(use-package markdown-mode :ensure t :defer t)
SQL Interaction
(use-package edbi
  :ensure t
  :config
  (progn
    (use-package company-edbi
      :ensure t
      :config
      (eval-after-load 'company
        '(push 'company-edbi company-backends)))

    (use-package edbi-minor-mode
      :ensure t
      :config
      (add-hook 'sql-mode-hook 'edbi-minor-mode))))
Rainbow Mode
 (use-package rainbow-mode
   :ensure t
   :config
   (defun lighten-color-at-point (&optional pct)
     (interactive "p")
     (unless (looking-at-p "#")
	(re-search-backward "#"))
     (save-excursion
	(push-mark nil t t)
	(let ((dist (skip-chars-forward "#A-Za-z0-9" (+ (point) 7)))
	      (percent (or pct 5)))
	  (insert (apply 'color-rgb-to-hex
			 (apply 'color-hsl-to-rgb
				(apply 'color-lighten-hsl
				       (append (apply 'color-rgb-to-hsl
						      (color-name-to-rgb (buffer-substring-no-properties (mark) (point))))
					       (list percent))))))
	  (delete-region (region-beginning) (+ (region-beginning) dist)))))

   (defun darken-color-at-point (&optional pct)
     (interactive "p")
     (lighten-color-at-point (if (numberp pct) (* pct -1) -5)))

   (defun convert-color-at-point (&optional pct)
     (interactive "p")
     (unless (looking-at-p "#")
	(re-search-backward "#"))
     (save-excursion
	(push-mark nil t t)
	(let ((dist (skip-chars-forward "#A-Za-z0-9" (+ (point) 7)))
	      (percent (or pct 5)))
	  (insert (s-join ", " (mapcar #'(lambda (a)
					   (format "%s" (truncate (* 255 a))))
				       (color-name-to-rgb (buffer-substring-no-properties (mark) (point))))))
	  (delete-region (region-beginning) (+ (region-beginning) dist)))))

   (defun leoc-rainbow-mode-hook ()
     (local-set-key (kbd "C-c l l") 'convert-color-at-point)
     (local-set-key (kbd "C-+") 'lighten-color-at-point)
     (local-set-key (kbd "C--") 'darken-color-at-point))

   (add-hook 'rainbow-mode-hook 'leoc-rainbow-mode-hook))

Org-Mode

(use-package org
  :ensure org-plus-contrib
  :diminish (org-indent-mode)
  :bind (("C-c a" . org-agenda)
         :map org-mode-map
         ("M-p" . org-metaup)
         ("M-n" . org-metadown)
         ("M-n" . org-metadown)
         ("C-c o o" . org-pomodoro))
  :config
  (progn
    <<leoc/org-mode-config>>
    ))
Org Files
FileAgendaBindingDescription
Bindings to jump to org files
(bind-key "C-c o P" (lambda () (interactive) (find-file "~/.org/passwords.org.gpg")))
(bind-key "C-c o b" (lambda () (interactive) (find-file "~/.org/bookmarks.org")))
(bind-key "C-c o c" (lambda () (interactive) (find-file "~/.org/calendar.org")))
(bind-key "C-c o j" (lambda () (interactive) (find-file "~/.org/journal.org")))
(bind-key "C-c o p" (lambda () (interactive) (find-file "~/.org/_personal.org")))
(bind-key "C-c o r" (lambda () (interactive) (find-file "~/.org/refile.org")))
(bind-key "C-c o v" (lambda () (interactive) (find-file "~/.org/_business_velaluqa.org")))

(which-key-add-key-based-replacements "C-c o P" "Open passwords.org.gpg")
(which-key-add-key-based-replacements "C-c o b" "Open bookmarks.org")
(which-key-add-key-based-replacements "C-c o c" "Open calendar.org")
(which-key-add-key-based-replacements "C-c o j" "Open journal.org")
(which-key-add-key-based-replacements "C-c o p" "Open _personal.org")
(which-key-add-key-based-replacements "C-c o r" "Open refile.org")
(which-key-add-key-based-replacements "C-c o v" "Open _business_velaluqa.org")
Default Hook
(add-hook 'org-mode-hook #'(lambda ()
                             (auto-fill-mode +1)
                             (rainbow-delimiters-mode -1)))
Function
Convert clock format to decimal
(defun org-clock-to-decimal (time)
  (when (string-match-p "^\\*\\(.*\\)\\*$" time)
    (setq time (substring time 1 -1)))
  (let* ((time (s-split ":" time))
         (hours (string-to-number (nth 0 time)))
         (minutes (string-to-number (nth 1 time)))
         (decimal (/ (+ (* hours 60.0) minutes) 60.0)))
    (format "%0.2f" (/ (ceiling (* decimal 100.0)) 100.0))))
Override Clock Table Indent String

The original indent string function uses “\ ” as indentation, but this seems to be problematic, so we use simple underscores “__” to indent headings within the clocktable.

(defun org-clocktable-indent-string (level)
  (if (= level 1) ""
    (let ((str " "))
      (dotimes (k (1- level) str)
        (setq str (concat "__" str))))))
Settings
(setq org-startup-indented t
      ;; Deprecated since org 9.0. ~completing-read~ is enough.
      org-completion-use-ido nil
      ;; Separate drawers for clocking and logs
      org-drawers '("PROPERTIES" "LOGBOOK"))

;; Other symbols: ▼
(setq org-ellipsis " ↴")
Markup
(setq org-hide-emphasis-markers t)
(setq org-emphasis-regexp-components-original
      '(" \t('\"{"
        "- \t.,:!?;'\")}\\["
        " \t\r\n,\"'"
        "."
        1))
(setq org-emphasis-regexp-components
      '(" \t('\"{[:alpha:]"
        "[:alpha:]- \t.,:!?;'\")}\\["
        " \t\r\n,\"'"
        "."
        0))
(org-set-emph-re 'org-emphasis-regexp-components org-emphasis-regexp-components)
org-emph-re
Movement
(setq org-use-speed-commands t)
Logging & Clocking
(setq org-log-done 'time
      org-log-repeat 'time
      org-log-reschedule 'time
      org-log-redeadline 'time
      org-log-into-drawer "LOGBOOK"
      ;; Show lot sof clocking history so it's easy to pick items off the C-F11 list
      org-clock-history-length 36
      ;; 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
      ;; Do not prompt to resume an active clock
      org-clock-persist-query-resume nil
      ;; Include current clocking task in clock reports
      org-clock-report-include-clocking-task t
      )
(setq org-time-clocksum-format '(:hours "%d" :require-hours t :minutes ":%02d" :require-minutes t))
Persistent Clocks

Resume active clocking task when emacs is restarted.

(org-clock-persistence-insinuate)
Auto Save After Clocking

I want to make sure that clocks are saved immediately when clocking in or out so I don’t lose any clocks.

(defun my-save-on-clocking-command ()
  (save-excursion
    (save-window-excursion
      (org-clock-goto)
      (save-buffer))))

(add-hook 'org-clock-in-hook 'my-save-on-clocking-command)
(add-hook 'org-clock-out-hook 'my-save-on-clocking-command)
Pomodoro Technique

The Pomodoro Technique™ is a time management method developed by Francesco Cirillo in the late 1980s. The technique uses a timer to break down work into intervals, traditionally 25 minutes in length, separated by short breaks. These intervals are called pomodoros, the plural in English of the Italian word pomodoro, which means tomato. The method is based on the idea that frequent breaks can improve mental agility.

The org-pomodoro package implements the timer functionality and some helpers to work with pomodoros within the org-mode clocking function.

(use-package org-pomodoro
  :ensure t
  :defer t)
Refile
 (defun leoc/verify-refile-target ()
   (let ((title (nth 4 (org-heading-components))))
     (or (not (equal (buffer-file-name) "/home/arthur/.org/bookmarks.org"))
         (not (string-match "\\(\\[\\[.*\\]\\[.*\\]\\]\\|\\[\\[.*\\]\\]\\)" title)))))

 (setq org-log-refile 'time
	org-refile-use-outline-path 'file
	org-outline-path-complete-in-steps nil
	org-refile-use-cache t
	org-refile-allow-creating-parent-nodes t
	org-refile-target-verify-function 'leoc/verify-refile-target
	org-refile-targets '(("~/.org/tasks.org" :maxlevel . 2)
                            ("~/.org/_personal.org" :maxlevel . 4)
                            ("~/.org/_personal2.org" :maxlevel . 4)
                            ("~/.org/_sideprojects.org" :maxlevel . 2)
                            ("~/.org/_business_velaluqa.org" :maxlevel . 4)
                            ("~/.org/_business_crowdcat.org" :maxlevel . 4)
                            ("~/.org/_business_personal.org" :maxlevel . 4)
                            ("~/.org/bookmarks.org" :maxlevel . 8)
                            ("~/.org/notes.org" :level . 1)
                            ("~/.org/thoughts.org" :level . 1)
                            ("~/.org/calendar.org" :level . 1)))
Replace Disputed Keys

Disable S-arrow bindings for org-mode, so we can use those bindings for navigating through windows.

(setq org-replace-disputed-keys t)
Code Blocks
(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
Emacs Lisp Code Blocks

To quickly write emacs-lisp code blocks within my Emacs configuration I like this little template addition:

(add-to-list 'org-structure-template-alist
        '("m" "#+BEGIN_SRC emacs-lisp\n?\n#+END_SRC" "<src lang=\"emacs-lisp\">\n\n</src>"))
Todo Keywords
(setq org-use-fast-todo-selection t)
(setq org-todo-keywords
      '((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!/!)")
        (sequence "WAITING(w@/!)" "HOLD(h@/!)" "SOMEDAY(o)" "|" "CANCELLED(c@/!)")
        (sequence "READ(r)" "|" "FINISHED(f!/!)" "REJECTED(r@/!)")))

For visual feedback I have a custom color for each todo keyword.

(setq org-todo-keyword-faces
      '(("SOMEDAY"   :foreground "#808080" :weight bold)
        ("NEXT"      :foreground "#e9c062" :weight bold)
        ("STARTED"   :foreground "#ffff63" :weight bold)
        ("WAITING"   :foreground "#fd9b3b" :weight bold)
        ("HOLD"      :foreground "#9b859d" :weight bold)
        ("READ"      :foreground "#9aaaff" :weight bold)
        ("FINISHED"  :foreground "#9eb9a7" :weight bold)
        ("REJECTED"  :foreground "#9eb9a7" :weight bold)
        ("CANCELLED" :foreground "#9eb9a7" :weight bold)))
Priority Settings

Similar to the TODO keywords I color each priority level differently.

(setq org-priority-faces
      '((65 :foreground "#ff7000" :weight bold)
        (66 :foreground "#ffa060" :weight bold)
        (67 :foreground "#ffcca8" :weight bold)))
Tags

Use fast-tag-selection for selecting tags. This shows a window listing common tags, from which I can choose with one key press.

(setq org-fast-tag-selection-single-key t)

The common tags are defined as follows:

(setq org-tag-alist '((:startgroup . nil)
			(:newline)
			("1vp" . ?1)
			("2ci" . ?2)
			("3lt" . ?3)
			("4mf" . ?4)
			("5cw" . ?5)
			("6hf" . ?6)
			(:newline)
			("7es" . ?7)
			("8sr" . ?8)
			("9ew" . ?9)
			("aci" . ?a)
			("bpo" . ?b)
			("cac" . ?c)
			(:newline)
			(:endgroup . nil)
			(:startgroup . nil)
			("business" . ?b)
			("personal" . ?p)
			(:endgroup . nil)
			(:startgroup . nil)
			("year" . ?y)
			("month" . ?m)
			("week" . ?w)
			("day" . ?d)
			(:endgroup . nil)))
Expiry

Currently I do not use the expiration feature of org-expiry, but I want to have each org heading to have a CREATED date to know the age of a certain heading.

(use-package org-expiry
  :demand t
  :config
  (setq org-expiry-created-property-name "CREATED"
        org-expiry-inactive-timestamps t))
Agenda
File NameDescription
~/.org/_personal.org
~/.org/_business_velaluqa.org
~/.org/calendar.org
;; Because the org-agenda `:config` block is deferred it does not have
;; access to the `leoc-agenda-files` variable that would be tangled
;; via a `let` statement. So I define a global variable instead.
`(quote ,leoc-agenda-files)
(use-package org-helpers
  :load-path "vendor/org-helpers")
(use-package org-agenda
  :ensure org
  :bind (:map org-agenda-mode-map
              ("W" . oh/agenda-remove-restriction)
              ("N" . oh/agenda-restrict-to-subtree)
              ("P" . oh/agenda-restrict-to-project)
              ("q" . bury-buffer)
              ("C-c o o" . org-pomodoro))
  :config
  (progn
    (setq org-agenda-files '("~/.org/_personal.org" "~/.org/_business_velaluqa.org" "~/.org/calendar.org")
          org-agenda-start-on-weekday nil
          org-agenda-span 1
          org-agenda-include-diary t
          org-agenda-window-setup 'current-window
          org-deadline-warning-days 365
          org-agenda-repeating-timestamp-show-all t

          ;; Show all agenda dates - even if they are empty
          org-agenda-show-all-dates t
          ;; Sorting order for tasks on the agenda
          ;; org-agenda-sorting-strategy '((agenda habit-down time-up user-defined-up priority-down effort-up category-keep)
          ;;                               (todo category-up priority-down effort-up)
          ;;                               (tags category-up priority-down effort-up)
          ;;                               (search category-up))
          ;; Keep tasks with dates on the global todo lists
          org-agenda-todo-ignore-with-date nil
          ;; Keep tasks with deadlines on the global todo lists
          org-agenda-todo-ignore-deadlines nil
          ;; Keep tasks with scheduled dates on the global todo lists
          org-agenda-todo-ignore-scheduled nil
          ;; Keep tasks with timestamps on the global todo lists
          org-agenda-todo-ignore-timestamp nil
          ;; Remove completed deadline tasks from the agenda view
          org-agenda-skip-deadline-if-done t
          ;; Remove completed scheduled tasks from the agenda view
          org-agenda-skip-scheduled-if-done t
          ;; Remove completed items from search results
          org-agenda-skip-timestamp-if-done t
          ;; Display tags farther right
          org-agenda-tags-column -102
          org-agenda-hide-tags-regexp "personal\\|habit\\|business\\|practice\\|music\\|ATTACH\\|hacking\\|code\\|project\\|pd\\|read"
          org-agenda-persistent-filter t
          ;; Enable display of the time grid
          ;; so we can see the marker for the current time
          ;; org-agenda-time-grid '((daily today remove-match)
          ;; 			 #("----------------" 0 16 (org-heading t))
          ;; 			 (830 1000 1200 1300 1500 1700 2000 2300))
          ;; Do not dim blocked tasks
          org-agenda-dim-blocked-tasks nil

          org-agenda-start-with-log-mode t
          org-agenda-log-mode-add-notes nil
          org-agenda-start-with-clockreport-mode t
          org-agenda-clockreport-parameter-plist '(:link t :maxlevel 3 :fileskip0 t))))
Getting Things Done
(add-to-list 'org-tags-exclude-from-inheritance "project")
(add-to-list 'org-tags-exclude-from-inheritance "sideproject")
(add-to-list 'org-tags-exclude-from-inheritance "week")
(add-to-list 'org-tags-exclude-from-inheritance "month")
(add-to-list 'org-tags-exclude-from-inheritance "year")
Custom Commands

For my agenda I use

(use-package org-super-agenda
  :load-path "vendor/org-super-agenda"
  :config
  (progn
    (setq org-agenda-custom-commands
          '(
	      ("a" "Agenda" agenda ""
	       ((org-agenda-span 'day)
		(org-super-agenda-groups
		 '((:todo ("SOMEDAY" "TO-READ" "CHECK" "TO-WATCH" "WATCHING") :last t)
		   (:name "Today" :time t :todo "TODAY")
		   (:name "Reading" :todo "READ")
		   (:name "Mindful Living" :tag ("mindfulness"))
		   (:name "Important" :priority "A")
		   (:name "Chores" :tag ("household" "chores"))
		   (:name "Current Projects" :tag "project")
		   (:name "Ergonomics" :tag "ergonomics")
		   (:name "Find Rehearsal Room" :tag "rehearsal")
		   (:name "Communication, Socializing & Networking" :tag ("networking" "socialize" "mail"))
		   (:name "Music" :tag "music")
		   (:name "Hacking" :tag "hacking")
		   (:name "Food-related" :tag ("food" "dinner"))
		   (:todo "WAITING")
		   (:priority ("B" "C"))))))
	      ("Z" "Agenda"
	       ((agenda ""
			((org-agenda-span 'day)
			 (org-super-agenda-groups
			  '((:discard (:tag "velaluqa"))
			    (:name "Done today" :and (:log t) :order 100)
			    (:name "Goals this year" :and (:tag "year" :deadline (before "2019-01-01")))
			    (:name "Goals this month" :and (:tag "month" :deadline (before "2018-06-01")))
			    (:name "Goals this week" :and (:tag "week" :deadline (before "2018-05-21")))
			    ;; (:name "Habits today" :habit t)
			    (:name "Focus area today" :and (:priority>= "A" :scheduled t))
			    (:name "To do today" :and (:scheduled t))
			    (:discard (:anything t))))))))
	      ("v" "Velaluqa Agenda"
	       ((agenda ""
			((org-agenda-span 'day)
			 (org-super-agenda-groups
			  '((:discard (:not (:tag "velaluqa")))
			    (:name "Done today" :log t :time-grid t :order 104)
			    (:name "Goals this year" :and (:tag "year" :deadline (before "2019-01-01")))
			    (:name "Goals this month" :and (:tag "month" :deadline (before "2018-06-01")))
			    (:name "Goals this week" :and (:tag "week" :deadline (before "2018-05-21")))
			    (:name "Focus area today" :and (:priority>= "A" :scheduled t))
			    (:name "To do today" :scheduled t)
			    (:discard (:anything t))))))))
	      ("o" "Agenda"
	       ((agenda "" ((org-agenda-sorting-strategy '(habit-down timestamp-up time-up priority-down category-keep user-defined-up))))
		(tags-todo "+project-archived-shopping-CANCELLED/!-HOLD-WAITING"
			   ((org-agenda-overriding-header "Stuck Projects")
			    (org-agenda-skip-function
			     '(oh/agenda-skip :headline-if '(non-project)
					      :subtree-if '(non-stuck-project inactive-project habit scheduled deadline)))
			    (org-tags-match-list-sublevels 'intended)))
		(tags-todo "-archived-shopping-CANCELLED/!WAITING|HOLD"
			   ((org-agenda-overriding-header "Waiting and Postponed Tasks")
			    (org-agenda-skip-function
			     '(oh/agenda-skip :subtree-if '(project habit)))
			    (org-tags-match-list-sublevels nil)))
		(tags-todo "-archived-shopping-WAITING-CANCELLED/!NEXT"
			   ((org-agenda-overriding-header "Next Tasks")
			    (org-agenda-skip-function
			     '(oh/agenda-skip :headline-if '(project)
					      :subtree-if '(inactive habit scheduled deadline)
					      :subtree-if-unrestricted-and '(subtask)
					      :subtree-if-restricted-and '(single-task)))
			    (org-tags-match-list-sublevels 'indented)
			    (org-agenda-sorting-strategy '(priority-down todo-state-down effort-up category-keep))))
		;; (tags-todo "-archived-shopping-CANCELLED/!-NEXT-HOLD-WAITING"
		;;            ((org-agenda-overriding-header "Available Tasks")
		;;             (org-agenda-skip-function
		;;              '(oh/agenda-skip :headline-if '(project)
		;;                               :subtree-if '(inactive habit scheduled deadline)
		;;                               :subtree-if-unrestricted-and '(subtask)
		;;                               :subtree-if-restricted-and '(single-task)))
		;;             (org-agenda-sorting-strategy '(priority-down category-keep))
		;;             (org-tags-match-list-sublevels nil)))
		(tags-todo "+project-archived-CANCELLED/!"
			   ((org-agenda-overriding-header "Currently Active Projects")
			    (org-agenda-skip-function
			     '(oh/agenda-skip :subtree-if '(non-project stuck-project inactive-project habit)
					      :headline-if-unrestricted-and '(subproject)
					      :headline-if-restricted-and '(top-project)))
			    (org-tags-match-list-sublevels 'indented)
			    (org-agenda-sorting-strategy '(priority-down category-keep)))))
	       nil)
	      ("r" "Tasks to Refile" alltodo ""
	       ((org-agenda-overriding-header "Tasks to Refile")
		(org-agenda-files '("~/.org/inbox.org"))))
	      ("#" "Stuck Projects" tags-todo "-archived-shopping-CANCELLED/!-HOLD-WAITING"
	       ((org-agenda-overriding-header "Stuck Projects")
		(org-agenda-skip-function
		 '(oh/agenda-skip :subtree-if '(inactive non-project non-stuck-project
							 habit scheduled deadline)))))
	      ("n" "Next Tasks" tags-todo "-archived-shopping-WAITING-CANCELLED/!NEXT"
	       ((org-agenda-overriding-header "Next Tasks")
		(org-agenda-skip-function
		 '(oh/agenda-skip :subtree-if '(inactive project habit scheduled deadline)))
		(org-tags-match-list-sublevels t)
		(org-agenda-sorting-strategy '(priority-down todo-state-down effort-up category-keep))))
	      ("R" "Tasks" tags-todo "-archived-shopping-CANCELLED/!-NEXT-HOLD-WAITING"
	       ((org-agenda-overriding-header "Available Tasks")
		(org-agenda-skip-function
		 '(oh/agenda-skip :headline-if '(project)
				  :subtree-if '(inactive habit scheduled deadline)
				  :subtree-if-unrestricted-and '(subtask)
				  :subtree-if-restricted-and '(single-task)))
		(org-agenda-sorting-strategy '(priority-down category-keep))))
	      ("p" "Projects" tags-todo "-archived-shopping-CANCELLED/!"
	       ((org-agenda-overriding-header "Currently Active Projects")
		(org-agenda-skip-function
		 '(oh/agenda-skip :subtree-if '(non-project inactive habit)))
		(org-agenda-sorting-strategy '(priority-down category-keep))
		(org-tags-match-list-sublevels 'indented)))
	      ("w" "Waiting Tasks" tags-todo "-archived-shopping-CANCELLED/!WAITING|HOLD"
	       ((org-agenda-overriding-header "Waiting and Postponed Tasks")
		(org-agenda-skip-function '(oh/agenda-skip :subtree-if '(project habit)))))))))
Time Budgets

I plan to work a defined amount of time on certain tasks. Time Budgets helps me visualizing my clocked time in a simple table.

(use-package org-time-budgets
  :ensure t
  :load-path "/home/arthur/projects/org-time-budgets/"
  :config
  (setq org-time-budgets '((:title "Business" :tags "+business" :budget "30:00" :block workweek)
                           (:title "Sideprojects" :tags "+personal+project" :budget "14:00" :block week)
                           (:title "Music Theory" :tags "+music+theory" :budget "2:55" :block week)
                           (:title "Music Practice" :tags "+music+practice" :budget "2:55" :block week)
                           (:title "Exercise" :tags "+exercise|+health" :budget "5:15" :block week)
                           (:title "Language" :tags "+lang" :budget "5:15" :block week))))
Planning
Bindings to set weekly, monthly, yearly focus

I like to have a hierarchy of tasks from the macro- to the micro-level. Yearly bigger goals get split into smaller goals that I can tackle within a month, within a week etc.

(defun planning/weekly-focus ()
  "Set deadline, schedule and tag."
  (interactive)
  (org-toggle-tag "week" 'on)
  (org-toggle-tag "month" 'off)
  (org-toggle-tag "year" 'off)
  (org-set-tags nil t)
  (org-deadline t (format-time-string "%Y-%m-%d" (last-day-of-week))))

(defun planning/monthly-focus ()
  "Set deadline, schedule and tag."
  (interactive)
  (org-toggle-tag "week" 'off)
  (org-toggle-tag "month" 'on)
  (org-toggle-tag "year" 'off)
  (org-set-tags nil t)
  (org-deadline t (format-time-string "%Y-%m-%d" (last-day-of-month))))

(defun planning/yearly-focus ()
  "Set deadline, schedule and tag."
  (interactive)
  (org-toggle-tag "week" 'off)
  (org-toggle-tag "month" 'off)
  (org-toggle-tag "year" 'on)
  (org-set-tags nil t)
  (org-deadline t (format-time-string "%Y-%m-%d" (last-day-of-year))))

(bind-key "C-c P w" 'planning/weekly-focus org-mode-map)
(bind-key "C-c P m" 'planning/monthly-focus org-mode-map)
(bind-key "C-c P y" 'planning/yearly-focus org-mode-map)

(defun last-day-of-year ()
  "Return the last day of the year as time."
  (encode-time 0 0 0 31 12 (nth 5 (decode-time
				     (current-time)))))

(defun last-day-of-month ()
  "Return the last day of month as time."
  (let* ((now (decode-time (current-time)))
	   (month (nth 4 now))
	   (year (nth 5 now))
	   (last-day-of-month (calendar-last-day-of-month month year)))
    (encode-time 0 0 0 last-day-of-month month year)))

(defun last-day-of-week ()
  "Return the last day of the week as time."
  (let* ((now (current-time))
	   (datetime (decode-time now))
	   (dow (nth 6 datetime)))
    (time-add now (days-to-time (- 7 dow)))))
Archive
 (defun org-archive-subtree (&optional find-done)
   "Move the current subtree to the archive.
 The archive can be a certain top-level heading in the current file, or in
 a different file.  The tree will be moved to that location, the subtree
 heading be marked DONE, and the current time will be added.

 When called with a single prefix argument FIND-DONE, find whole trees without any
 open TODO items and archive them (after getting confirmation from the user).
 When called with a double prefix argument, find whole trees with timestamps before
 today and archive them (after getting confirmation from the user).
 If the cursor is not at a headline when these commands are called, try all level
 1 trees.  If the cursor is on a headline, only try the direct children of
 this heading.

 Patched to keep the previous hierarchy at time of archival."
   (interactive "P")
   (if (and (org-region-active-p) org-loop-over-headlines-in-active-region)
	(let ((cl (if (eq org-loop-over-headlines-in-active-region 'start-level)
		      'region-start-level 'region))
	      org-loop-over-headlines-in-active-region)
	  (org-map-entries
	   `(progn (setq org-map-continue-from (progn (org-back-to-heading) (point)))
		   (org-archive-subtree ,find-done))
	   org-loop-over-headlines-in-active-region
	   cl (if (outline-invisible-p) (org-end-of-subtree nil t))))
     (cond
      ((equal find-done '(4))  (org-archive-all-done))
      ((equal find-done '(16)) (org-archive-all-old))
      (t
	;; Save all relevant TODO keyword-relatex variables
	(let* ((tr-org-todo-keywords-1 org-todo-keywords-1)
	       (tr-org-todo-kwd-alist org-todo-kwd-alist)
	       (tr-org-done-keywords org-done-keywords)
	       (tr-org-todo-regexp org-todo-regexp)
	       (tr-org-todo-line-regexp org-todo-line-regexp)
	       (tr-org-odd-levels-only org-odd-levels-only)
	       (this-buffer (current-buffer))
	       (time (format-time-string
		      (substring (cdr org-time-stamp-formats) 1 -1)))
	       (file (abbreviate-file-name
		      (or (buffer-file-name (buffer-base-buffer))
			  (error "No file associated to buffer"))))
	       (location (org-get-local-archive-location))
	       (afile (or (org-extract-archive-file location)
			  (error "Invalid `org-archive-location'")))
	       (heading (org-extract-archive-heading location))
	       (infile-p (equal file (abbreviate-file-name (or afile ""))))
	       (newfile-p (and (org-string-nw-p afile)
			       (not (file-exists-p afile))))
	       (buffer (cond ((not (org-string-nw-p afile)) this-buffer)
			     ((find-buffer-visiting afile))
			     ((find-file-noselect afile))
			     (t (error "Cannot access file \"%s\"" afile))))
	       level datetree-date datetree-subheading-p)
	  (when (string-match "\\`datetree/" heading)
	    ;; Replace with ***, to represent the 3 levels of headings the
	    ;; datetree has.
	    (setq heading (replace-regexp-in-string "\\`datetree/" "***" heading))
	    (setq datetree-subheading-p (> (length heading) 3))
	    (setq datetree-date (org-date-to-gregorian
				 (or (org-entry-get nil "CLOSED" t) time))))
	  (if (and (> (length heading) 0)
		   (string-match "^\\*+" heading))
	      (setq level (match-end 0))
	    (setq heading nil level 0))
	  (save-excursion
	    (org-back-to-heading t)
	    ;; Get context information that will be lost by moving the
	    ;; tree.  See `org-archive-save-context-info'.
	    (let* ((all-tags (org-get-tags-at))
		   (local-tags (org-get-tags))
		   (inherited-tags (org-delete-all local-tags all-tags))
		   (old-path (org-get-outline-path))
		   (context
		    `((category . ,(org-get-category nil 'force-refresh))
		      (file . ,file)
		      (itags . ,(mapconcat #'identity inherited-tags " "))
		      (ltags . ,(mapconcat #'identity local-tags " "))
		      (olpath . ,(mapconcat #'identity
					    (org-get-outline-path)
					    "/"))
		      (time . ,time)
		      (todo . ,(org-entry-get (point) "TODO")))))
	      ;; We first only copy, in case something goes wrong
	      ;; we need to protect `this-command', to avoid kill-region sets it,
	      ;; which would lead to duplication of subtrees
	      (let (this-command) (org-copy-subtree 1 nil t))
	      (set-buffer buffer)
	      ;; Enforce Org mode for the archive buffer
	      (if (not (derived-mode-p 'org-mode))
		  ;; Force the mode for future visits.
		  (let ((org-insert-mode-line-in-empty-file t)
			(org-inhibit-startup t))
		    (call-interactively 'org-mode)))
	      (when (and newfile-p org-archive-file-header-format)
		(goto-char (point-max))
		(insert (format org-archive-file-header-format
				(buffer-file-name this-buffer))))
	      (when datetree-date
		(require 'org-datetree)
		(org-datetree-find-date-create datetree-date)
		(org-narrow-to-subtree))
	      ;; Force the TODO keywords of the original buffer
	      (let ((org-todo-line-regexp tr-org-todo-line-regexp)
		    (org-todo-keywords-1 tr-org-todo-keywords-1)
		    (org-todo-kwd-alist tr-org-todo-kwd-alist)
		    (org-done-keywords tr-org-done-keywords)
		    (org-todo-regexp tr-org-todo-regexp)
		    (org-todo-line-regexp tr-org-todo-line-regexp)
		    (org-odd-levels-only
		     (if (local-variable-p 'org-odd-levels-only (current-buffer))
			 org-odd-levels-only
		       tr-org-odd-levels-only)))
		(goto-char (point-min))
		(outline-show-all)

		(let (search-limit)
		  (-map-indexed
		   (lambda (i element)
		     (unless (re-search-forward
			      (concat "^"
				      (apply 'concat (-repeat (+ i 1) "\\*"))
				      " "
				      (regexp-quote element)
				      "[ \t]*\\(:[[:alnum:]_@#%:]+:\\)?[ \t]*\\($\\|\r\\)") ;; \\{" i "\\}
			      search-limit t)
		       (goto-char (or search-limit (point-max)))
		       (or (bolp) (insert "\n"))
		       (let ((str (concat (apply 'concat (-repeat (+ i 1) "*")) " " element "\n")))
			 (when search-limit
			   (setq search-limit (+ search-limit (length str))))
			 (insert str)))
		     (setq search-limit
			   (or (save-excursion
				 (if (re-search-forward
				      (concat "^" (apply 'concat (-repeat (+ i 1) "\\*")) " ") search-limit t)
				     (match-beginning 0)))
			       search-limit)))
		   old-path))

		;; (if (and heading (not (and datetree-date (not datetree-subheading-p))))
		;; 	  (progn
		;; 	    (if (re-search-forward
		;; 		 (concat "^" (regexp-quote heading)
		;; 			 "[ \t]*\\(:[[:alnum:]_@#%:]+:\\)?[ \t]*\\($\\|\r\\)")
		;; 		 nil t)
		;; 		(goto-char (match-end 0))
		;; 	      ;; Heading not found, just insert it at the end
		;; 	      (goto-char (point-max))
		;; 	      (or (bolp) (insert "\n"))
		;; 	      ;; datetrees don't need too much spacing
		;; 	      (insert (if datetree-date "" "\n") heading "\n")
		;; 	      (end-of-line 0))
		;; 	    ;; Make the subtree visible
		;; 	    (outline-show-subtree)
		;; 	    (if org-archive-reversed-order
		;; 		(progn
		;; 		  (org-back-to-heading t)
		;; 		  (outline-next-heading))
		;; 	      (org-end-of-subtree t))
		;; 	    (skip-chars-backward " \t\r\n")
		;; 	    (and (looking-at "[ \t\r\n]*")
		;; 		 ;; datetree archives don't need so much spacing.
		;; 		 (replace-match (if datetree-date "\n" "\n\n"))))
		;; 	;; No specific heading, just go to end of file.
		;; 	(goto-char (point-max))
		;; 	;; Subtree narrowing can let the buffer end on
		;; 	;; a headline.  `org-paste-subtree' then deletes it.
		;; 	;; To prevent this, make sure visible part of buffer
		;; 	;; always terminates on a new line, while limiting
		;; 	;; number of blank lines in a date tree.
		;; 	(unless (and datetree-date (bolp)) (insert "\n")))

		(or (bolp) (insert "\n"))
		;; Paste
		(org-paste-subtree (org-get-valid-level (length old-path) 1))
		;; Shall we append inherited tags?
		(and inherited-tags
	      	     (or (and (eq org-archive-subtree-add-inherited-tags 'infile)
	      		      infile-p)
	      		 (eq org-archive-subtree-add-inherited-tags t))
	      	     (org-set-tags-to all-tags))
		;; Mark the entry as done
		(when (and org-archive-mark-done
	      		   (let ((case-fold-search nil))
	      		     (looking-at org-todo-line-regexp))
	      		   (or (not (match-end 2))
	      		       (not (member (match-string 2) org-done-keywords))))
	      	  (let (org-log-done org-todo-log-states)
	      	    (org-todo
	      	     (car (or (member org-archive-mark-done org-done-keywords)
	      		      org-done-keywords)))))

		;; Add the context info.
		(dolist (item org-archive-save-context-info)
	      	  (let ((value (cdr (assq item context))))
	      	    (when (org-string-nw-p value)
	      	      (org-entry-put
	      	       (point)
	      	       (concat "ARCHIVE_" (upcase (symbol-name item)))
	      	       value))))
		(widen)
		;; Save and kill the buffer, if it is not the same
		;; buffer.
		(unless (eq this-buffer buffer) (save-buffer))
		)))
	  ;; Here we are back in the original buffer.  Everything seems
	  ;; to have worked.  So now run hooks, cut the tree and finish
	  ;; up.
	  (run-hooks 'org-archive-hook)
	  (let (this-command) (org-cut-subtree))
	  (when (featurep 'org-inlinetask)
	    (org-inlinetask-remove-END-maybe))
	  (setq org-markers-to-move nil)
	  (message "Subtree archived %s"
		   (if (eq this-buffer buffer)
		       (concat "under heading: " heading)
		     (concat "in file: " (abbreviate-file-name afile)))))))
     (org-reveal)
     (if (looking-at "^[ \t]*$")
   	  (outline-next-visible-heading 1))))
Exporting and Publishing

To export blocks with syntax coloring we need the htmlize package.

(use-package htmlize
  :ensure t
  :defer t)
Ditaa
Presentations with Reveal.js
(use-package ox-reveal
  :ensure t
  :defer t)
Capture
Templates
 (use-package org-capture
   :ensure org
   :defer t
   :bind
   (("C-c c" . leoc/org-capture-clockable-interruption)
    ("C-c j j" . leoc/org-capture-journal-day)
    ("C-c j a" . leoc/org-capture-journal-accomplishment)
    ("C-c j n" . leoc/org-capture-journal-note)
    ("C-c r" . leoc/org-capture-reading)
    ("C-c m" . leoc/org-capture-mail)
    ("C-c n" . leoc/org-capture-note)
    ("C-c t" . leoc/org-capture-task))
   :config
   (progn
     (defun leoc/org-capture-clockable-interruption ()
	(interactive)
	(org-capture nil "c"))

     (defun leoc/org-capture-journal-day ()
	(interactive)
	(org-capture nil "jj"))
     (defun leoc/org-capture-journal-note ()
	(interactive)
	(org-capture nil "jn"))
     (defun leoc/org-capture-journal-accomplishment ()
	(interactive)
	(org-capture nil "ja"))

     (defun leoc/org-capture-task ()
	(interactive)
	(org-capture nil "t"))

     (defun leoc/org-capture-reading ()
	(interactive)
	(org-capture nil "r"))

     (defun leoc/org-capture-mail ()
	(interactive)
	(org-capture nil "m"))

     (defun leoc/org-capture-note ()
	(interactive)
	(org-capture nil "n"))

     (defvar leoc/web-last-blog-post-title nil
	"This variable contains the last blog post title captured to be added to a blog post template.")

     (defun leoc/web-blog-post-file (path)
	(setq leoc/web-last-blog-post-title (read-string "Title: "))
	(expand-file-name (format "%s-%s.org"
				  (format-time-string "%Y-%m-%d")
				  (downcase (s-replace " " "-" leoc/web-last-blog-post-title)))
			  path))

     (defun leoc/get-last-web-post-title ()
	leoc/web-last-blog-post-title)

     (setq org-capture-templates
	    '(
	      ("b" "Web Bookmark" entry (file+headline "~/.org/refile.org" "Bookmarks") "* %c\n:PROPERTIES:\n:CREATED: %U\n:END:\n%i")
	      ("t" "Remember" entry (file+headline "~/.org/refile.org" "Inbox") "* TODO %?%c\n:PROPERTIES:\n:CREATED: %U\n:END:")
	      ("r" "Reading" entry (file+headline "~/.org/refile.org" "Readings") "* READ %?%c :read:\n:PROPERTIES:\n:CREATED: %U\n:END:")
	      ("n" "Note" entry (file+headline "~/.org/refile.org" "Notes") "* %?%c\n:PROPERTIES:\n:CREATED: %U\n:END:")
	      ("c" "Clockable Interruption" entry (file+headline "~/.org/refile.org" "Inbox") "* %u %?\nADDED: %U" :clock-in t :clock-resume t)
	      ("f" "Food" entry (file+headline "~/.org/track_food.org" "Food") "* %u %?")
	      ("l" "Link to current clocking task" checkitem (clock) "- %?%c" :immediate-finish t)
	      ("j" "Journal")
	      ("jr" "Review" plain (file+datetree "~/.org/journal.org") (file "~/.org/templates/review"))
	      ("ja" "Accomplishment" entry (file+datetree "~/.org/journal.org") "* %u Accomplished: %?")
	      ("jj" "Simple Entry" entry (file+datetree "~/.org/journal.org") "* %u %?")
	      ("w" "Today I Learned Post" plain (file (leoc/web-blog-post-file "/home/arthur/projects/andersen.berlin/blog/_posts")) "---\nlayout: post\ntitle: %(leoc/get-last-web-post-title)\ntags:\n  - til\n---\n\n%?" :unnarrowed t)
	      ("m" "Respond to mail" entry (file "~/.org/refile.org") "* NEXT Respond to %:fromname on \"%:subject\" ([[%l][Link]])\nSCHEDULED: %^t\n\n%?" :immediate-finish t)))))
Refile after capture

Some capturing templates should initiate a refile upon finalizing the capturing process.

 (defun leoc/refile-maybe ()
   (let ((key (org-capture-get :key)))
     (when (member key '("b" "t" "c" "m"))
	(org-refile))))

 (add-hook 'org-capture-before-finalize-hook 'leoc/refile-maybe)
Protocol

Org-protocol allows capturing from outside Emacs. I use it to capture things via Chromium User Scripts which makes it easy to capture web bookmarks, todos (e.g. read book/article, check out this library, etc.).

(use-package org-protocol
  :config
  (defun leoc/org-protocol-capture-p ()
    "Return true if this capture was initiated via org-protocol."
    (equal "emacs-capture" (frame-parameter nil 'name)))
  (defun leoc/org-capture-delete-frame ()
    "Delete frame if capture was initiated via org-protocol."
    (when (leoc/org-protocol-capture-p)
      (delete-frame)))

  (defun leoc/org-capture-delete-other-windows ()
    "Make sure frame has only one window if capture was initiated via org-protocol."
    (when (leoc/org-protocol-capture-p)
      (delete-other-windows)))

  (add-hook 'org-capture-mode-hook 'leoc/org-capture-delete-other-windows)
  (add-hook 'org-capture-after-finalize-hook 'leoc/org-capture-delete-frame)

  (defadvice org-switch-to-buffer-other-window (after org-capture-supress-window-splitting activate)
    "Delete the extra window if we're in a capture frame."
    (leoc/org-capture-delete-other-windows))

  (defadvice org-capture (around org-capture-protocol-ignore-error activate)
    "If in emacs-capture buffer, ignore errors when quitting capture."
    (if (leoc/org-protocol-capture-p)
        (unless (ignore-errors ad-do-it t)
          (leoc/org-capture-delete-frame))
      ad-do-it)))

When capturing a larger chunk of text from the browser, this text should be captured with markup. The package org-protocol-capture-html uses Pandoc to create org-mode markup.

(use-package org-protocol-capture-html
  :ensure org
  :load-path "vendor/org-protocol-capture-html")
Habits
(use-package org-habit
  :ensure org
  :demand t
  :config
  (setq org-habit-graph-column 104
        org-habit-following-days 4
        org-habit-preceding-days 21
        org-habit-show-done-always-green nil))
Contacts
(use-package org-contacts
  :ensure org
  :demand t
  :config
  (setq org-contacts-files '("~/.org/contacts.org")))
Encryption
(use-package org-crypt
  :ensure org
  :defer t
  :config
  (progn
  (org-crypt-use-before-save-magic)
  (add-to-list 'org-tags-exclude-from-inheritance "crypt")
  ;; GPG key to use for encryption
  ;; Either the Key ID or set to nil to use symmetric encryption.
  (setq org-crypt-key "id_rsa")))
Babel

Do not prompt to confirm evaluation.

(setq org-confirm-babel-evaluate nil)
(with-eval-after-load 'org
  (org-babel-do-load-languages
    'org-babel-load-languages
    '((emacs-lisp . t)
      (dot . t)
      (ditaa . t)
      (python . t)
      (ruby . t)
      (gnuplot . t)
      (clojure . t)
      (shell . t)
      (ledger . t)
      (org . t)
      (plantuml . t)
      (latex . t))))
org-passwords
(require 'org-passwords)
(setq org-passwords-file "/home/arthur/.org/passwords.org.gpg")
(setq org-passwords-random-words-dictionary "/etc/dictionaries-common/words")
Velaluqa

For Velaluqa I have some custom defaults to generate beautiful documents.

(load "~/projects/velaluqa/documents/templates/emacs.el")
Templates
(add-to-list 'org-structure-template-alist
             (list "p" ":PROPERTIES:\n?\n:END:"))
Redmine Sync Binding

I use org-mode to track all my issues. Currently I use org-redmine.rb to synchronize clocks and new issues to Redmine.

There is a bi-directional sync in the works, but it still does not work as it should. So right now only:

  • sync of clocks to time entries in the respective project
  • creation of new issues from headlines the format of: \* TODO # - Title of the issue :@bug:
 (defun leoc/org-redmine-sync (&optional prefix)
   "Run org-redmine sync command for the last X days given by PREFIX."
   (interactive "P")
   (save-some-buffers)
   (if prefix
	(let ((from-timestamp (format-time-string "%Y-%m-%d" (time-subtract (current-time) (seconds-to-time (* prefix 24 60 60)))))
	      (to-timestamp (format-time-string "%Y-%m-%d" (current-time))))
	  (shell-command (concat "urxvt -e bash --login -c \"cd /home/arthur/projects/org-redmine-time-transfer; ./org-redmine sync --date " from-timestamp "--" to-timestamp ";\"")) nil nil)
     (shell-command (concat "urxvt -e bash --login -c \"cd /home/arthur/projects/org-redmine-time-transfer; ./org-redmine sync;\"") nil nil))
   (kill-buffer "*Shell Command Output*"))

 (bind-key "C-c o s" 'leoc/org-redmine-sync)

Accounting with Ledger

Ledger is a powerful, double-entry accounting system that is accessed from the UNIX command-line with a great Emacs integration.

(use-package ledger-mode
  :ensure t
  :defer t
  :mode ("\\.ledger$" . ledger-mode))

(bind-key "C-c l l" '(lambda ()  (interactive) (dired "~/.ledger/")))

e-Mail

(use-package mu4e
  :load-path "/usr/local/share/emacs/site-lisp/mu4e"
  :config
  (progn
    (require 'smtpmail)

    (defun leoc/html2text ()
      "Replacement for standard html2text using shr."
      (interactive)
      (let ((dom (libxml-parse-html-region (point-min) (point-max))))
        (erase-buffer)
        (shr-insert-document dom)
        (goto-char (point-min))))

    (setq send-mail-function 'smtpmail-send-it

          mu4e-get-mail-command "mbsync -a"
          mu4e-update-interval 60

          mu4e-maildir "/home/arthur/.mail/"

          mu4e-use-fancy-chars t

          ;; don't save message to Sent Messages, Gmail/IMAP takes care of this
          mu4e-sent-messages-behavior 'sent
          mu4e-confirm-quit nil

          ;; Try to display images in mu4e
          mu4e-view-show-images t
          mu4e-view-image-max-width 800

          mu4e-compose-dont-reply-to-self t
          ;; use 'fancy' non-ascii characters in various places in mu4e
          mu4e-use-fancy-chars nil

          ;; save attachment to my desktop (this can also be a function)
          mu4e-attachment-dir "~/Attachments"

          user-full-name "Arthur Leonard Andersen"
          mu4e-headers-date-format "%d.%b %Y %H:%M" ; date format

          mu4e-html2text-command 'leoc/html2text

          message-kill-buffer-on-exit t
          message-send-mail-function 'smtpmail-send-it
          mail-user-agent 'mu4e-user-agent

          ;; Remove signatures
          message-signature ""
          mu4e-compose-signature-auto-include nil
          mu4e-compose-signature ""

          ;; Make sure UIDs are not duplicated.
          ;; Otherwise mbsync would lament and stop syncing.
          mu4e-change-filenames-when-moving t)

    <<leoc/mu4e-config>>
    ))
User Interface
Header Fields
(setq mu4e-headers-fields '((:maildir      . 30)
                            (:date         . 19)
                            (:flags        . 6)
                            (:from-or-to   . 28)
                            (:mailing-list . 20)
                            (:subject      . nil)))
Header Tag Marks
Mark NameTextSymbol
mu4e-headers-draft-markDD
mu4e-headers-flagged-markFF
mu4e-headers-new-markNN
mu4e-headers-passed-markPP
mu4e-headers-replied-markRR
mu4e-headers-seen-markSS
mu4e-headers-trashed-markTT
mu4e-headers-attach-markaa
mu4e-headers-encrypted-markxx
mu4e-headers-signed-markss
mu4e-headers-unread-markuu
(mapcar '(lambda (mark)
	    (let ((variable (nth 0 mark))
		  (text (nth 1 mark))
		  (symbol (nth 2 mark)))
	      `(setq ,(intern variable) '(,text . ,symbol))))
	  headers-marks)
Thread Prefix Markers
(setq mu4e-headers-has-child-prefix (purecopy '("+"  . "└┬")))
(setq mu4e-headers-empty-parent-prefix (purecopy '("-"  . "─")))
(setq mu4e-headers-first-child-prefix (purecopy '("\\" . "├")))
(setq mu4e-headers-duplicate-prefix (purecopy '("="  . "═")))
(setq mu4e-headers-default-prefix (purecopy '("|"  . "├")))
Behaviour
Org-Mime
(use-package org-mu4e
  :config
  (setq org-mu4e-convert-to-html t))
Bookmarks
(setq mu4e-bookmarks '(("flag:unread AND NOT flag:trashed"      "Unread messages"      ?u)
                       ("date:today..now AND NOT flag:trashed"  "Today's messages"     ?t)
                       ("date:7d..now AND NOT flag:trashed"     "Last 7 days"          ?w)
                       ("mime:image/*"                          "Messages with images" ?p)))
Maildir Shortcuts
(setq mu4e-maildir-shortcuts '(("/gmail/Inbox"          . ?s)
                               ("/icloud/Inbox"         . ?d)
                               ("/tuberlin/Inbox"       . ?f)
                               ("/gmail/Sent"           . ?w)
                               ("/icloud/Sent"          . ?e)
                               ("/tuberlin/Sent"        . ?r)
                               ("/gmail/Trash"          . ?x)
                               ("/icloud/Trash"         . ?c)
                               ("/tuberlin/Trash"       . ?v)))
Citation Behaviour
(setq message-cite-reply-position 'above
      message-citation-line-function 'message-insert-formatted-citation-line
      message-citation-line-format "----- original message -----\nOn %a, %b %d %Y, %f wrote:\n")
Smart Refiling
(load "~/.mu4e-refile-assocs.el")
(setq mu4e-refile-folder
      '(lambda (msg)
        (let* ((maildir (mu4e-message-field msg :maildir))
               (account (my-mu4e-find-account 'mu4e-maildir-prefix maildir))
               (maildir-prefix (my-mu4e-account-value account 'mu4e-maildir-prefix))
               (maildir-postfix (catch 'found
                                  (dolist (assoc my-mu4e-refile-assocs)
                                    (let ((postfix (car assoc))
                                          (sender-list (cdr assoc)))
                                      (dolist (sender sender-list)
                                        (when (mu4e-message-contact-field-matches msg :from sender)
                                          (throw 'found postfix))))))))
          (if maildir-postfix
              (concat maildir-prefix "/" maildir-postfix)
            (concat maildir-prefix "/Archive")))))
Encryption
(add-hook 'mu4e-compose-mode-hook 'epa-mail-mode)
(add-hook 'mu4e-view-mode-hook 'epa-mail-mode)
Accounts

Mu4e does not support multiple accounts by default, so I have to trick around a bit, to have a multiple accounts working the way as I want them to work.

My e-Mail Addresses

First mu4e needs to be able to distinguish between my own e-Mail addresses and the addresses of other people.

(load "~/.mu4e-my-email-addresses.el")

(setq mu4e-user-mail-address-list mu4e-my-email-addresses)
Account Defaults
(setq mu4e-maildir-prefix "/gmail"
      mu4e-sent-folder "/Sent"
      mu4e-drafts-folder "/Drafts"
      mu4e-trash-folder  "/Trash"
      message-signature ""
      user-mail-address "leoc.git@gmail.com"
      smtpmail-default-smtp-server "smtp.gmail.com"
      smtpmail-local-domain "gmail.com"
      smtpmail-smtp-server "smtp.gmail.com"
      starttls-use-gnutls t
      message ""
      smtpmail-smtp-service 587)
Multi-Account Extensions
(defvar my-mu4e-account-alist nil
  "Defines all mu4e accounts.")

(load "~/.mu4e-accounts.el")

(defun my-mu4e-find-account (variable value)
  "Find the first account that match VARIABLE with VALUE.

The VALUE may be a sequence aswell, where the first account is returned,
which VARIABLE value is a member of the VALUE sequence."
  (car (find-if #'(lambda (account)
                    (let* ((account-vars (cdr account))
                           (variable-value (cadr (assoc variable account-vars))))
                      (cond ((listp value)
                             (member variable-value value))
                            ((eq variable 'mu4e-maildir-prefix)
                             (string-match variable-value value))
                            (t (equal variable-value value)))))
                my-mu4e-account-alist)))

(defun my-mu4e-account-value (account var)
  "Find the value for a given ACCOUNT VAR."
  (let ((account-vars (cdr (assoc account my-mu4e-account-alist)))
        value)
    (if account-vars
        (mapc #'(lambda (pair)
                  (if (eq (car pair) var)
                      (setq value (cadr pair))))
              account-vars))
    value))

(defun my-mu4e-set-account-variables (account)
  "Set the account variables for given email ACCOUNT."
  (let ((account-vars
         (cdr (assoc account my-mu4e-account-alist))))
    (if account-vars
        (mapc #'(lambda (var)
                  (set (car var) (cadr var)))
              account-vars)
      (error (format "No email account found: %S" account)))))

(defadvice mu4e~get-folder (before load-corresponding-account (foldervar msg))
  (when msg
    (let* ((maildir (mu4e-message-field msg :maildir))
           (account (my-mu4e-find-account 'mu4e-maildir-prefix maildir)))
      (my-mu4e-set-account-variables account))))

(ad-activate 'mu4e~get-folder)

(defun my-mu4e-set-account-for-composition ()
  "Ask for and set the account to compose a new message with."
  (let* ((account (if mu4e-compose-parent-message
                      (let ((maildir (mu4e-message-field mu4e-compose-parent-message :maildir)))
                        (my-mu4e-find-account 'mu4e-maildir-prefix maildir))
                    (completing-read (format "Compose with account: (%s) "
                                             (mapconcat #'(lambda (var) (car var)) my-mu4e-account-alist "/"))
                                     (mapcar #'(lambda (var) (car var)) my-mu4e-account-alist)
                                     nil t nil nil (caar my-mu4e-account-alist)))))
    (my-mu4e-set-account-variables account)))

(add-hook 'mu4e-compose-pre-hook 'my-mu4e-set-account-for-composition)
Contacts
(add-to-list 'mu4e-headers-actions
             '("org-contact-add" . mu4e-action-add-org-contact) t)
(add-to-list 'mu4e-view-actions
             '("org-contact-add" . mu4e-action-add-org-contact) t)
Completion via Mailaprop

Mailaprop extracts all mail addresses from the mail folder and creates an .eld file with an index.

 (setq mailaprop-address-file (expand-file-name "~/private/mailaprop/mailaprop-addresses.eld"))
 (load-file (expand-file-name "~/.emacs.d/vendor/mailaprop/mailaprop.el"))

 (setq mailaprop-drop-address-regexps
	(list
	 "member@paypal.com"
	 "member@paypal.de"
	 "=\?.*\?=" ; never want to email Uncle Fester
	 ))

 (when (featurep 'mailaprop)
   (mailaprop-load-addresses))
Functions
Extract names from e-mail

This one is used by a yasnippet that automatically expands a greeting text for mails.

(defun leoc/mu4e-get-names-for-yasnippet ()
  "Return comma separated string of names for an email"
  (interactive)
  (let ((email-name "") str email-string email-list email-name2 tmpname)
    (save-excursion
      (goto-char (point-min))
      ;; first line in email could be some hidden line containing NO to field
      (setq str (buffer-substring-no-properties (point-min) (point-max))))
    ;; take name from TO field - match series of names
    (when (string-match "^To: \"?\\(.+\\)" str)
      (setq email-string (match-string 1 str)))
    ;;split to list by comma
    (setq email-list (split-string email-string " *, *"))
    ;;loop over emails
    (dolist (tmpstr email-list)
      ;;get first word of email string
      (setq tmpname (car (split-string tmpstr " ")))
      ;;remove whitespace or ""
      (setq tmpname (replace-regexp-in-string "[ \"]" "" tmpname))
      ;;join to string
      (setq email-name
            (concat email-name ", " tmpname)))
    ;;remove initial comma
    (setq email-name (replace-regexp-in-string "^, " "" email-name))

    ;;see if we want to use the name in the FROM field
    ;;get name in FROM field if available, but only if there is only
    ;;one name in TO field
    (if (< (length email-list) 2)
        (when (string-match "^\\([^ ,\n]+\\).+writes:$" str)
          (progn (setq email-name2 (match-string 1 str))
                 ;;prefer name in FROM field if TO field has "@"
                 (when (string-match "@" email-name)
                   (setq email-name email-name2))
                 )))
    email-name))

Miscellaneous

Searching the Web with Google
(defun leoc/search-google ()
  "Googles a query or region if any."
  (interactive)
  (let ((term (if mark-active
                  (buffer-substring (region-beginning) (region-end))
                (read-string "Google: "))))
    (browse-url
     (concat "http://www.google.com/search?ie=utf-8&oe=utf-8&q="
             (url-hexify-string term)))))

(global-set-key (kbd "C-c g") 'leoc/search-google)
Searching the dict.leo.org
(defun leoc/search-dict ()
  "Looks up in a dictionary. Query or region if any."
  (interactive)
  (let ((term (if mark-active
                  (buffer-substring (region-beginning) (region-end))
                (read-string "Dict: "))))
    (call-process
     "surf" nil 0 nil (concat
                       "http://dict.leo.org/ende?lp=ende&search="
                       (url-hexify-string term)))))

(global-set-key (kbd "C-c C-g") 'leoc/search-dict)
Configure Emacs
Open Emacs File

Sometimes I want to quickly change something in Emacs.

(defun leoc/open-init-emacs ()
  (interactive)
  (find-file-other-window "~/.emacs.d/init-emacs.org"))

(bind-key "C-c 0" 'leoc/open-init-emacs)

Experiments

mu4e yasnippet helper functions