-- coding: utf-8 --

April 12, 2018 · View on GitHub

#+TITLE: Emacs Configuration

This is my Emacs configuration.

  • Content :TOC_3:
  • [[#notes][Notes]]
  • [[#inspiration][Inspiration]]
  • [[#installation][Installation]]
  • [[#packages][Packages]]
    • [[#sources][Sources]]
    • [[#installation-1][Installation]]
    • [[#updates][Updates]]
  • [[#configuration-helpers][Configuration Helpers]]
  • [[#tweaking-defaults][Tweaking Defaults]]
    • [[#disabled-commands][Disabled Commands]]
    • [[#yes-or-no][Yes or No]]
    • [[#symlinks][Symlinks]]
    • [[#display-line-numbers][Display Line Numbers]]
    • [[#final-newline][Final Newline]]
    • [[#backup][Backup]]
    • [[#auto-save][Auto-Save]]
    • [[#keystrokes][Keystrokes]]
    • [[#scroll][Scroll]]
    • [[#auto-revert][Auto revert]]
    • [[#garbage-collection][Garbage Collection]]
    • [[#browser][Browser]]
    • [[#line-filling][Line Filling]]
    • [[#whitespace-cleanup][Whitespace Cleanup]]
    • [[#buffers-and-frames][Buffers and Frames]]
    • [[#ido][Ido]]
    • [[#sudo-save][Sudo Save]]
    • [[#flyspell][Flyspell]]
    • [[#occur][Occur]]
    • [[#dired][Dired]]
    • [[#org-mode][Org-Mode]]
      • [[#settings][Settings]]
      • [[#toc-org][TOC-Org]]
    • [[#kill-buffers][Kill Buffers]]
  • [[#additional-functionality][Additional Functionality]]
    • [[#ace-window][Ace Window]]
    • [[#smex][Smex]]
    • [[#browse-kill-ring][Browse-Kill-Ring]]
    • [[#crux][Crux]]
    • [[#docker][Docker]]
    • [[#ag][Ag]]
    • [[#ripgrep][Ripgrep]]
    • [[#evil][Evil]]
      • [[#states][States]]
      • [[#evil-surround][Evil Surround]]
      • [[#free-keys][Free Keys]]
    • [[#god-mode][God Mode]]
    • [[#which-key][Which-Key]]
    • [[#projectile][Projectile]]
    • [[#ivy-counsel-and-swiper][Ivy, Counsel and Swiper]]
    • [[#pdf-tools][PDF-Tools]]
    • [[#xdg-open][XDG-open]]
    • [[#mu4e][Mu4e]]
      • [[#general][General]]
      • [[#headers][Headers]]
      • [[#view][View]]
      • [[#bookmarks][Bookmarks]]
      • [[#compose][Compose]]
      • [[#send][Send]]
      • [[#contexts][Contexts]]
  • [[#programming][Programming]]
    • [[#general-purpose][General Purpose]]
      • [[#company][Company]]
      • [[#brackets][Brackets]]
      • [[#dumb-jump][Dumb Jump]]
      • [[#flycheck][Flycheck]]
      • [[#git][Git]]
      • [[#indentation][Indentation]]
      • [[#rainbow][Rainbow]]
      • [[#yasnippet][YASnippet]]
    • [[#c][C++]]
    • [[#css][CSS]]
    • [[#go][Go]]
    • [[#haml][Haml]]
    • [[#haskell][Haskell]]
    • [[#javascript][JavaScript]]
      • [[#autocompletion][Autocompletion]]
      • [[#js2-mode][JS2-mode]]
      • [[#tern][Tern]]
      • [[#eslint][Eslint]]
    • [[#json][JSON]]
    • [[#lua][Lua]]
    • [[#markdown][Markdown]]
    • [[#php][PHP]]
    • [[#python][Python]]
      • [[#elpy][Elpy]]
      • [[#auto-completion][Auto Completion]]
      • [[#pipenv][Pipenv]]
    • [[#emacs-speaks-statistics][Emacs speaks Statistics]]
    • [[#ruby][Ruby]]
      • [[#inf-ruby][Inf-ruby]]
      • [[#ruby-mode][Ruby Mode]]
      • [[#robe][Robe]]
      • [[#rspec-mode][Rspec-mode]]
      • [[#projectile-rails][Projectile Rails]]
      • [[#autocompletion-1][Autocompletion]]
    • [[#shell][Shell]]
    • [[#tex][TeX]]
    • [[#web-mode][Web mode]]
      • [[#autocompletion-2][Autocompletion]]
    • [[#yaml][Yaml]]
  • [[#keybindings][Keybindings]]
    • [[#not-user-reserved][Not User-Reserved]]
    • [[#user-reserved][User-Reserved]]
    • [[#state-specific][State Specific]]
  • [[#user-interface][User Interface]]
    • [[#default-face][Default Face]]
    • [[#diminish][Diminish]]
    • [[#doom-modeline][Doom Modeline]]
      • [[#settings-1][Settings]]
      • [[#segments][Segments]]
      • [[#setup][Setup]]
    • [[#color-themes][Color Themes]]
    • [[#fancy-stuff][Fancy stuff]]
    • [[#frame-title][Frame Title]]
    • [[#tooltips][Tooltips]]
  • Notes

Some functions I should use more often:

  • Use =evil-window= commands (e.g. =C-w j=)
  • Use =C-c u= more often (=counsel-imenu=).
  • Use =C-c p 5 f= to open a file in a new frame with projectile.
  • Use =``= to jump back and forth.
  • Use =m = to create markers =` = to go to marker.
  • Use =C-i= (=jump-forward=) and =C-o= (=jump-backward=).
  • The font-size can be adjusted buffer-locally with =C-x C-+= and =C-x C--=.

Packages to check out:

Other things to check out and problems to deal with:

  • Inspiration
  • Installation

#+BEGIN_SRC shell cd /gitcd ~/git git clone http://github.com/sirpscl/emacs.d $ ln -s ~/git/emacs.d ~/.emacs.d #+END_SRC

Some important and noteworthy dependencies:

After the first start, run the following commands.

#+BEGIN_SRC lisp (jedi:install-server) #+END_SRC

  • Packages ** Sources

Use the =gnu= (official) and =melpa= (unofficial) archives.

#+BEGIN_SRC emacs-lisp (require 'package) (setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/") ("melpa" . "https://melpa.org/packages/"))) (package-initialize) #+END_SRC

** Installation

Install packages on demand. This is cleaner and easier to keep tidy than defining a huge list of packages at the beginning of the configuration.

#+BEGIN_SRC emacs-lisp (defun ph/install-package (package) "Install PACKAGE if not yet installed." (unless (package-installed-p package) (progn (package-refresh-contents) (package-install package)))) #+END_SRC

** Updates

Update all packages with =M-x auto-package-update-now=.

#+BEGIN_SRC emacs-lisp (ph/install-package 'auto-package-update) (require 'auto-package-update) (setq auto-package-update-interval 7) #+END_SRC

To calculate the number of available updates, =package-refresh-contents= needs to be executed. Doing this periodically is annoying since it will block emacs. I therefore use the following function to query the number of =auto-package-update-interval= since the last update for my status bar so that I remember to update my packages regularly.

#+BEGIN_SRC emacs-lisp (defun ph/update-intervals-since-last-update () "Return the number of auto-update-package-intervals since the last update." (when (file-exists-p auto-package-update-last-update-day-path) (/ (- (apu--today-day) (apu--read-last-update-day)) auto-package-update-interval))) #+END_SRC

  • Configuration Helpers

[[https://github.com/noctuid/general.el][General]] provides a more convenient method for binding keys in emacs (for both evil and non-evil users).

#+BEGIN_SRC emacs-lisp (ph/install-package 'general) #+END_SRC

Other Helpers:

#+BEGIN_SRC emacs-lisp (defun ph/call-rotate (fn lst) "Call FN with first element of the LST. Returns the rotated list." (let ((args (car lst))) (funcall fn args) (append (cdr lst) (cons args ())))) #+END_SRC

  • Tweaking Defaults

This section contains customizations of Emacs' default settings and built-in packages configuration and extensions.

** Disabled Commands

Enable all disabled commands.

#+BEGIN_SRC emacs-lisp (setq disabled-command-function nil) #+END_SRC

** Yes or No

For reasons of simplicity.

#+BEGIN_SRC emacs-lisp (defalias 'yes-or-no-p 'y-or-n-p) #+END_SRC

** Symlinks

Always Follow Symlinks, no questions asked.

#+BEGIN_SRC emacs-lisp (setq vc-follow-symlinks t) #+END_SRC

** Display Line Numbers

Show line numbers in all text and programming buffers.

#+BEGIN_SRC emacs-lisp (add-hook 'text-mode-hook 'display-line-numbers-mode) (add-hook 'prog-mode-hook 'display-line-numbers-mode) #+END_SRC

Count the number of lines to use for line number width.

#+BEGIN_SRC emacs-lisp (setq display-line-numbers-width-start t) #+END_SRC

** Final Newline

Automatically add a newline at the end of a file.

#+BEGIN_SRC emacs-lisp (setq require-final-newline t) #+END_SRC

** Backup

No backups, commit frequently!

#+BEGIN_SRC emacs-lisp (setq make-backup-files nil) #+END_SRC

** Auto-Save

Store auto-saves in =/tmp=

#+BEGIN_SRC emacs-lisp (setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t))) #+END_SRC

** Keystrokes

Show my keystrokes almost immediately in the echo-area.

#+BEGIN_SRC emacs-lisp (setq echo-keystrokes 0.1) #+END_SRC

** Scroll

When scrolling, keep the cursor at the same position.

#+BEGIN_SRC emacs-lisp (setq scroll-preserve-screen-position 'keep) #+END_SRC

** Auto revert

When something changes a file, automatically refresh the buffer containing that file so they can't get out of sync.

#+BEGIN_SRC emacs-lisp (global-auto-revert-mode t) #+END_SRC

Update vc-info when reverting (e.g. after changing branch). Note that this may cause performance issues when many buffers are present.

#+BEGIN_SRC emacs-lisp (setq auto-revert-check-vc-info t) #+END_SRC

** Garbage Collection

Collect garbage after 20MB. Some packages which cache a lot (e.g. =flx-ido=) will profit.

#+BEGIN_SRC emacs-lisp (setq gc-cons-threshold (* 20 1000 1000)) #+END_SRC

** Browser

Use Firefox to browse URLs.

#+BEGIN_SRC emacs-lisp (setq browse-url-browser-function 'browse-url-generic browse-url-generic-program "firefox" browse-url-generic-args '("--private-window") browse-url-new-window-flag t) #+END_SRC

** Line Filling

Use a line width of 80 columns.

#+BEGIN_SRC emacs-lisp (setq-default fill-column 80) #+END_SRC

To reorganize a paragraph to fit the 80 columns, use =M-q= (=M-x fill-paragraph=) and/or enable =auto-fill-mode=.

Don't do double-spaces between sentences.

#+BEGIN_SRC emacs-lisp (setq-default sentence-end-double-space nil) #+END_SRC

To undo paragraph and region reorganization. Stolen from [[https://www.emacswiki.org/emacs/UnfillParagraph][here]].

#+BEGIN_SRC emacs-lisp (defun ph/unfill-paragraph (&optional region) "Takes a multi-line paragraph and makes it into a single line of text." (interactive (progn (barf-if-buffer-read-only) '(t))) (let ((fill-column (point-max)) ;; This would override `fill-column' if it's an integer. (emacs-lisp-docstring-fill-column t)) (fill-paragraph nil region))) #+END_SRC

** Whitespace Cleanup

Delete trailing whitespaces when saving.

#+BEGIN_SRC emacs-lisp (add-hook 'write-file-hooks 'delete-trailing-whitespace) #+END_SRC

** Buffers and Frames

Split functions which open the previous buffer in the new window instead of showing the current buffer twice. [[http://www.alandmoore.com/blog/2013/05/01/better-window-splitting-in-emacs/][Stolen shamelessly from here]]

#+BEGIN_SRC emacs-lisp (defun ph/vsplit-last-buffer () (interactive) (split-window-vertically) (other-window 1 nil) (switch-to-next-buffer))

(defun ph/hsplit-last-buffer () (interactive) (split-window-horizontally) (other-window 1 nil) (switch-to-next-buffer)) #+END_SRC

A function to open the previous buffer in a new frame.

#+BEGIN_SRC emacs-lisp (defun ph/open-last-buffer () (interactive) (switch-to-buffer-other-frame (other-buffer))) #+END_SRC

** Ido

[[https://www.emacswiki.org/emacs/InteractivelyDoThings][Ido ("interactively do things")]] supercharges Emacs' completion system. I use =ido= everywhere =ivy= is not set up.

#+BEGIN_SRC emacs-lisp (ido-mode 1) (ido-everywhere 1) #+END_SRC

Enable the built-in fuzzy-matching

#+BEGIN_SRC emacs-lisp (setq ido-enable-flex-matching t) #+END_SRC

[[https://github.com/creichert/ido-vertical-mode.el][ido-vertical-mode]] makes ido-mode display vertically.

#+BEGIN_SRC emacs-lisp (ph/install-package 'ido-vertical-mode) (ido-vertical-mode 1) (setq ido-vertical-define-keys 'C-n-and-C-p-only) (setq ido-vertical-show-count t) #+END_SRC

** Sudo Save

If the current buffer is not writable, ask if it should be saved with sudo.

#+BEGIN_SRC emacs-lisp (defun ph/sudo-file-name (filename) "Prepend '/sudo:root@system-name:' to FILENAME if appropriate. If the file already has a tramp prefix, return nil." (when (and filename (not (file-remote-p filename))) (format "/sudo:root@%s:%s" (system-name) filename)))

(defun ph/sudo-save-buffer () "Save buffer as root if the user approves." (let ((filename (ph/sudo-file-name (buffer-file-name)))) (when (and filename (yes-or-no-p (format "Save file as %s ? " filename))) (write-file filename))))

(advice-add 'save-buffer :around '(lambda (fn &rest args) (when (or (not (buffer-file-name)) (not (buffer-modified-p)) (file-writable-p (buffer-file-name)) (not (ph/sudo-save-buffer))) (call-interactively fn args)))) #+END_SRC

** Flyspell

[[https://www.emacswiki.org/emacs/FlySpell][Flyspell]] enables on-the-fly spell checking in Emacs by the means of a minor mode. Flyspell highlights incorrect words as soon as they are completed or as soon as the TextCursor hits a new word.

[[https://github.com/d12frosted/flyspell-correct][Flyspell-Correct]] offers distraction-free words correction with flyspell via selected interface.

#+BEGIN_SRC emacs-lisp (ph/install-package 'flyspell-correct-ivy) (setq flyspell-correct-interface #'flyspell-correct-ivy) #+END_SRC

Use Hunspell instead of Aspell.

#+BEGIN_SRC emacs-lisp (setq ispell-program-name "hunspell") #+END_SRC

Rotate through Ispell languages

#+BEGIN_SRC emacs-lisp (setq ph/ispell-dictionaries-list '("en_US" "de_CH"))

(defun ph/ispell-next-dictionary () "Load next Ispell dictionary." (interactive) (setq ph/ispell-dictionaries-list (ph/call-rotate 'ispell-change-dictionary ph/ispell-dictionaries-list)))

(add-hook 'after-init-hook 'ph/ispell-next-dictionary) #+END_SRC

** Occur

[[http://emacswiki.org/emacs/OccurMode][Occur-Mode]] is a search minor-mode that shows a buffer with all matching results in a popup buffer. Use the occur-dwim (do what I mean) function from [[https://oremacs.com/2015/01/26/occur-dwim/][(or emacs irrelevant)]]

#+BEGIN_SRC emacs-lisp (defun ph/occur-dwim () "Call `occur' with a sane default." (interactive) (push (if (region-active-p) (buffer-substring-no-properties (region-beginning) (region-end)) (let ((sym (thing-at-point 'symbol))) (when (stringp sym) (regexp-quote sym)))) regexp-history) (call-interactively 'occur)) #+END_SRC

** Dired

Usage:

  • =a= to open a file or directory in the current buffer
  • =RET= to open a file or directory in a new buffer
  • =o= to open a file or directory in a vertical split buffer
  • =C-o= to open a file or directory in a vertical split buffer but keep the focus in the current buffer.
  • =C-c C-o= to open a file or directory in a new frame.

Reuse buffer

#+BEGIN_SRC emacs-lisp (put 'dired-find-alternate-file 'disabled nil) #+END_SRC

Show all files, in long listing format and human readable units.

#+BEGIN_SRC emacs-lisp (setq-default dired-listing-switches "-lh") #+END_SRC

Open in new frame

#+BEGIN_SRC emacs-lisp (defun ph/dired-find-file-other-frame () "In Dired, visit this file or directory in another window." (interactive) (find-file-other-frame (dired-get-file-for-visit)))

(eval-after-load "dired" '(define-key dired-mode-map (kbd "C-c C-o") 'ph/dired-find-file-other-frame)) #+END_SRC

** Org-Mode

[[https://orgmode.org/][Org-Mode]] is for keeping notes, maintaining TODO lists, planning projects, and authoring documents with a fast and effective plain-text system.

#+BEGIN_SRC emacs-lisp (require 'org) #+END_SRC

*** Settings

Automatically fill lines

#+BEGIN_SRC emacs-lisp (add-hook 'org-mode-hook 'auto-fill-mode) #+END_SRC

Don't ask every time when executing a code block.

#+BEGIN_SRC emacs-lisp (setq org-confirm-babel-evaluate nil) #+END_SRC

Don't indent code blocks

#+BEGIN_SRC emacs-lisp (setq org-edit-src-content-indentation 0) #+END_SRC

No empty lines between items

#+BEGIN_SRC emacs-lisp (setq org-blank-before-new-entry '((heading . nil) (plain-list-item . nil))) #+END_SRC

*** TOC-Org

Every time you’ll be saving an org file, the first headline with a =:TOC:= tag will be updated with the current table of contents.

  • =:TOC_2:= - sets the max depth of the headlines in the table of contents to 2 (the default)
  • =:TOC_2_gh:= - sets the max depth as in above and also uses the GitHub-style hrefs in the table of contents (this style is default). The other supported href style is ‘org’, which is the default org style.

#+begin_src emacs-lisp (ph/install-package 'toc-org) (add-hook 'org-mode-hook 'toc-org-enable) #+end_src

** Kill Buffers

Kill all but the current buffer. [[https://www.emacswiki.org/emacs/KillingBuffers][Stolen shamelessly from here]].

#+BEGIN_SRC emacs-lisp (defun ph/kill-other-buffers () "Kill all other buffers." (interactive) (mapc 'kill-buffer (delq (current-buffer) (buffer-list)))) #+END_SRC

  • Additional Functionality

This section contains some third party packages and additional functionality.

** Ace Window

[[https://github.com/abo-abo/ace-window][Ace-window]] aims to take the speed and predictability of =windmove= and pack it into a single key binding, similar to =other-window=.

#+BEGIN_SRC emacs-lisp (ph/install-package 'ace-window) #+END_SRC

Use the following characters/keys to switch to the windows

#+BEGIN_SRC emacs-lisp (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)) #+END_SRC

Set the ace-window-scope to =frame= because I often have multiple frames opened on other workspaces and only want to jump to other windows in the current frame.

#+BEGIN_SRC emacs-lisp (setq aw-scope 'frame) #+END_SRC

** Smex

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.

#+BEGIN_SRC emacs-lisp (ph/install-package 'smex) #+END_SRC

** Browse-Kill-Ring

#+BEGIN_SRC emacs-lisp (ph/install-package 'browse-kill-ring)

(setq browse-kill-ring-highlight-inserted-item t browse-kill-ring-highlight-current-entry nil browse-kill-ring-show-preview t)

(general-def browse-kill-ring-mode-map "k" 'browse-kill-ring-previous "j" 'browse-kill-ring-forward) #+END_SRC

** Crux

[[https://github.com/bbatsov/crux][A Collection of Ridiculously Useful eXtensions]] for Emacs. crux bundles a few useful interactive commands to enhance your overall Emacs experience.

#+BEGIN_SRC emacs-lisp (ph/install-package 'crux) #+END_SRC

** Docker

#+BEGIN_SRC emacs-lisp (ph/install-package 'dockerfile-mode) #+END_SRC

** Ag

[[https://github.com/Wilfred/ag.el][Ag]] allows you to search using ag from inside Emacs. You can filter by file type, edit results inline, or find files.

#+BEGIN_SRC emacs-lisp (ph/install-package 'ag) #+END_SRC

** Ripgrep

[[https://github.com/dajva/rg.el][Ripgrep (rg)]] is a replacement for both grep like (search one file) and ag like (search many files) tools. It's fast and versatile and written in Rust.

#+BEGIN_SRC emacs-lisp (ph/install-package 'rg) #+END_SRC

** Evil

[[https://github.com/emacs-evil/evil][Evil]] is an extensible vi layer for Emacs. It emulates the main features of Vim, and provides facilities for writing custom extensions.

#+BEGIN_SRC emacs-lisp (ph/install-package 'evil) (require 'evil) (evil-mode 1) #+END_SRC

*** States

Set initial state by major mode.

#+BEGIN_SRC emacs-lisp (dolist (mode-map '((ag-mode . emacs) (calendar-mode . emacs) (elfeed-show-mode . emacs) (elfeed-search-mode . emacs) (eshell-mode . emacs) (flycheck-error-list-mode . emacs) (git-commit-mode . insert) (git-rebase-mode . emacs) (haskell-error-mode . emacs) (haskell-interactive-mode . emacs) (help-mode . emacs) (inferior-ess-mode . emacs) (inf-ruby-mode . emacs) (intero-repl-mode . emacs) (pdf-occur-buffer-mode . emacs) (rspec-compilation-mode . emacs) (shell-mode . emacs) (term-mode . emacs))) (evil-set-initial-state ,(car mode-map) ,(cdr mode-map))) #+END_SRC

*** Evil Surround

  • Add surrounding ​'​ with S'​ from visual-state (use =viw= to mark current word)
  • Change surrounding ​'​ to * with cs'*
  • Remove surrounding * with ds*

#+BEGIN_SRC emacs-lisp (ph/install-package 'evil-surround) (global-evil-surround-mode 1) #+END_SRC

*** Free Keys

Free =M-.= and =M-,​= since they are popular keybindings for "jump to definition" and "back". Also I don't use =evil-complete=.

#+BEGIN_SRC emacs-lisp (general-def 'normal "M-." nil "M-," nil)

(general-def 'insert "C-p" nil "C-n" nil) #+END_SRC

** God Mode

Evil Goddess makes it possible for evil users to conveniently access Emacs keybindings without touching the control and meta key - similar to god-mode.

In order not to loose (hard-coded) which-key support, it is called =god-mode= and thus conflicts with the original =god-mode=.

See [[evil-goddess/README.md]] for more details.

#+BEGIN_SRC emacs-lisp (add-to-list 'load-path "~/.emacs.d/evil-goddess/") (require 'god-mode) #+END_SRC

** Which-Key

[[https://github.com/justbur/emacs-which-key][Which-Key]] is a minor mode for Emacs that displays the key bindings following your currently entered incomplete command (a prefix) in a popup.

#+BEGIN_SRC emacs-lisp (ph/install-package 'which-key) (which-key-mode)

;; (use-package which-key ;; :bind (("C-' k" . which-key-mode) ;; ("C-' C-k" . which-key-mode)) ;; :init ;; (which-key-setup-side-window-bottom) ;; (which-key-enable-god-mode-support) ;; ;; ... ;; (which-key-mode t)) #+END_SRC

Also use which-key evil and god-mode shortcuts.

#+BEGIN_SRC emacs-lisp (setq which-key-allow-evil-operators t) (setq which-key-show-operator-state-maps t) #+END_SRC

Show command names up to 40 columns before cutting them.

#+BEGIN_SRC emacs-lisp (setq which-key-max-description-length 25) #+END_SRC

Show which-key after .4 seconds inactivity

#+BEGIN_SRC emacs-lisp (setq which-key-idle-delay 0.4) #+END_SRC

#+BEGIN_SRC emacs-lisp (which-key-setup-side-window-bottom) (which-key-enable-god-mode-support) (which-key-enable-god-mode-support) #+END_SRC

** Projectile

[[https://github.com/bbatsov/projectile][Projectile]] is a project interaction library for Emacs. Its goal is to provide a nice set of features operating on a project level without introducing external dependencies (when feasible).

#+BEGIN_SRC emacs-lisp (ph/install-package 'projectile) (projectile-mode +1) (general-def projectile-mode-map "C-c p" 'projectile-command-map) (setq projectile-completion-system 'ivy) #+END_SRC

** Ivy, Counsel and Swiper

[[https://github.com/abo-abo/swiper][Ivy, Counsel (and Swiper)]], a collection of Ivy-enhanced versions of common Emacs commands.

  • Ivy is a generic completion mechanism for Emacs.
  • Counsel is a collection of Ivy-enhanced versions of common Emacs commands.
  • Swiper is an Ivy-enhanced alternative to isearch.

Installing =counsel= will also install the other two as dependencies.

#+BEGIN_SRC emacs-lisp (ph/install-package 'counsel) (require 'swiper) #+END_SRC

Use =ivy= for completion instead of =ido=.

#+BEGIN_SRC emacs-lisp (ivy-mode 1) (setq ivy-use-virtual-buffers t) (setq enable-recursive-minibuffers t) #+END_SRC

Some packages need special attention.

#+BEGIN_SRC emacs-lisp (setq magit-completing-read-function 'ivy-completing-read) (setq projectile-completion-system 'ivy) (setq mu4e-completing-read-function 'ivy-completing-read) #+END_SRC

Show current entry number.

#+BEGIN_SRC emacs-lisp (setq ivy-count-format " %d/%d ") #+END_SRC

Prevent swiper from swiping itself.

#+BEGIN_SRC emacs-lisp (defun ph/swiper-from-isearch () (interactive) (unless (string= (symbol-name major-mode) "minibuffer-inactive-mode") (swiper-from-isearch))) #+END_SRC

** PDF-Tools

[[https://github.com/politza/pdf-tools][Pdf-Tools]] is, among other things, a replacement of DocView for PDF files. The key difference is that pages are not pre-rendered by e.g. ghostscript and stored in the file-system, but rather created on-demand and stored in memory.

#+BEGIN_SRC emacs-lisp (ph/install-package 'pdf-tools) (require 'pdf-tools) (pdf-tools-install-noverify) #+END_SRC

When highlighting, automatically add an annotation.

#+BEGIN_SRC emacs-lisp (setq pdf-annot-activate-created-annotations t) #+END_SRC

Zoom by 10%.

#+BEGIN_SRC emacs-lisp (setq pdf-view-resize-factor 1.1) #+END_SRC

Keybindings:

** XDG-open

Open File in External App. [[http://ergoemacs.org/emacs/emacs_dired_open_file_in_ext_apps.html][Stolen shamelessly from here]].

#+BEGIN_SRC emacs-lisp (defun ph/xdg-open (&optional @fname) "Open the current file or dired marked files in external app. The app is chosen from your OS's preference.

When called in emacs lisp, if @fname is given, open that.

URL `http://ergoemacs.org/emacs/emacs_dired_open_file_in_ext_apps.html' Version 2019-01-18" (interactive) (let* ( (filelist(if@fname(progn(list@fname))(if(stringequalmajormode"diredmode")(diredgetmarkedfiles)(list(bufferfilename)))))(file-list (if @fname (progn (list @fname)) (if (string-equal major-mode "dired-mode") (dired-get-marked-files) (list (buffer-file-name))))) (do-it-p (if (<= (length filelist)5)t(yornp"Openmorethan5files?"))))(whenfile-list) 5) t (y-or-n-p "Open more than 5 files? ")))) (when do-it-p (cond ((string-equal system-type "windows-nt") (mapc (lambda (fpath)(w32shellexecute"open"(replaceregexpinstring"/"""fpath) (w32-shell-execute "open" (replace-regexp-in-string "/" "\\" fpath t t))) filelist))((stringequalsystemtype"darwin")(mapc(lambda(file-list)) ((string-equal system-type "darwin") (mapc (lambda (fpath) (shell-command (concat "open " (shell-quote-argument fpath))))fpath)))) file-list)) ((string-equal system-type "gnu/linux") (mapc (lambda (fpath)(let((processconnectiontypenil))(startprocess""nil"xdgopen"fpath) (let ((process-connection-type nil)) (start-process "" nil "xdg-open" fpath))) $file-list)))))) #+END_SRC

** Mu4e

[[https://www.djcbsoftware.nl/code/mu/mu4e.html][Mu4e]] is an emacs-based e-mail client. It’s based on the mu e-mail indexer/searcher. It attempts to be a super-efficient tool to withstand the daily e-mail tsunami.

#+BEGIN_SRC emacs-lisp (require 'mu4e) (require 'mu4e-contrib) (ph/install-package 'smtpmail) #+END_SRC

*** General

Mail directory

#+BEGIN_SRC emacs-lisp (setq mu4e-maildir "~/.mail") #+END_SRC

Save attachments in =~/Downloads/=.

#+BEGIN_SRC emacs-lisp (setq mu4e-attachment-dir "~/Downloads") #+END_SRC

Close mu4e without asking.

#+BEGIN_SRC emacs-lisp (setq mu4e-confirm-quit nil) #+END_SRC

Open mu4e in the current frame or switch to an already existing mu4e-buffer.

#+BEGIN_SRC emacs-lisp (defun ph/mu4e () "Open or switch to mu4e." (interactive) (unless (string-prefix-p "mu4e" (symbol-name major-mode)) (let ((buffer (get-buffer "mu4e-headers"))) (if buffer (switch-to-buffer buffer) (mu4e))))) #+END_SRC

Hide addresses on main view

#+BEGIN_SRC emacs-lisp (setq mu4e-main-buffer-hide-personal-addresses t) #+END_SRC

Hide the annoying indexing message.

#+BEGIN_SRC emacs-lisp (setq mu4e-hide-index-messages t) #+END_SRC

Update every 10 minutes

#+BEGIN_SRC emacs-lisp (setq mu4e-get-mail-command "offlineimap") (setq mu4e-update-interval (* 10 60)) #+END_SRC

For some reason the first two cited faces are equal by default. Let's fix this.

TODO: Find out why the first two mu4e-cited faces are identical

#+BEGIN_SRC emacs-lisp (set-face-attribute 'mu4e-cited-2-face nil :foreground "#5fafd7") #+END_SRC

*** Headers

Custom date and time format.

#+BEGIN_SRC emacs-lisp (setq mu4e-headers-time-format "today %H:%M") (setq mu4e-headers-date-format "%d.%m.%y %H:%M") #+END_SRC

Do not show related messages by default (toggle with =W=)

#+BEGIN_SRC emacs-lisp (setq mu4e-headers-include-related nil) #+END_SRC

Don't show duplicate messages.

#+BEGIN_SRC emacs-lisp (setq mu4e-headers-skip-duplicates t) #+END_SRC

Add default search values for =mu4e-headers-search= unless arguments are given to =mu4e-headers-search= or the search is not called from within a mu4e-buffer. The values are set in the context definition (=ph/mu4e-default-search-expr=).

#+BEGIN_SRC emacs-lisp (advice-add 'mu4e-headers-search :around (lambda (fn &rest args) (if (and (= 0 (length args)) (string-prefix-p "mu4e" (symbol-name major-mode)) (< 0 (length ph/mu4e-default-search-expr))) (apply fn (list (concat ph/mu4e-default-search-expr " ") "Search for: " t)) (apply fn args)))) #+END_SRC

Some functions to get some additional information about emails. [[https://etienne.depar.is/emacs.d/mu4e.html][Stolen shamelessly from here]]

#+BEGIN_SRC emacs-lisp (defun ph/mu4e-get-user-agent (msg) (let ((path (or (mu4e-message-field msg :path) ""))) (if (or (string= path "") (not (file-readable-p path))) "no path found" (let ((xmailer (ph/mu4e-get-mail-header "x-mailer" path)) (useragent (ph/mu4e-get-mail-header "user-agent" path))) (if (string= xmailer useragent) xmailer (cond ((string= xmailer "") useragent) ((string= useragent "") xmailer) (t (concat xmailer " (xmailer)\n" useragent " (user-agent)"))))))))

(defun ph/mu4e-get-mail-header (header-name path) (replace-regexp-in-string "[ \t\n]*" "" (shell-command-to-string (concat "/usr/bin/sed -n '/^" header-name ":/I{:loop t;h;n;/^ /{H;x;s/\\n//;t loop};x;p}' '" path "' | sed -n 's/^" header-name ": \\(.*\\)/\1/Ip'"))))

(add-to-list 'mu4e-header-info-custom '(:useragent . (:name "User-Agent" :shortname "UserAgt." :help "Mail client used by correspondant" :function ph/mu4e-get-user-agent))) #+END_SRC

Set the fields displayed in =mu4e-headers-mode= and =mu4e-view-mode=.

#+BEGIN_SRC emacs-lisp (setq mu4e-headers-fields '((:flags . 4) (:human-date . 15) (:from . 25) (:subject))) #+END_SRC

Ask before I delete something permanently or set the trash flag. I just move messages to the trash folder to "delete" them.

#+BEGIN_SRC emacs-lisp (defun ph/do-or-dont-execute (fn &rest args) "Execute FN (with ARGS) iff I confirm." (when (y-or-n-p "Are you sure? ") (apply fn args)))

(advice-add 'mu4e-headers-mark-for-delete :around 'ph/do-or-dont-execute) (advice-add 'mu4e-view-mark-for-delete :around 'ph/do-or-dont-execute) (advice-add 'mu4e-headers-mark-for-trash :around 'ph/do-or-dont-execute) (advice-add 'mu4e-view-mark-for-trash :around 'ph/do-or-dont-execute) #+END_SRC

*** View

Show the =useragent= and =bcc=.

#+BEGIN_SRC emacs-lisp (setq mu4e-view-fields '(:from :to :cc :bcc :subject :flags :date :maildir :mailing-list :tags :signature :decryption :useragent :attachments)) #+END_SRC

Show me the addresses, not only names.

#+BEGIN_SRC emacs-lisp (setq mu4e-view-show-addresses t) #+END_SRC

View html-mail in browser with =aV=.

#+BEGIN_SRC emacs-lisp (add-to-list 'mu4e-view-actions '("ViewInBrowser" . mu4e-action-view-in-browser) t) #+END_SRC

*** Bookmarks

Custom Bookmarks

#+BEGIN_SRC emacs-lisp (add-to-list 'mu4e-bookmarks (make-mu4e-bookmark :name "Big ones" :query "size:5M..50000M" :key ?b)) (add-to-list 'mu4e-bookmarks (make-mu4e-bookmark :name "Bullshit" :query "maildir:/./.\(spam\|junk\).*/" :key ?s)) #+END_SRC

*** Compose

Enabling receiving clients that support this feature to reflow my paragraphs. Plain text emails with =Content-Type: text/plain; format=flowed= can be reflowed (i.e. line endings removed, paragraphs refilled) by receiving clients that support this standard. Clients that don’t support this, show them as is, which means this feature is truly non-invasive.

#+BEGIN_SRC emacs-lisp (setq mu4e-compose-format-flowed t) #+END_SRC

Dont reply to myself.

#+BEGIN_SRC emacs-lisp (setq mu4e-compose-dont-reply-to-self t) #+END_SRC

Kill message-buffer when finished.

#+BEGIN_SRC emacs-lisp (setq message-kill-buffer-on-exit t) #+END_SRC

Add formatted citation line.

#+BEGIN_SRC emacs-lisp (setq message-citation-line-function 'message-insert-formatted-citation-line) #+END_SRC

*** Send

Use =smtpmail= with =gnutls= to sending mails.

#+BEGIN_SRC emacs-lisp (setq message-send-mail-function 'smtpmail-send-it) (setq starttls-use-gnutls t) (setq smtpmail-debug-info t) #+END_SRC

Before sending a message, check if it contains any words that indicate that there should be an attachement. If it does, ask if all attachments were added before sending the mail.

#+BEGIN_SRC emacs-lisp (defvar ph/message-attachment-regexp (concat "\(" "[Ww]e send\|" "[Ii] send\|" "attach\|" "[aA]nhang\|" "[aA]ngehängt\|" "[sS]chicke\|" "haenge\|" "hänge\)"))

(defun ph/message-check-attachment nil "Check for forgotten attachments" (save-excursion (message-goto-body) (when (search-forward-regexp ph/message-attachment-regexp nil t nil) (message-goto-body) (unless (message-y-or-n-p "Did you attach all documents?" nil nil) (error "No message sent, add some attachments!")))))

(add-hook 'message-send-hook 'ph/message-check-attachment) #+END_SRC

*** Contexts

Pick first Context as default.

#+BEGIN_SRC emacs-lisp (setq mu4e-context-policy 'pick-first) (setq mu4e-compose-context-policy 'ask-if-none)

(setq mu4e-contexts `(,(make-mu4e-context :name "Private" :match-func (lambda (msg) (when msg (or (mu4e-message-contact-field-matches msg :to "pascal.huber@resolved.ch") (mu4e-message-contact-field-matches msg :to "accounts@resolved.ch")))) :vars '((user-full-name . "Pascal Huber" ) (user-mail-address . "pascal.huber@resolved.ch") (mu4e-get-mail-command . "offlineimap") (mu4e-drafts-folder . "/r/Drafts") (mu4e-sent-folder . "/r/Sent") (mu4e-trash-folder . "/r/Trash") (mu4e-maildir-shortcuts .( ("/r/INBOX" . ?i) ("/r/Sent" . ?s) ("/r/Spam" . ?x) ("/r/keep" . ?k) ("/r/tempKeep" . ?t) ("/r/Trash" . ?b))) (mu4e-compose-crypto-reply-plain-policy . sign) (ph/mu4e-default-search-expr . "maildir:/r/.[^Trash]/") (mu4e-sent-messages-behavior . sent) (smtpmail-stream-type . starttls) (smtpmail-default-smtp-server . "mail.infomaniak.com") (smtpmail-smtp-server . "mail.infomaniak.com") (smtpmail-smtp-service . 587) (smtpmail-smtp-user . "pascal.huber@resolved.ch") (smtpmail-starttls-credentials . "/home/pascal/.authinfo.gpg") (smtpmail-auth-credentials . '(("mail.resolved.ch" 587 nil nil))))) ,(make-mu4e-context :name "QuickShift" :match-func (lambda (msg) (when msg (mu4e-message-contact-field-matches msg :to "pascal@quickshift.ch"))) :vars '((user-full-name . "Pascal Huber" ) (user-mail-address . "pascal@quickshift.ch") (mu4e-get-mail-command . "offlineimap") (mu4e-drafts-folder . "/q/INBOX.Drafts") (mu4e-sent-folder . "/q/INBOX.Sent") (mu4e-trash-folder . "/q/INBOX.Trash") (mu4e-maildir-shortcuts .( ("/q/INBOX" . ?i) ("/q/INBOX.Sent" . ?s) ("/q/INBOX.spambucket" . ?x) ("/q/INBOX.keep" . ?k) ("/q/INBOX.live" . ?l) ("/q/INBOX.customers" . ?c) ("/q/INBOX.tempKeep" . ?k) ("/q/INBOX.bugsnag" . ?e) ("/q/INBOX.Trash" . ?b))) (mu4e-compose-crypto-reply-plain-policy . sign) (ph/mu4e-default-search-expr . "maildir:/q/.[^Trash]/") (mu4e-sent-messages-behavior . sent) (smtpmail-stream-type . starttls) (smtpmail-default-smtp-server . "mail.quickshift.ch") (smtpmail-smtp-server . "mail.quickshift.ch") (smtpmail-smtp-service . 587) (smtpmail-smtp-user . "pascal@quickshift.ch") (smtpmail-starttls-credentials . "/home/pascal/.authinfo.gpg") (smtpmail-auth-credentials . '(("mail.quickshift.ch" 587 nil nil))))) ,(make-mu4e-context :name "ETH" :match-func (lambda (msg) (when msg (mu4e-message-contact-field-matches msg :to "pahuber@student.ethz.ch"))) :vars '((user-full-name . "Pascal Huber" ) (user-mail-address . "pahuber@student.ethz.ch") (mu4e-get-mail-command . "offlineimap") (mu4e-drafts-folder . "/e/Drafts") (mu4e-sent-folder . "/e/Sent Items") (mu4e-trash-folder . "/e/Deleted Items") (mu4e-maildir-shortcuts .( ("/e/INBOX" . ?i) ("/e/Junk E-Mail" . ?x) ("/e/INBOX.keep" . ?k) ("/e/INBOX.asl" . ?a) ("/e/INBOX.iml" . ?m) ("/e/INBOX.negotiation" . ?n) ("/e/INBOX.podc" . ?p) ("/e/Sent Items" . ?s) ("/e/INBOX.tmp" . ?t) ("/e/Deleted Items" . ?b))) (mu4e-compose-crypto-reply-plain-policy . sign) (ph/mu4e-default-search-expr . "maildir:/e/.*[^Deleted\ Items]/") (mu4e-sent-messages-behavior . sent) (smtpmail-stream-type . starttls) (smtpmail-default-smtp-server . "mail.ethz.ch") (smtpmail-smtp-server . "mail.ethz.ch") (smtpmail-smtp-service . 587) (smtpmail-smtp-user . "pahuber") (smtpmail-starttls-credentials . "/home/pascal/.authinfo.gpg") (smtpmail-auth-credentials . '(("mail.ethz.ch" 587 nil nil))))))) #+END_SRC

  • Programming

This section contains programming packages and settings.

** General Purpose *** Company

[[http://company-mode.github.io/][Company]] is a text completion framework for Emacs. The name stands for "complete anything". It uses pluggable back-ends and front-ends to retrieve and display completion candidates.

#+BEGIN_SRC emacs-lisp (ph/install-package 'company) (require 'company) (add-hook 'after-init-hook 'global-company-mode) #+END_SRC

**** Settings

Automatically show completion after 1 character.

#+BEGIN_SRC emacs-lisp (setq company-minimum-prefix-length 1) #+END_SRC

Don't require a match to continue typing.

#+BEGIN_SRC emacs-lisp (setq company-require-match nil) #+END_SRC

Switch between suggestions with =C-n= and =C-p=.

#+BEGIN_SRC emacs-lisp (general-def company-active-map "C-n" 'company-select-next "C-p" 'company-select-previous)

(general-def company-search-map "C-n" 'company-select-next "C-p" 'company-select-previous) #+END_SRC

*** Brackets

[[https://github.com/Fanael/rainbow-delimiters][Rainbow-Delimiters]] makes brackets colorful.

#+BEGIN_SRC emacs-lisp (ph/install-package 'rainbow-delimiters) (add-hook 'prog-mode-hook 'rainbow-delimiters-mode) #+END_SRC

Highlight matching brackets.

#+BEGIN_SRC emacs-lisp (setq show-paren-style 'mixed) (add-hook 'prog-mode-hook 'show-paren-mode) #+END_SRC

*** Dumb Jump

[[https://github.com/jacktasia/dumb-jump][Dumb-Jump]] is an Emacs "jump to definition" package with support for multiple programming languages that favors "just working". This means minimal -- and ideally zero -- configuration with absolutely no stored indexes (TAGS) or persistent background processes

#+BEGIN_SRC emacs-lisp (ph/install-package 'dumb-jump) (dumb-jump-mode) (setq dumb-jump-selector 'ivy) (setq dumb-jump-use-visible-window nil) #+END_SRC

*** Flycheck

[[https://www.flycheck.org/en/latest/][Flycheck]] is a modern on-the-fly syntax checking extension for GNU Emacs. The most important commands have keybindings with prefix =C-c !=.

#+BEGIN_SRC emacs-lisp (ph/install-package 'flycheck) (require 'flycheck) #+END_SRC

Enable =Flycheck= globally (=prog-mode-hook= may not cover all modes).

#+BEGIN_SRC emacs-lisp (add-hook 'after-init-hook 'global-flycheck-mode) #+END_SRC

#+BEGIN_SRC emacs-lisp (define-fringe-bitmap 'flycheck-fringe-bitmap-ball (vector #b00000000 #b00000000 #b00000000 #b00000000 #b00000000 #b00111000 #b01111100 #b11111110 #b11111110 #b11111110 #b01111100 #b00111000 #b00000000 #b00000000 #b00000000 #b00000000 #b00000000))

(flycheck-define-error-level 'error :severity 100 :compilation-level 2 :overlay-category 'flycheck-error-overlay :fringe-bitmap 'flycheck-fringe-bitmap-ball :fringe-face 'flycheck-fringe-error :error-list-face 'flycheck-error-list-error) #+END_SRC

*** Git

[[https://magit.vc/][Magit]] is an interface to the version control system Git.

#+BEGIN_SRC emacs-lisp (ph/install-package 'magit) #+END_SRC

[[https://github.com/alphapapa/magit-todos][Magit-Todos]] shows all =TODO= items of the projct in the main magit-buffer.

#+BEGIN_SRC emacs-lisp (ph/install-package 'magit-todos) (magit-todos-mode t) #+END_SRC

Some major-modes to configure git repositories.

#+BEGIN_SRC emacs-lisp (ph/install-package 'gitattributes-mode) (ph/install-package 'gitconfig-mode) (ph/install-package 'gitignore-mode) #+END_SRC

[[https://github.com/dgutov/diff-hl][diff-hl-mode]] highlights uncommitted changes on the left side of the window, allows you to jump between and revert them selectively.

#+BEGIN_SRC emacs-lisp (ph/install-package 'diff-hl) #+END_SRC

*** Indentation

#+BEGIN_SRC emacs-lisp (setq-default indent-tabs-mode nil tab-width 2) #+END_SRC

*** Rainbow

[[https://github.com/emacsmirror/rainbow-mode][Rainbow-Mode]] sets background color to strings that match color names, e.g. #0000ff is displayed in white with a blue background

#+BEGIN_SRC emacs-lisp (ph/install-package 'rainbow-mode) (add-hook 'prog-mode-hook 'rainbow-mode) #+END_SRC

*** YASnippet

[[https://github.com/joaotavora/yasnippet][YASnippet]] is a template system for Emacs.

#+BEGIN_SRC emacs-lisp (ph/install-package 'yasnippet) (ph/install-package 'yasnippet-snippets) (require 'yasnippet) (yas-global-mode 1) #+END_SRC

** C++

[[https://github.com/Sarcasm/irony-mode][Irony-mode]] is an Emacs minor-mode that aims at improving the editing experience for the C, C++ and Objective-C languages. I

#+BEGIN_SRC emacs-lisp (ph/install-package 'irony)

(add-hook 'c++-mode-hook 'irony-mode) (add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options) #+END_SRC

Add flycheck linting.

#+BEGIN_SRC emacs-lisp (ph/install-package 'flycheck-irony) (add-hook 'flycheck-mode-hook #'flycheck-irony-setup) #+END_SRC

#+BEGIN_SRC emacs-lisp (ph/install-package 'flycheck-clang-tidy) (eval-after-load 'flycheck '(add-hook 'flycheck-mode-hook #'flycheck-clang-tidy-setup)) #+END_SRC

[[https://github.com/realgud/realgud][Realgud]] - An extensible, modular GNU Emacs front-end for interacting with external debuggers (e.g. gdb).

#+BEGIN_SRC emacs-lisp (ph/install-package 'realgud) (require 'realgud) #+END_SRC

Notes:

** CSS

#+BEGIN_SRC emacs-lisp (setq css-indent-offset 2) #+END_SRC

** Go

Install on system.

#+BEGIN_SRC shell gogetugithub.com/rogpeppe/godefgo get -u github.com/rogpeppe/godef go get -u github.com/mdempsky/gocode #+END_SRC

#+BEGIN_SRC emacs-lisp (ph/install-package 'go-mode) #+END_SRC

Autocompletion

#+BEGIN_SRC emacs-lisp (ph/install-package 'company-go) #+END_SRC

** Haml

#+BEGIN_SRC emacs-lisp (ph/install-package 'haml-mode) #+END_SRC

** Haskell

OS setup

#+BEGIN_SRC shell curl -sSL https://get.haskellstack.org/ | sh #+END_SRC

Create a new project

#+BEGIN_SRC shell stack new myproject # to create a new project

see stack --help

#+END_SRC

[[http://chrisdone.github.io/intero/][Intero]] is a complete interactive development program for Haskell. It offers many useful functions ([[https://github.com/chrisdone/intero/blob/master/EMACS.md#default-key-bindings][see here]]) and an (automatically loaded) company-backend.

#+BEGIN_SRC emacs-lisp (ph/install-package 'intero) (with-eval-after-load 'haskell-mode (intero-global-mode)) #+END_SRC

Don't jump to the repl everytime it does something.

TODO: find out if there is a nicer solution to prevent intero from jumping to

the repl every time.

#+BEGIN_SRC emacs-lisp (defun ph/intero-repl-switch-back (&rest _) (intero-repl-switch-back)) (advice-add 'intero-repl-eval-region :after 'ph/intero-repl-switch-back) (advice-add 'intero-repl-load :after 'ph/intero-repl-switch-back) #+END_SRC

Some more convenient keybindings

#+BEGIN_SRC emacs-lisp (general-def 'haskell-mode-map "C-c C-d" 'haskell-hoogle) (general-def 'intero-mode-map "C-c C-b" 'intero-repl) (general-def 'intero-repl-mode-map "C-c C-b" 'intero-repl-switch-back) #+END_SRC

Syntax checker

#+BEGIN_SRC emacs-lisp (ph/install-package 'flycheck-haskell) (add-hook 'haskell-mode-hook #'flycheck-haskell-setup) #+END_SRC

** JavaScript

Indentation

#+BEGIN_SRC emacs-lisp (setq js-indent-level 2) #+END_SRC

*** Autocompletion

TODO: company-tern is not on melpa anymore, find a solution

#+BEGIN_SRC emacs-lisp ;(ph/install-package 'company-tern) ;(require 'company-tern) ;(add-to-list 'company-backends 'company-tern) #+END_SRC

=jquery-doc= provides completion source for auto-complete and company-mode as well as a =jquery-doc= command to lookup documentation.

#+BEGIN_SRC emacs-lisp (ph/install-package 'jquery-doc) #+END_SRC

*** JS2-mode

#+BEGIN_SRC emacs-lisp (ph/install-package 'js2-mode) (ph/install-package 'js2-refactor) #+END_SRC

*** Tern

This is Tern. Tern is a stand-alone, editor-independent JavaScript analyzer that can be used to improve the JavaScript integration of existing editors.

#+BEGIN_SRC emacs-lisp (ph/install-package 'tern) #+END_SRC

Put a file =.tern-project= in the root of the project. Additionally, a file =~/.tern-config=.

A Ruby on Rails =.tern-project= may look like this:

#+BEGIN_SRC javascript { "libs": [ "browser", "jquery" ], "loadEagerly": [ "app/assets/javascripts//*.js", "lib/assets/javascript//.js", "vendor/assets/javascript/**/.js" ], "plugins": { "es_modules": {}, "node": {} } } #+END_SRC

And my =~/.tern-config=

#+BEGIN_SRC javascript { "libs": [ "browser", "jquery" ], "plugins": { "es_modules": {}, "node": {} } } #+END_SRC

*** Eslint

Use =eslint= instead of =jshint=.

#+BEGIN_SRC emacs-lisp (setq-default flycheck-disabled-checkers (append flycheck-disabled-checkers '(javascript-jshint))) (flycheck-add-mode 'javascript-eslint 'web-mode) #+END_SRC

** JSON

#+BEGIN_SRC emacs-lisp (ph/install-package 'json-mode) #+END_SRC

** Lua

#+BEGIN_SRC emacs-lisp (ph/install-package 'lua-mode) #+END_SRC

** Markdown

#+BEGIN_SRC emacs-lisp (ph/install-package 'markdown-mode) (setq markdown-command "pandoc") #+END_SRC

** PHP

#+BEGIN_SRC emacs-lisp (ph/install-package 'php-mode) #+END_SRC

** Python *** Elpy

#+BEGIN_SRC emacs-lisp (ph/install-package 'elpy) (elpy-enable) #+END_SRC

Indentation

#+BEGIN_SRC emacs-lisp (setq python-indent 2) #+END_SRC

Some useful commands:

  • =M-x run-python= to start a shell
  • =C-c C-z= to switch to shell
  • =C-c C-y b= to send buffer to shell
  • many more send to shell functions

*** Auto Completion

Jedi is a Python auto-completion package for Emacs.

#+BEGIN_SRC emacs-lisp (ph/install-package 'jedi) (add-hook 'python-mode-hook 'jedi:setup) (setq jedi:complete-on-dot t) #+END_SRC

*** Pipenv

There are several tools and helpers to handle virtual environments, dependencies, etc. (virtualenv, pyenv, pyenv-virtualenv, virtualenvwrapper, pyenv-virtualenvwrapper, pipenv, venv, pip-tools, ...).

[[https://github.com/pypa/pipenv][Pipenv]] is the newest and combines =Pipfile=, =pip= and =virtualenv= and plays well with =projectile=.

#+BEGIN_SRC emacs-lisp (ph/install-package 'pipenv) (add-hook 'python-mode 'pipenv-mode) #+END_SRC

To run a shell, use =M-x pipenv-shell=. Some example commands are:

#+BEGIN_SRC shell pipenv --python 3.7 # create project with python 3.7 pipenv run python main.py # run application pipenv install numpy # with Pipfile pipenv install -r path/to/requirements.txt # with requirements.txt #+END_SRC

** Emacs speaks Statistics

[[https://github.com/emacs-ess/ESS][Emacs Speaks Statistics (ess)]] is designed to support editing of scripts and interaction with various statistical analysis programs such as R, S-Plus, SAS, Stata and OpenBUGS/JAGS.

#+BEGIN_SRC emacs-lisp (ph/install-package 'ess) #+END_SRC

Function:

** Ruby *** Inf-ruby [[https://github.com/nonsequitur/inf-ruby][ Inf-Ruby]] provides a REPL buffer connected to a Ruby subprocess.

#+BEGIN_SRC emacs-lisp (ph/install-package 'inf-ruby) #+END_SRC

*** Ruby Mode

Use the built-in =ruby-mode= for all common ruby-files.

No magic comments

#+BEGIN_SRC emacs-lisp (setq ruby-insert-encoding-magic-comment nil) #+END_SRC

*** Robe

[[https://github.com/dgutov/robe][Robe]] is a code assistance tool that uses a Ruby REPL subprocess with your application or gem code loaded, to provide information about loaded classes and modules, and where each method is defined.

#+BEGIN_SRC emacs-lisp (ph/install-package 'robe) #+END_SRC

Add the following gems to the =Gemfile= (if existent) and install them.

#+BEGIN_SRC ruby group :development do gem 'pry' gem 'pry-doc' gem 'method_source' end #+END_SRC

Generally, you'll want to start with =M-x inf-ruby-console-auto=. If there's no Ruby console running, most interactive commands provided by Robe will offer to launch it automatically.

The exceptions are code completion and eldoc, which only work if the server is already running. To launch it, type =M-x robe-start=.

As you change the code in your project, you'll want to update the running process. To load the current file, type =C-c C-l= (=ruby-load-file=), see inf-ruby for more commands. When you're working on a Rails project, you can type =C-c C-k= instead to reload the whole environment at once.

#+BEGIN_SRC emacs-lisp (add-hook 'ruby-mode-hook 'robe-mode) #+END_SRC

Some useful Commands/Keybindings

  • =C-c C-d= Lookup documentation
  • =M-.= / =M-,​= Jump to defintion and back

Use company mode for code completion.

#+BEGIN_SRC emacs-lisp (eval-after-load 'company '(push 'company-robe company-backends)) #+END_SRC

*** Rspec-mode

[[https://github.com/pezra/rspec-mode][Rspec-Mode]] provides some convenience functions for dealing with RSpec.

#+BEGIN_SRC emacs-lisp (ph/install-package 'rspec-mode) #+END_SRC

When you've hit the breakpoint, hit =C-x C-q= to enable inf-ruby.

#+BEGIN_SRC emacs-lisp (add-hook 'after-init-hook 'inf-ruby-switch-setup) #+END_SRC

Usage:

Put the following in the =Gemfile= of the projects.

#+BEGIN_SRC ruby group :development do gem 'spring-commands-rspec' end #+END_SRC

*** Projectile Rails

[[https://github.com/asok/projectile-rails][Projectile Rails]] is a minor mode for working with Ruby on Rails applications and engines in GNU Emacs. Internally it is based on Projectile.

#+BEGIN_SRC emacs-lisp (setq projectile-rails-keymap-prefix (kbd "C-c p n")) (ph/install-package 'projectile-rails) (projectile-rails-global-mode) #+END_SRC

*** Autocompletion

#+BEGIN_SRC emacs-lisp (ph/install-package 'company-inf-ruby) (add-to-list 'company-backends 'company-inf-ruby) #+END_SRC

** Shell

Indentation

#+BEGIN_SRC emacs-lisp (setq sh-basic-offset 2) (setq sh-indentation 2) #+END_SRC

Autocompletion

#+BEGIN_SRC emacs-lisp (ph/install-package 'company-shell) (add-to-list 'company-backends 'company-shell) #+END_SRC

** TeX

AUCTeX is an extensible package for writing and formatting TeX files in GNU Emacs.

#+BEGIN_SRC emacs-lisp (ph/install-package 'auctex) #+END_SRC

Parse on load and save. This increases performance, especially for large multifile projects. The information is stored in an "auto" subdirectory.

#+BEGIN_SRC emacs-lisp (setq TeX-parse-self t) (setq TeX-auto-save t) #+END_SRC

Query to find out which is the master file.

#+BEGIN_SRC emacs-lisp (setq-default TeX-master nil) #+END_SRC

Auctex by default adds comment sections to all the .tex files to save the =TeX-master= variable. In order not to confuse my colleagues with such auctex-specific lines I use [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html][per-directory local variables]]. For that I put the following list in a =.dir-locals.el= file in the project root if the main latex file is =report.tex=.

#+BEGIN_SRC lisp ((latex-mode . ((TeX-master . "report")))) #+END_SRC

I use Evince to view my PDFs.

#+BEGIN_SRC emacs-lisp (setq TeX-PDF-mode t) (setq TeX-view-program-selection '((output-pdf "Evince"))) #+END_SRC

Sync with evince. Use =Control + Left Click= for backward search.

#+BEGIN_SRC emacs-lisp (add-hook 'LaTeX-mode-hook 'TeX-source-correlate-mode) (setq TeX-source-correlate-start-server t) #+END_SRC

Autocompletion

#+BEGIN_SRC emacs-lisp (ph/install-package 'company-bibtex) (add-to-list 'company-backends 'company-bibtex)

(ph/install-package 'company-auctex) (company-auctex-init) #+END_SRC

Auto-fill

#+BEGIN_SRC emacs-lisp (add-hook 'LaTeX-mode-hook 'turn-on-auto-fill) #+END_SRC

** Web mode

[[http://web-mode.org/][Web-Mode]] is an autonomous emacs major-mode for editing web templates. HTML documents can embed parts (CSS / JavaScript) and blocks (client / server side).

#+BEGIN_SRC emacs-lisp (ph/install-package 'web-mode) #+END_SRC

Use =web-mode= for the following file-types.

#+BEGIN_SRC emacs-lisp (add-to-list 'auto-mode-alist '("\.html?\'" . web-mode)) (add-to-list 'auto-mode-alist '("\.tag?\'" . web-mode)) (add-to-list 'auto-mode-alist '("\.vue?\'" . web-mode)) (add-to-list 'auto-mode-alist '("\.erb?\'" . web-mode)) (add-to-list 'auto-mode-alist '("\.js[x]?\'" . web-mode)) (add-to-list 'auto-mode-alist '("\.json?\'" . web-mode)) #+END_SRC

Some web-mode settings.

#+BEGIN_SRC emacs-lisp (setq web-mode-markup-indent-offset 2 web-mode-css-indent-offset 2 web-mode-code-indent-offset 2 web-mode-script-padding 2 web-mode-style-padding 2 web-mode-script-padding 2 web-mode-block-padding 0 web-mode-enable-current-element-highlight t web-mode-enable-current-column-highlight t) #+END_SRC

*** Autocompletion

#+BEGIN_SRC emacs-lisp (ph/install-package 'company-web) (require 'company-web-html) (add-to-list 'company-backends 'company-web-html) #+END_SRC

Use company backends for =tern=, =html= and =css=.

#+BEGIN_SRC emacs-lisp (add-hook 'web-mode-hook '(lambda () (set (make-local-variable 'company-backends) '(company-tern company-web-html company-css company-files)))) #+END_SRC

Enable =tern= when the current language is JavaScript.

#+BEGIN_SRC emacs-lisp (advice-add 'company-tern :before '(lambda (&rest _) (if (equal major-mode 'web-mode) (let ((web-mode-cur-language (web-mode-language-at-pos))) (if (or (string= web-mode-cur-language "javascript") (string= web-mode-cur-language "jsx")) (unless tern-mode (tern-mode)) (if tern-mode (tern-mode -1))))))) #+END_SRC

** Yaml

#+BEGIN_SRC emacs-lisp (ph/install-package 'yaml-mode) #+END_SRC

  • Keybindings

My global keybindings are defined here. In order to get a better overview, they are neatly packed inside a minor-mode with its own keymap.

#+BEGIN_SRC emacs-lisp (defvar ph/global-keys-keymap (make-sparse-keymap))

(define-minor-mode ph/global-keys-mode "A minor mode with personalized keybindings." t ;; init-value nil ;; lighter ph/global-keys-keymap) #+END_SRC

** Not User-Reserved

Overwriting sequences (and defining new ones) for non-user-reserved sequences.

#+BEGIN_SRC emacs-lisp (general-def ph/global-keys-keymap "M-x" 'counsel-M-x "C-s" 'ph/swiper-from-isearch "C-h f" 'counsel-describe-function "C-h v" 'counsel-describe-variable)

(general-def ph/global-keys-keymap :prefix "C-x" "2" 'ph/vsplit-last-buffer "3" 'ph/hsplit-last-buffer "7" 'ph/open-last-buffer "b" 'ivy-switch-buffer "f" 'counsel-find-file "m" 'counsel-M-x "o" 'ace-window "C-b" 'ivy-switch-buffer "C-f" 'set-fill-column) #+END_SRC ** User-Reserved

User-reserved sequences (=C-c= followed by a letter and == through == without modifiers) should (theoretically -.-) not be used by any major modes and are intended for user-defined keybindings.

#+BEGIN_SRC emacs-lisp (general-def ph/global-keys-keymap :prefix "C-c" "d" 'crux-kill-line-backwards "f d" 'rg-dwim "f f" 'counsel-rg "f p" 'rg-project "f r" 'rg "h b" 'dumb-jump-back "h f" 'dumb-jump-go "h p" 'dumb-jump-go-prompt "l g" 'diff-hl-mode "l k" 'ph/kill-other-buffers "l m" 'magit-diff-buffer-file "l o" 'ph/xdg-open "l q" 'ph/qs-notes "l r" 'browse-kill-ring "l u" 'ph/unfill-paragraph "l v" 'visual-line-mode "i" 'indent-region "j" 'switch-to-next-buffer "k" 'switch-to-prev-buffer "m" 'magit "o" 'ph/occur-dwim "r" 'ph/mu4e "s b" 'flyspell-buffer "s c" 'flyspell-correct-at-point "s e" 'flyspell-mode "s n" 'flyspell-goto-next-error "s l" 'ph/ispell-next-dictionary "u" 'counsel-imenu "w m" 'which-key-show-major-mode "w t" 'which-key-show-top-level)

(general-def ph/global-keys-keymap "" 'ph/next-theme "" 'ivy-resume) #+END_SRC

** State Specific

Some state specific bindings.

#+BEGIN_SRC emacs-lisp (general-def 'normal ph/global-keys-keymap "SPC" 'god-local-mode) (general-def 'visual ph/global-keys-keymap "SPC" 'god-local-mode)

(general-def 'motion ph/global-keys-keymap "j" 'evil-next-visual-line "k" 'evil-previous-visual-line)

(general-def 'insert ph/global-keys-keymap "" 'company-yasnippet "C-SPC" 'company-complete) #+END_SRC

  • User Interface ** Default Face

#+BEGIN_SRC emacs-lisp (set-face-attribute 'default nil :family "DejaVu Sans Mono" ;; some similar characters: 0OD yprw VU Ss |iIl :weight 'normal :height 120 :width 'normal) #+END_SRC

** Diminish

[[https://github.com/emacsmirror/diminish][Diminish]] implements hiding or abbreviation of the mode line displays (lighters) of minor-modes.

#+BEGIN_SRC emacs-lisp (ph/install-package 'diminish)

(diminish 'counsel-mode) (diminish 'god-local-mode) (diminish 'ivy-mode) (diminish 'projectile-mode) (diminish 'undo-tree-mode) (diminish 'visual-line-mode "VL") (diminish 'which-key-mode) #+END_SRC

** Doom Modeline

[[https://github.com/seagle0128/doom-modeline][Doom Modeline]] is a fancy and fast mode-line with minimalism design.

#+BEGIN_SRC emacs-lisp (ph/install-package 'doom-modeline) (require 'doom-modeline) #+END_SRC

*** Settings

Show both line and column numbers but not a percentage.

#+BEGIN_SRC emacs-lisp (setq line-number-mode t) (setq column-number-mode t) (setq doom-modeline-percent-position nil) #+END_SRC

Make modeline as high as its content.

#+BEGIN_SRC emacs-lisp (setq doom-modeline-height 30) (setq doom-modeline-bar-width 1) #+END_SRC

No icons in my mode-line.

#+BEGIN_SRC emacs-lisp (setq doom-modeline-icon (display-graphic-p)) (setq all-the-icons-scale-factor 1.0) #+END_SRC

Make the mode-line segment show the minions-menu AND the minor-modes.

#+BEGIN_SRC emacs-lisp (setq doom-modeline-minor-modes t) #+END_SRC

Show flycheck info/warning/error instead of only one number for them all.

#+BEGIN_SRC emacs-lisp (setq doom-modeline-checker-simple-format nil) #+END_SRC

Show long branch names.

#+BEGIN_SRC emacs-lisp (setq doom-modeline-vcs-max-length 24) #+END_SRC

Show buffer-name instead of path.

#+BEGIN_SRC emacs-lisp (setq doom-modeline-buffer-file-name-style 'buffer-name) #+END_SRC

*** Segments

A Segment to indicate the active ispell dictionary in flyspell.

#+BEGIN_SRC emacs-lisp (doom-modeline-def-segment ph/flyspell-dictionary (when (and flyspell-mode ispell-local-dictionary) (concat (doom-modeline-spc) (propertize ispell-local-dictionary 'face 'doom-modeline-buffer-minor-mode)))) #+END_SRC

Show the tramp method.

#+BEGIN_SRC emacs-lisp (doom-modeline-def-segment tramp-method (let ((method (file-remote-p default-directory 'method))) (if method (concat (doom-modeline-spc) (propertize method 'face 'doom-modeline-urgent))))) #+END_SRC

Show the projectile project name.

#+BEGIN_SRC emacs-lisp (doom-modeline-def-segment ph/projectile-project-name (when (projectile-project-p) (concat (doom-modeline-spc) (propertize (projectile-project-name) 'face (if (doom-modeline--active) 'doom-modeline-buffer-path 'mode-line-inactive)) (doom-modeline-spc)))) #+END_SRC

Show the buffer name.

#+BEGIN_SRC emacs-lisp (doom-modeline-def-segment ph/buffer-info (concat (doom-modeline-spc) (propertize (buffer-name) 'face 'doom-modeline-buffer-file))) #+END_SRC

Handle evil-state faces in a more extendable way. I also want them to be always active/colorful to have a better overview of where my windows start and end. Also the =modals= segment adds a second indicator for god-mode which I don't want.

#+BEGIN_SRC emacs-lisp (setq doom-modeline-evil-state-faces-alist '((normal . doom-modeline-evil-normal-state) (emacs . doom-modeline-evil-emacs-state) (insert . doom-modeline-evil-insert-state) (motion . doom-modeline-evil-motion-state) (visual . doom-modeline-evil-visual-state) (operator . doom-modeline-evil-operator-state) (replace . doom-modeline-evil-replace-state)))

(doom-modeline-def-segment ph/evil-state "The current evil state. Requires `evil-mode' to be enabled." (when (bound-and-true-p evil-local-mode) (let ((tag (evil-state-property evil-state :tag t))) (propertize (if (stringp tag) tag (funcall tag)) 'face (if (doom-modeline--active) (cdr (assoc evil-state doom-modeline-evil-state-faces-alist)) 'doom-modeline-bar-inactive)))))

(set-face-attribute 'doom-modeline-evil-emacs-state nil :foreground "#111" :background "SkyBlue") (set-face-attribute 'doom-modeline-evil-insert-state nil :foreground "#111" :background "LimeGreen") (set-face-attribute 'doom-modeline-evil-motion-state nil :foreground "#111" :background "#9c91e4") (set-face-attribute 'doom-modeline-evil-normal-state nil :foreground "#111" :background "#ffdd30") (set-face-attribute 'doom-modeline-evil-operator-state nil :foreground "#111" :background "NavajoWhite") (set-face-attribute 'doom-modeline-evil-visual-state nil :foreground "#111" :background "#aaaaaa") (set-face-attribute 'doom-modeline-evil-replace-state nil :foreground "#111" :background "#fd971f") #+END_SRC

*** Setup

Setup the mode-line.

#+BEGIN_SRC emacs-lisp (doom-modeline-def-modeline 'main '(bar window-number ph/evil-state matches ; e.g. evil-substitute selection-info tramp-method ph/buffer-info remote-host buffer-position ph/flyspell-dictionary checker) '(minor-modes media-info misc-info vcs ph/projectile-project-name major-mode) ) #+END_SRC

Last but not least, enable it.

#+BEGIN_SRC emacs-lisp (doom-modeline-mode 1) #+END_SRC

When I open my first frame, the mode-line has a rather large empty space on the right side. The width is set incorrectly although =doom-modeline-refresh-font-width-cache= is in =after-make-frame-functions=. Adding the function to =buffer-list-update-hook= seems to resolve this issue.

TODO: Create an issue on doom-modeline about font-width-cache

#+BEGIN_SRC emacs-lisp (add-hook 'buffer-list-update-hook 'doom-modeline-refresh-font-width-cache) #+END_SRC

** Color Themes

Function to rotate through =ph/theme-list=. The entries may be functions or themes.

#+BEGIN_SRC emacs-lisp (ph/install-package 'doom-themes)

(setq ph/theme-list '(doom-peacock doom-tomorrow-day))

(defun ph/next-theme () "Load next theme." (interactive) (setq ph/theme-list (ph/call-rotate 'ph/load-theme ph/theme-list)))

(add-hook 'emacs-startup-hook 'ph/next-theme) #+END_SRC

Functions to load and customize themes.

#+BEGIN_SRC emacs-lisp (defun ph/load-theme (theme) "Like load-theme but first disable all custom-enabled themes , then load THEME and finally do some customizations." (interactive (list (intern (completing-read "Load custom theme: " (mapcar 'symbol-name (custom-available-themes)))))) (mapcar 'disable-theme custom-enabled-themes) (load-theme theme t) (ph/customize-theme theme) (ph/any-theme-customize))

(defun ph/customize-theme (theme) "Call ph/THEME-customize if existent." (let ((fn (intern (concat "ph/" (symbol-name theme) "-customize")))) (message (concat "ph/" (symbol-name theme) "-customize")) (if (functionp fn) (funcall fn))))

(defun ph/doom-peacock-customize () ;; highlight current line number (set-face-attribute 'line-number-current-line nil :foreground "#BCD42A" :weight 'bold))

(defun ph/any-theme-customize () "This function sets some default values for all themes."

;; Never ever scale org and markdown headings (set-face-attribute 'org-level-1 nil :height 1.0 :background nil) (set-face-attribute 'org-level-2 nil :height 1.0 :background nil) (set-face-attribute 'org-level-3 nil :height 1.0 :background nil) (set-face-attribute 'org-level-4 nil :height 1.0 :background nil) (set-face-attribute 'org-level-5 nil :height 1.0 :background nil) (set-face-attribute 'org-level-6 nil :height 1.0 :background nil) (set-face-attribute 'org-level-7 nil :height 1.0 :background nil) (set-face-attribute 'org-level-8 nil :height 1.0 :background nil)

(set-face-attribute 'doom-modeline-bar nil :foreground nil :background nil)

;; Use a smaller font for the mode-line (set-face-attribute 'mode-line nil :height 90) (set-face-attribute 'mode-line-inactive nil :height 90) ) #+END_SRC

** Fancy stuff

Disable fancy GUI stuff

#+BEGIN_SRC emacs-lisp (setq inhibit-splash-screen t) (tool-bar-mode -1) (scroll-bar-mode -1) (menu-bar-mode -1) #+END_SRC

** Frame Title

Show the buffer-name in the frame title and use the same title for unfocused frames.

#+BEGIN_SRC emacs-lisp (setq ph/frame-title-format '("%b")) (setq frame-title-format ph/frame-title-format) (setq icon-title-format ph/frame-title-format) #+END_SRC

** Tooltips

Don't use ugly GTK tooltips.

#+BEGIN_SRC emacs-lisp (setq x-gtk-use-system-tooltips nil) #+END_SRC