NOTE: This post was originally posted on the 18.02.2017 and got updated on the 17.04.2017

I recently discovered the text editor Emacs. This is of course a bit ironic since Emacs has been around for ages (actually since 1976).

I've tried it a few years ago, before I started using Vim. However at that point it just seemed too annoying with it's weird keyboard shortcuts and Vim seemed much more interesting. Over the years I started to enjoy working with plain text files more and more, from note taking to simple task management.

When I found out that org-mode existed it just seemed too brilliant to not give Emacs another try. It turns out that Emacs is quite a great piece of software and for a Linux user like myself it feels actually quite natural once you spend a bit more time with it.

First of all it's very configurable. Not as easy as one would expect if you're used to working with the usual Linux config files. But Emacs's configuration is much more powerful than anything I've ever seen so far. One thing which helped me quite a bit with the configuration is understanding the basics of the programming language Elisp. You don't have to be able to write tons of code in Elisp but it helps quite a bit if you know the "syntax" of it.

Secondly it has a built in package manager which allows you to download various plugins.

What I like as well is that it is available on Windows which I have to use at work and the configuration works more or less on both Windows and Linux without changing anything and for the places where it doesn't work one can add separate configs for each system so they only get loaded where they are needed.

In the following sections I want to show you how I configured Emacs so far. Both on Windows and on Linux. Which is basically the same except for some workarounds for Windows. Instructions on how to use Emacs are better found elsewhere but I find it useful to share my configs with the world since I often benefit myself if someone else does the same.

People often say that Emacs is not just an editor, it's an operating system. This is really not that far of. Emacs even has it's own package manager. So let's go ahead and use it.

By default Emacs is looking for the .emacs file in your home directory which contains your configuration. Emacs writes settings in that file as well which can make it a bit messy. For this reason I've split my configuration into multiple files which then get called from the main .emacs file.

In the case of the packages settings I've created a file called packages.el in the .emacs.d folder in my home directory. To load the file I had to add this line to the .emacs file.

(load "~/.emacs.d/packages.el")

Inside the packages.el file I've added the following lines. Which provide the location of the MELPA, ELPA and org-mode repository and enable the package manager.

In addition it checks if a package called "use-package" is installed and if it isn't installs it.

use-package 1 is a nice little tool which helps you with organizing your packages. For one thing it will check if all the packages specified in the configuration are installed and if not it will download and install them. In addition it will load the packages only if they are needed. This helps to keep Emacs's startup times reasonable. It can help as well with key bindings for the various packages and many more things. I highly recommend that you check out it's documentation.

;; --- Packages ---

(require 'package)
(setq package-enable-at-startup nil)

;; -- Repositories --

;; MELPA
(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/"))
(when (< emacs-major-version 24)
  ;; For important compatibility libraries like cl-lib
  (add-to-list 'package-archives '("gnu" . "http://elpa.gnu.org/packages/")))

;; org-mode repository
(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t)

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

If you want to use Emacs on Windows with this configuration make sure that you download the dependencies for it: Emacs Dependencies To install simply extract over your current Emacs installation. You will see that the zip includes directories which are already present in the Emacs installation just overwrite them. If you don't install the dependencies you want be able to use SSL connections under Windows and maybe some other things won't work.

With the above configuration use-package will install missing packages automatically. It's quite likely though that you would want to manually install packages.

To update the package list you have to execute M-x package-list-packages [RET] which downloads the newest package list. Similar to an sudo apt update on a Debian based Linux system.

To install a package you can then execute M-x package-install [RET] which will prompt you for the name of the package you want to install. Since I was using Vim before Emacs I'm going to install a package called evil-mode. This packages provides nearly the full Vim experience inside Emacs. After Emacs downloaded the package we have to activate it so that it gets loaded at each start of Emacs. To achieve this we can add this lines to the packages.el file:

;; evil-mode
(use-package evil
    :ensure t
    :config
    (evil-mode 1))

Now every time we start Emacs we can use the familiar Vim key bindings.

Let's do the same thing with the package php-mode because I have to write a lot of PHP code at the moment and Emacs doesn't provide syntax highlighting by default for it. To have it loaded we only have to add:

;; enable php-mode
(use-package php-mode
  :ensure t
  :mode ("\\.php\\'" . php-mode))

To the packages.el file after we've installed it from ELPA. With this configuration use-package will ensure that php-mode is present and will enable it every time we open a .php file.

My current packages.el contains many more lines which I will explain partially in the following sections. All of the packages have a short comment with an explanation about it's function, however.

;; --- Packages ---

(require 'package)
(setq package-enable-at-startup nil)

;; -- Repositories --

;; MELPA
(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/"))
(when (< emacs-major-version 24)
  ;; For important compatibility libraries like cl-lib
  (add-to-list 'package-archives '("gnu" . "http://elpa.gnu.org/packages/")))

;; org-mode
(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t)

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

;; evil-mode allows to use vim keybindings
(use-package evil
    :ensure t
    :config
    (evil-mode 1))

;; enable php-mode for php syntax highlighting and more
(use-package php-mode
  :ensure t
  :mode ("\\.php\\'" . php-mode))

;; enable auto-completion
(use-package auto-complete
    :ensure t
    :config
    (global-auto-complete-mode t))

;; relative line numbers
(use-package relative-line-numbers
    :ensure t
    :config
    (add-hook 'prog-mode-hook 'relative-line-numbers-mode t)
    (add-hook 'prog-mode-hook 'line-number-mode t)
    (add-hook 'prog-mode-hook 'column-number-mode t))

;; smooth scrolling
(use-package smooth-scrolling
    :ensure t
    :config
    (setq scroll-margin 1
    scroll-conservatively 9999
    scroll-step 1))

;; web-mode for general web development
(use-package web-mode
    :ensure t
    :config
    (add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.tpl\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.[agj]sp\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.as[cp]x\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
    (defun toggle-php-flavor-mode ()
      (interactive)
      "Toggle mode between PHP & Web-Mode Helper modes"
      (cond ((string= mode-name "PHP/l")
             (web-mode))
            ((string= mode-name "Web")
             (php-mode))))
    (global-set-key [f5] 'toggle-php-flavor-mode))

;; enable magit a great git porcelain.
(use-package magit
    :ensure t
    :commands magit-status
    :bind
    ("C-c g" . magit-status))

;; extend IDO with fussy search
(use-package flx-ido
  :ensure t
  :init
  ;; enable IDO
  (ido-mode 1)
  (setq ido-everywhere t)
  :config
  (flx-ido-mode 1)
  (setq ido-enable-flex-matching t)
  (setq ido-use-faces nil))

;; auctex a greate plugin for latex writing
(use-package tex
  :ensure auctex
  :config
    (setq TeX-auto-save t)
    (setq TeX-parse-self t)
    (setq-default TeX-master nil)
    (add-hook 'plain-TeX-mode-hook
        (lambda () (set (make-variable-buffer-local ’TeX-electric-math)
        (cons "$" "$"))))
    (add-hook 'LaTeX-mode-hook
        (lambda () (set (make-variable-buffer-local ’TeX-electric-math)
                        (cons "\\(" "\\)"))))
    (setq LaTeX-electric-left-right-brace t))

;; Enable pretty bullets in org mode
(use-package org-bullets
    :ensure t
    :config
    (add-hook 'org-mode-hook (lambda ()
                               (org-bullets-mode 1))))

;; which key is a package to show which keys can be pressed
(use-package which-key
  :ensure t
  :diminish which-key-mode
  :config
  (which-key-mode))

;; change the colours of parenthesis the further out they are
(use-package rainbow-delimiters
  :ensure t
  :config
  (add-hook 'prog-mode-hook #'rainbow-delimiters-mode))

;; add plantuml-mode to draw diagramms
(use-package plantuml-mode
  :ensure t
  :config
  (setq plantuml-jar-path "~/.emacs.d/plantuml.jar")
  (add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode)))

;; add olivetti writing mode to center the buffer
(use-package olivetti
  :ensure t
  :bind
  ("C-c o" . olivetti-mode))

;; add markdown-mode to edit markdown files
(use-package markdown-mode
  :ensure t
  :commands (markdown-mode gfm-mode)
  :mode (("README\\.md\\'" . gfm-mode)
         ("\\.md\\'" . markdown-mode)
         ("\\.markdown\\'" . markdown-mode))
  :init (setq markdown-command "multimarkdown"))

Emacs is mainly used in the GUI, from Vim I'm used to work in the terminal which provides a nice distraction free environment. Luckily Emacs let's you configure every single bit. So we can make it look and feel like a terminal and configure various other details. I've created for the theme and GUI settings an additional file called theme.el in my .emacs.d directory. To load it I had to add the follow line to the .emacs file.

(load "~/.emacs.d/theme.el")

Inside the theme.el file I've added various settings which change the following things:

  • load the solarized theme
  • disable the toolbar
  • hide the menu bar
  • hide the scroll bar
  • enable line wrapping
  • disable the line markers on the side
  • match parentheses
  • disable the splash screen
  • start weeks in the calender on Monday
  • enable IDO
  • disable various prompts
  • highlight bad whitespace
  • configure the font based on the operating system

To be able to use the solarized theme we need to install two packages. color-theme can be found in the MELPA repository and emacs-color-theme-solarized can be found on github: https://github.com/sellout/emacs-color-theme-solarized

color-theme can be installed by using the integrated package manager of Emacs as described in the Packages section. To load the package I've added this lines to the theme.el file:

;; Color theme
(use-package color-theme
    :ensure t
    :config
    (color-theme-initialize))

To install emacs-color-theme-solarized you simply get it with the built in package manager and then add this lines to the theme.el file:

;; load solarized color theme
(use-package color-theme-solarized
    :init
    (setq frame-background-mode (quote light))
    (add-to-list 'load-path "~/git_repos/emacs-color-theme-solarized")
    :config
    (load-theme 'solarized t))

The last theme related package we're going to install is whitespace As before get it from MELPA and then add the following lines to the theme.el file:

;; highlight bad whitespace
(use-package whitespace
    :ensure t
    :config
    (setq whitespace-style '(face lines-tail tabs trailing))
    (global-whitespace-mode t))

Emacs will now highlight trailing whitespace or tabs on empty lines.

The rest of the configurations are part of a standard Emacs installation.

I think besides IDO the settings should be clear. So let me quickly explain what IDO does. IDO extends the functionality of the mini-buffer to give various previews of the available options. For example: When you want to switch a buffer you'll get a list of all the currently open buffers. Or if you want to open a file you get a list of all the available files in the currently selected directory. It has many more options and makes working with Emacs quite a bit more comfortable.

As mentioned the fonts get loaded depending on the operating system 17 Emacs is run on this is a simple if statement which shouldn't be a problem for anyone familiar with coding so I will only show the code here:

;; set default font

; for Linux
(if (eq system-type 'gnu/linux)
    (set-face-attribute 'default nil :font "Source Code Pro 14"))
; for windows
(if (eq system-type 'windows-nt)
    (set-face-attribute 'default nil :font "Consolas 14"))

You can see the full content of the theme.el file here:

;; Color theme
(use-package color-theme
    :ensure t
    :config
    (color-theme-initialize))

;; load solarized color theme
(use-package color-theme-solarized
    :init
    (setq frame-background-mode (quote light))
    (add-to-list 'load-path "~/git_repos/emacs-color-theme-solarized")
    :config
    (load-theme 'solarized t))

;; Various UI changes

;; disable menu and toolbar
(tool-bar-mode -1)
(menu-bar-mode -99)
(scroll-bar-mode -1)

; Proper line wrapping
(global-visual-line-mode 1)

; Matches parentheses and such in every mode
(show-paren-mode 1)

; Disable fringe because I use visual-line-mode
(set-fringe-mode '(0 . 0))

; Disable splash screen
(setq inhibit-splash-screen t)

; Calender should start on Monday
(setq calendar-week-start-day 1)

(tooltip-mode -1)
(setq tooltip-use-echo-area t)

;; disable or reconfigure prompts
(fset 'yes-or-no-p 'y-or-n-p) ;; remap yes or no to y or n
(setq confirm-nonexistent-file-or-buffer nil);; just create buffers don't ask
(setq ido-create-new-buffer 'always)
(setq vc-follow-symlinks t);; always follow symlinks

;; highlight bad whitespace
(use-package whitespace
    :ensure t
    :config
    (setq whitespace-style '(face lines-tail tabs trailing))
    (global-whitespace-mode t))

;; set default font

; for linux
(if (eq system-type 'gnu/linux)
    (set-face-attribute 'default nil :font "Source Code Pro 14"))
; for windows
(if (eq system-type 'windows-nt)
    (set-face-attribute 'default nil :font "Consolas 14"))

Org-mode 5 has it's own repository which I've added to my packages.el file. Please check the Packages section if you want to know how exactly I did that. After that you can install it like any other package from MELPA and like the other packages I'm configuring it in one huge use-package block.

;; --- org-mode config ---

(use-package org
    :ensure t
    :config
    ....)

Org-mode itself provides a huge amount of options. However I only configured a few of those those by hand. I recommend that you have a look at it's configuration menu with M-x org-customize [RET] and configure it this way. For a beginner like me it's certainly the easiest option. When I changed a setting with org-customize I'm moving the configuration into my org-mode.el file. This way the .emacs file stays clean and I have a nicely commented file.

I'm not going to explain every singe configuration I've done to org-mode because that would be too much. I'm going to explain the important or interesting ones however. Most importantly it contains the key bindings for a few org-mode functions:

;; enable org-mode keys
(define-key global-map "\C-ca" 'org-agenda)
(global-set-key "\C-cl" 'org-store-link)
(global-set-key "\C-cc" 'org-capture)
(global-set-key "\C-cb" 'org-iswitchb)

I've added an option to extend the todo keywords.

;; extend the work flow states
(setq org-todo-keywords
        '((sequence "TODO" "NEXT" "WAITING" "|" "DONE" "CANCELED")))

An option to replace the usual stars of org-mode with intends which makes for cleaner files if you have to look at them without Emacs.

;; enable org-indent
(setq org-startup-indented t)

And an input template to easily input pictures for a LaTeX export.

(eval-after-load 'org
'(progn
     (add-to-list 'org-structure-template-alist
'("p" "#+ATTR_LATEX: :center\n[[]]" "<src lang=\"?\">\n\n</src>"))))

The following two lines remove all the todo keywords and tags when you export the org file to another format. This is very handy because it allows you to still use the tags and todo keywords to mark sections as work in progress without cluttering your final result.

;; disable the Todo keywords in the export
(setq org-export-with-todo-keywords nil)

;; disable the tags in the export
(setq org-export-with-tags nil)

Last but not least two quite handy options. The first one lets you refile a section under every heading with a level higher than 6 and the second one lets you add a heading or todo item without splitting the current line in half. Without this option the part of the line after your cursor will become part of the new heading. For me this makes very little sense that's why I disable this option. You can find the rest of my org-mode configuration after this code snippets.

;; org-refile options
    (setq org-refile-allow-creating-parent-nodes (quote confirm))
    (setq org-refile-targets (quote ((org-agenda-files :maxlevel . 6))))

;; disable line split with M-RET
(setq org-M-RET-may-split-line (quote ((default))))

;; --- org-mode config ---

(use-package org
    :ensure t
    :config
    ;; enable org-mode keys
    (define-key global-map "\C-ca" 'org-agenda)
    (global-set-key "\C-cl" 'org-store-link)
    (global-set-key "\C-cc" 'org-capture)
    (global-set-key "\C-cb" 'org-iswitchb)

    ;; extend the workflow states
    (setq org-todo-keywords
            '((sequence "TODO" "NEXT" "WAITING" "|" "DONE" "CANCELLED")))

    ;; enable org-indent
    (setq org-startup-indented t)

    ;; input templates
    (eval-after-load 'org
    '(progn
        (add-to-list 'org-structure-template-alist
                     '("p" "#+ATTR_LATEX: :center\n[[]]" "<src lang=\"?\">\n\n</src>"))))

    ;; capture templates
    (setq org-capture-templates
    (quote
    (("i" "IBZ Journal entry" plain
      (file+datetree "~/03_documents/notes/ibz/ibz_journal.org"))
     ("j" "Journal entry" plain
      (file+datetree "~/03_documents/notes/journal.org"))
     ("t" "Adds a Next entry" entry
      (file+headline "~/03_documents/notes/personal.org" "Tasks")
      (file "~/03_documents/notes/templates/temp_personal_todo.txt")))))

    ;; org-columns format
    (setq org-columns-default-format
     "%40ITEM(Task) %8Effort(Estimated Effort){:} %8CLOCKSUM %10TAGS")

    ;; available effort times
    (setq org-global-properties
     (quote
      (("Effort_ALL" . "0 0:10 0:30 1:00 2:00 3:00 4:00 5:00 6:00 7:00"))))

    ;; org-export formats
    (setq org-export-backends (quote (ascii beamer html icalendar latex md odt)))

    ;; disable the Todo keywords in the export
    (setq org-export-with-todo-keywords nil)

    ;; disable the tags in the export
    (setq org-export-with-tags nil)

    ;; options for beamer exports
    (setq org-beamer-frame-level 2)
    (setq org-beamer-outline-frame-options "")
    (setq org-beamer-outline-frame-title "Inhalt")
    (setq org-beamer-theme "metropolis")
    ;; options for latex exports
    (setq org-latex-classes
    (quote
    (("beamer" "\\documentclass{az_beamer}"
        ("\\section{%s}" . "\\section*{%s}")
        ("\\subsection{%s}" . "\\subsection*{%s}")
        ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
        ("article" "\\documentclass{az_article}"
        ("\\section{%s}" . "\\section*{%s}")
        ("\\subsection{%s}" . "\\subsection*{%s}")
        ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
        ("\\paragraph{%s}" . "\\paragraph*{%s}")
        ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
        ("report" "\\documentclass[11pt]{report}"
        ("\\part{%s}" . "\\part*{%s}")
        ("\\chapter{%s}" . "\\chapter*{%s}")
        ("\\section{%s}" . "\\section*{%s}")
        ("\\subsection{%s}" . "\\subsection*{%s}")
        ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
        ("book" "\\documentclass[11pt]{book}"
        ("\\part{%s}" . "\\part*{%s}")
        ("\\chapter{%s}" . "\\chapter*{%s}")
        ("\\section{%s}" . "\\section*{%s}")
        ("\\subsection{%s}" . "\\subsection*{%s}")
        ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))))
    (setq org-latex-default-packages-alist nil)
    (setq org-latex-title-command "\\maketitle\\newpage")
    (setq org-latex-toc-command "\\tableofcontents
    \\newpage
    ")
    ;; org-refile options
    (setq org-refile-allow-creating-parent-nodes (quote confirm))
    (setq org-refile-targets (quote ((org-agenda-files :maxlevel . 6))))
    ;; disable line split with M-RET
    (setq org-M-RET-may-split-line (quote ((default))))
)

Since Emacs is so highly configurable everyone ends up with his own custom functions. This section will explain the functions I'm currently using. As before I will focus on the interesting ones. For this purpose I've created a file called functions.el in my .emacs.d directory the code it contains is at the end of this section. To load this file you have to add this line to the .emacs file:

(load "~/.emacs.d/functions.el")

13

By default Emacs provides no function to toggle split windows between vertical and horizontal orientation. However this is something which I want to be able to do and luckily it's quite easy to achieve with this code:

;; a function to toggle the splits
(defun toggle-window-split ()
  (interactive)
  (if (= (count-windows) 2)
      (let* ((this-win-buffer (window-buffer))
         (next-win-buffer (window-buffer (next-window)))
         (this-win-edges (window-edges (selected-window)))
         (next-win-edges (window-edges (next-window)))
         (this-win-2nd (not (and (<= (car this-win-edges)
                     (car next-win-edges))
                     (<= (cadr this-win-edges)
                     (cadr next-win-edges)))))
         (splitter
          (if (= (car this-win-edges)
             (car (window-edges (next-window))))
          'split-window-horizontally
        'split-window-vertically)))
    (delete-other-windows)
    (let ((first-win (selected-window)))
      (funcall splitter)
      (if this-win-2nd (other-window 1))
      (set-window-buffer (selected-window) this-win-buffer)
      (set-window-buffer (next-window) next-win-buffer)
      (select-window first-win)
      (if this-win-2nd (other-window 1))))))

(define-key ctl-x-map "4" 'toggle-window-split)

The function gets mapped to the key combination C-x 4. It doesn't work in all the modes at the moment but I couldn't find a solution to this so far.

;; a function to toggle the splits
(defun toggle-window-split ()
  (interactive)
  (if (= (count-windows) 2)
      (let* ((this-win-buffer (window-buffer))
         (next-win-buffer (window-buffer (next-window)))
         (this-win-edges (window-edges (selected-window)))
         (next-win-edges (window-edges (next-window)))
         (this-win-2nd (not (and (<= (car this-win-edges)
                     (car next-win-edges))
                     (<= (cadr this-win-edges)
                     (cadr next-win-edges)))))
         (splitter
          (if (= (car this-win-edges)
             (car (window-edges (next-window))))
          'split-window-horizontally
        'split-window-vertically)))
    (delete-other-windows)
    (let ((first-win (selected-window)))
      (funcall splitter)
      (if this-win-2nd (other-window 1))
      (set-window-buffer (selected-window) this-win-buffer)
      (set-window-buffer (next-window) next-win-buffer)
      (select-window first-win)
      (if this-win-2nd (other-window 1))))))

(define-key ctl-x-map "4" 'toggle-window-split)

15

Because I'm writing both in German (Swiss grammar) and English I need two dictionaries for spell checking. This configuration allows me to do this with the ispell-change-dictionary function.

;; ispell settings
(setenv "DICTIONARY" "en_US")
(setq ispell-program-name "hunspell")
(setq ispell-local-dictionary "en_US")
(setq ispell-local-dictionary-alist
      '(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_US") nil utf-8)
        ("de_CH" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "de_CH") nil utf-8)))

16

At work I often have to write emails some of which can get quite lengthy. Because I hate it when people send me emails with very long lines I try to be a leading example and write the longer emails in Emacs. When I'm finished with them I reformat them with gq (Vim keybindings). Which triggers a function which to wrap the selected paragraphs to a reasonable line length. I then copy the final result into Outlook. To easily achieve this I use this function which is mapped to CTRL-Shift C

;; copy the complete buffer to the clipboard
(defun copy-all ()
    "Copy entire buffer to clipboard"
    (interactive)
    (clipboard-kill-ring-save (point-min) (point-max)))

(global-set-key (kbd "C-S-c") 'copy-all)

Since I have to use Windows at work and sometimes at school I've started to use a windowsfunctions.el file which contains all the Windows specific configuration which doesn't belong to one of the other files.

14

On Linux this is rather easily done with the option -mm (emacs -mm). On Windows it needs an additional functional to have it working. For this I've added the following code to my functions.el file.

(defun maximize-frame ()
  "Maximizes the active frame in Windows"
  (interactive)
  ;; Send a `WM_SYSCOMMAND' message to the active frame with the
  ;; `SC_MAXIMIZE' parameter.
  (when (eq system-type 'windows-nt)
    (w32-send-sys-command 61488)))
(add-hook 'window-setup-hook 'maximize-frame t)

Thanks to John Hilliard 2 I've found a way to add links which point to Emails in Outlook to my org-mode files. This is really handy to keep track of things even when you follow the concept of "Zero Inbox".

To achieve this you have to add this configuration to Emacs: Please note that it contains the path to the OUTLOOK.EXE file which you might have to change depending on the version of Office your company is using.

;;; org-outlook.el - Support for links to Outlook items in Org

(org-add-link-type "outlook" 'org-outlook-open)

(defun org-outlook-open (id)
   "Open the Outlook item identified by ID.  ID should be an Outlook GUID."
   (w32-shell-execute "open" "C:/Program Files (x86)/Microsoft Office/Office14/OUTLOOK.EXE" (concat "/select " "outlook:" id)))

(provide 'org-outlook)

In Outlook you have to create a VBA script with the following code which copies the link to the email into the clipboard I've changed John's code slightly because our ticketing system uses brackets in the subject line which would break the link:

'Adds a link to the currently selected message to the clipboard
Sub AddLinkToMessageInClipboard()

   Dim objMail As Outlook.MailItem
   Dim doClipboard As New DataObject

   'One and ONLY one message muse be selected
   If Application.ActiveExplorer.Selection.Count <> 1 Then
       MsgBox ("Select one and ONLY one message.")
       Exit Sub
   End If

   Set objMail = Application.ActiveExplorer.Selection.Item(1)
   doClipboard.SetText "outlook:" + objMail.EntryID
   doClipboard.PutInClipboard

End Sub

Like John I've got an error when I first executed the script his fix worked quite well however so here it is:

  1. In the VBA editor click “Tools” then “References” in the menu.
  2. Check “Microsoft Forms 2.0 Object Library” in the list of available references.
  3. This option wasn’t available to me at first so I clicked “Browse” Then I opened “c:\windows\system32\FM20.DLL” Then I clicked “OK”

Afterwards you can create a button in Outlook which executes the VBA script. When you clicked on the button you can then create a link in Emacs and paste the clipboard into the link destination.

Because I work on multiple systems at work I wanted to have a portable version of Emacs. Luckily Emacs for Windows is more or less portable by default. To make it truly portable you have to create a directory called "home" inside the "bin" directory of the emacs installation. This directory will be the home directory for your Emacs installation. Means that the .emacs file and the .emacs.d folder have to go there.

Next we create a file called site-start.el in share/emacs/site-lisp which contains the following code:

(defvar full-path (expand-file-name invocation-directory)) (defvar
home-dir (concat full-path "home/")) (setenv "HOME" home-dir)

This checks from which directory Emacs was run and then sets the home variable to that path + home/ . Now you can simply copy the main Emacs directory where every you want and have all it's configurations moved with it.

The final result then lookes like this: img img

  1. https://github.com/jwiegley/use-package
  2. http://jfh.me/post/65485740773/linking-directly-to-outlook-messages-using
  3. https://www.masteringemacs.org
  4. http://sachachua.com/blog/2013/05/how-to-learn-emacs-a-hand-drawn-one-pager-for-beginners/
  5. http://orgmode.org/
  6. https://www.emacswiki.org/emacs/
  7. https://www.youtube.com/watch?v=SzA2YODtgK4
  8. https://www.youtube.com/watch?v=oJTwQvgfgMM
  9. https://www.youtube.com/watch?v=sQS06Qjnkcc&list=PLVtKhBrRV_ZkPnBtt_TD1Cs9PJlU0IIdE
  10. https://stackoverflow.com/questions/10216148/elisp-copy-buffer-to-clipboard#10216310
  11. https://github.com/skuro/plantuml-mode
  12. http://plantuml.com/
  13. https://www.emacswiki.org/emacs/ToggleWindowSplit
  14. https://masteringemacs.org/article/maximizing-emacs-startup
  15. https://emacs.stackexchange.com/questions/21378/spell-check-with-multiple-dictionaries#21379
  16. https://stackoverflow.com/questions/10216148/elisp-copy-buffer-to-clipboard#10216310
  17. https://stackoverflow.com/questions/1817257/how-to-determine-operating-system-in-elisp#1817318

Next Post Previous Post