Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1382 lines (1133 sloc) 39.9 KB

GNU Emacs Configuration

Introduction

This is my GNU Emacs Configuration.

It is written in a literate style using orgmode tangling to generate the actual configuration file. This can be done by adding the following line to the init.el file.

(setq init-dir (file-name-directory (or load-file-name (buffer-file-name))))
(org-babel-load-file (expand-file-name "loader.org" init-dir))

It has support for many programming languages such as C++, Haskell and Clojure. The configurations for the different languages can be found in the Programming section. It also supports academic writing with org mode using the amazing org-ref package to add citations to the LaTeX output. The configuration for that can be found in the Writing section.

(setq user-full-name "Yann Herklotz")
(setq user-mail-address "yann@yannherklotz.com")

Setup

Set path so that it picks up some executables that I use. This is done because when emacs is started as a server, the PATH is not set correctly, so it has to be manually set inside emacs.

(setenv "PATH"
    (concat
     "/home/ymherklotz/.local/bin" ":"
     "/home/ymherklotz/.yarn/bin" ":"
     "/usr/bin/vendor_perl" ":"
     "/home/ymherklotz/.opam/ocaml-base-compiler.4.09.0/bin" ":"
     "/home/ymherklotz/.nix-profile/bin" ":"
     (getenv "PATH")))
(setq exec-path (append
         '("/home/ymherklotz/.opam/ocaml-base-compiler.4.09.0/bin"
           "/home/ymherklotz/.local/bin"
           "/home/ymherklotz/.yarn/bin"
           "/home/ymherklotz/.nix-profile/bin")
         exec-path))

Define a function to load a user file whenever I want to add configurations that are not pushed as part of this configuration file. This includes a private file containing email configurations for mu4e. In this case, user-init-dir is used to find the current init directory that Emacs is using and load-user-file can be used to load any file in that directory.

(defconst user-init-dir
  (cond ((boundp 'user-emacs-directory)
         user-emacs-directory)
        ((boundp 'user-init-directory)
         user-init-directory)
        (t "~/.emacs.d/")))

(defun load-user-file (file)
  (interactive "f")
  "Load a file in current user's configuration directory"
  (load-file (expand-file-name file user-init-dir)))

Repositories

Defining all the package repositories that are going to be used.

gnu
The default package repository for emacs
melpa
Contains a lot of additional packages for emacs that are made by the community.
melpa-stable
The stable melpa repository that only contains that full versions for packages. This repository will be used for packages that maybe get updated often, so that they do not break the config.
org
org package repository that contains many packages to extend org-mode.

Use use-package to manage other packages, and improve load times.

(require 'use-package)

(setq use-package-always-ensure t)

GC Threshold

Threshold for faster startup. This should increase the garbage collector’s threshold at which it will start cleaning, so that it is not triggered during startup.

(setq gc-cons-threshold 500000000)

General Configuration

Editor settings

Editor specific options such as adding line numbers.

Disable UI that starts when starting emacs and also set the y or n instead of yes or no. Also stop the start up message from popping up and enter the scratch buffer instead.

(setq inhibit-startup-message t
      confirm-nonexistent-file-or-buffer nil)
(setq-default fill-column 80)
(setq-default truncate-lines t)
(tool-bar-mode 0)
(menu-bar-mode 0)
(fset 'yes-or-no-p 'y-or-n-p)
(global-hl-line-mode 1)
(add-to-list 'custom-theme-load-path "~/.emacs.d/themes/")
(global-set-key (kbd "M-u")   #'upcase-dwim)
(global-set-key (kbd "M-l")   #'downcase-dwim)
(global-set-key (kbd "M-c")   #'capitalize-dwim)
(global-set-key (kbd "C-c z") #'quick-calc)
(global-set-key (kbd "<f5>")  #'revert-buffer)
(global-set-key (kbd "C-c q") #'y/exit-emacs-client)
(global-set-key (kbd "C-c i") #'y/eshell-here)
(global-set-key (kbd "C-.")   #'other-window)
(global-set-key (kbd "C-,")   #'prev-window)
(global-set-key (kbd "C-`")   #'push-mark-no-activate)
(global-set-key (kbd "M-`")   #'jump-to-mark)

(global-set-key (kbd "C-c l") #'org-store-link)
(global-set-key (kbd "C-c a") #'org-agenda)
(global-set-key (kbd "C-c c") #'org-capture)
(global-visual-line-mode t)

Custom modeline

Editing the modeline. %c might be a bit slow though, so that could be removed if that is ever a problem.

(defun -custom-modeline-github-vc ()
  (let ((branch (mapconcat 'concat (cdr (split-string vc-mode "[:-]")) "-")))
    (concat
     (propertize (format " %s" (all-the-icons-octicon "git-branch"))
                 'face `(:height 1 :family ,(all-the-icons-octicon-family))
                 'display '(raise 0))
     (propertize (format " %s" branch))
     (propertize "  "))))

(defun -custom-modeline-svn-vc ()
  (let ((revision (cadr (split-string vc-mode "-"))))
    (concat
     (propertize (format " %s" (all-the-icons-faicon "cloud"))
                 'face `(:height 1)
                 'display '(raise 0))
     (propertize (format " %s" revision) 'face `(:height 0.9)))))

(define-minor-mode minor-mode-blackout-mode
  "Hides minor modes from the mode line."
  t)

(catch 'done
  (mapc (lambda (x)
          (when (and (consp x)
                     (equal (cadr x) '("" minor-mode-alist)))
            (let ((original (copy-sequence x)))
              (setcar x 'minor-mode-blackout-mode)
              (setcdr x (list "" original)))
            (throw 'done t)))
        mode-line-modes))

(defun simple-mode-line-render (left middle right)
  "Return a string of `window-width' length containing LEFT, and RIGHT aligned respectively."
  (let* ((available-width
          (/ (- (window-total-width)
                (+ (length (format-mode-line left))
                   (length (format-mode-line right))
                   (length (format-mode-line middle))))
             2)))
    (append left (list (format (format "%%%ds" available-width) ""))
            middle (list (format (format "%%%ds" available-width) ""))
            right)))

(setq-default mode-line-format
              '((:eval
                 (simple-mode-line-render
                  (quote (" " mode-line-modified
                          " " mode-line-buffer-identification
                          " %l:%c " mode-line-modes " "))
                  (quote ((:propertize
                           (:eval (when vc-mode
                                    (cond
                                     ((string-match "Git[:-]" vc-mode) (-custom-modeline-github-vc))
                                     ((string-match "SVN-" vc-mode) (-custom-modeline-svn-vc))
                                     (t (format "%s" vc-mode)))))
                           face mode-line-vc)))
                  (quote (" " mode-line-misc-info))))))

Move the backup files into the temporaty directory so that they are out of the way.

(setq backup-directory-alist
      `((".*" . ,temporary-file-directory)))
(setq auto-save-file-name-transforms
      `((".*" ,temporary-file-directory t)))

Make emacs follow symlinks every time, this means that it will open the actual file and go to where the file is actually stored instead of editing it through the symlink. This enables the use of git and other version control when editing the file.

(setq vc-follow-symlinks t)

This stops paren mode with interfering with the modeline.

(show-paren-mode 'expression)

Revert the buffer automatically when a file changes on disc. This is useful when monitoring a file such as a log file. It will also do this silently.

(global-auto-revert-mode 1)
(setq auto-revert-verbose nil)

Disable tabs, I want to move towards only using spaces everywhere as that is my preferred style. This is just personal preference though.

(setq-default indent-tabs-mode nil)
(setq-default tab-width 4)
(setq tab-width 4)
(setq-default python-indent-offset 4)
(setq-default c-basic-offset 4)
(setq-default python-indent 4)

Set the line number display very high so that it is always shown in the modeline.

(setq line-number-display-limit 2000000)

Set the undo correctly

(define-key global-map (kbd "C-\\") 'undo-only)

Setting up my keybindings

(defun y/swap-windows ()
  "Swaps two windows and leaves the cursor in the original one"
  (interactive)
  (ace-swap-window)
  (aw-flip-window))

(defun y/exit-emacs-client ()
  "consistent exit emacsclient. If not in emacs client, echo a
  message in minibuffer, don't exit emacs. If in server mode and
  editing file, do C-x # server-edit else do C-x 5 0
  delete-frame"
  (interactive)
  (if server-buffer-clients
      (server-edit)
    (delete-frame)))

(defun y/beautify-json ()
  (interactive)
  (let ((b (if mark-active (min (point) (mark)) (point-min)))
        (e (if mark-active (max (point) (mark)) (point-max))))
    (shell-command-on-region b e
                             "python -m json.tool" (current-buffer) t)))

(use-package pass
  :commands (password-store-copy
             password-store-insert
             password-store-generate))

(define-prefix-command 'y-map)
(global-set-key (kbd "C-c y") 'y-map)

(define-key y-map (kbd "s") 'y/swap-windows)
(define-key y-map (kbd "j") 'y/beautify-json)
(define-key y-map (kbd "p") 'password-store-copy)
(define-key y-map (kbd "i") 'password-store-insert)
(define-key y-map (kbd "g") 'password-store-generate)
(define-key y-map (kbd "r") 'toggle-rot13-mode)

Set the font to Hack, which is an opensource monospace font designed for programming and looking at source code.

(set-default-font "Misc Tamsyn-16")
(setq default-frame-alist '((font . "Misc Tamsyn-16")))
(set-default-font "Iosevka Medium-14")
(setq default-frame-alist '((font . "Iosevka Medium-14")))
(use-package eshell
  :ensure nil
  :bind (("C-c e" . eshell))
  :init
  (defun eshell/vi (&rest args)
    "Invoke `find-file' on the file.
    \"vi +42 foo\" also goes to line 42 in the buffer."
    (while args
      (if (string-match "\\`\\+\\([0-9]+\\)\\'" (car args))
          (let* ((line (string-to-number (match-string 1 (pop args))))
                 (file (pop args)))
            (find-file file)
            (goto-line line))
        (find-file (pop args)))))

  (defun eshell/em (&rest args)
    "Open a file in emacs. Some habits die hard."
    (if (null args)
        (bury-buffer)
      (mapc #'find-file (mapcar #'expand-file-name (eshell-flatten-list (reverse args))))))

  (defun y/eshell-here ()
    "Go to eshell and set current directory to the buffer's directory"
    (interactive)
    (let ((dir (file-name-directory (or (buffer-file-name)
                                        default-directory))))
      (eshell)
      (eshell/pushd ".")
      (cd dir)
      (goto-char (point-max))
      (eshell-kill-input)
      (eshell-send-input))))

Reload

(defun y/reload ()
  (interactive)
  (load-file (expand-file-name "~/.emacs.d/init.el")))

Social

Mail

mu4e is automatically in the load path when installed through a package manager.

For archlinux, the command to install mu4e is:

pacman -S mu

which comes with mu.

Set the email client to be mu4e in emacs, and set the correct mail directory. As I am downloading all the mailboxes, there will be duplicates, which can be ignored in searches by setting mu4e-headers-skip-duplicates.

Also delete messages when they are sent, and don’t copy them over to the sent directory, as Gmail will do that for us.

To download the mail using imap, I use mbsync, which downloads all mail with the -a flag.

Finally, remove buffers when an email has been sent.

(load-user-file "personal.el")

Elfeed

(use-package elfeed-org
  :config
  (elfeed-org)
  (setq rmh-elfeed-org-files
        (list (expand-file-name "~/Annex/Dropbox/org/elfeed.org"))))

(use-package elfeed
  :bind (:map elfeed-search-mode-map
              ("A" . y/elfeed-show-all)
              ("E" . y/elfeed-show-emacs)
              ("D" . y/elfeed-show-daily)
              ("q" . y/elfeed-save-db-and-bury)))

Define utility functions to make the reader work.

(defun y/elfeed-show-all ()
  (interactive)
  (bookmark-maybe-load-default-file)
  (bookmark-jump "elfeed-all"))

(defun y/elfeed-show-emacs ()
  (interactive)
  (bookmark-maybe-load-default-file)
  (bookmark-jump "elfeed-emacs"))

(defun y/elfeed-show-daily ()
  (interactive)
  (bookmark-maybe-load-default-file)
  (bookmark-jump "elfeed-daily"))

;;functions to support syncing .elfeed between machines
;;makes sure elfeed reads index from disk before launching
(defun y/elfeed-load-db-and-open ()
  "Wrapper to load the elfeed db from disk before opening"
  (interactive)
  (elfeed-db-load)
  (elfeed)
  (elfeed-search-update--force))

;;write to disk when quiting
(defun y/elfeed-save-db-and-bury ()
  "Wrapper to save the elfeed db to disk before burying buffer"
  (interactive)
  (elfeed-db-save)
  (quit-window))

Utility

Navigation

Set navigation commands in all the buffers

(defun prev-window ()
  (interactive)
  (other-window -1))

(use-package golden-ratio
  :config
  (golden-ratio-mode))

(defun push-mark-no-activate ()
  "Pushes `point' to `mark-ring' and does not activate the region
   Equivalent to \\[set-mark-command] when \\[transient-mark-mode] is disabled"
  (interactive)
  (push-mark (point) t nil)
  (message "Pushed mark to ring"))

(defun jump-to-mark ()
  "Jumps to the local mark, respecting the `mark-ring' order.
  This is the same as using \\[set-mark-command] with the prefix argument."
  (interactive)
  (set-mark-command 1))

Enable winner mode to save window state.

(winner-mode 1)
(use-package flx)

(use-package ivy
  :bind
  (("C-c s"     . swiper)
   ("M-x"       . counsel-M-x)
   ("C-x C-f"   . counsel-find-file)
   ("C-c g"     . counsel-git)
   ("C-c j"     . counsel-git-grep)
   ("C-c C-r"   . ivy-resume)
   ("C-x b"     . ivy-switch-buffer)
   ("C-x 8 RET" . counsel-unicode-char))
  :config
  (ivy-mode 1)
  (counsel-mode t)
  (setq ivy-use-virtual-buffers t)
  (setq ivy-count-format "(%d/%d) ")
  (define-key minibuffer-local-map (kbd "C-r") 'counsel-minibuffer-history)
  (setq ivy-re-builders-alist
        '((t . ivy--regex-fuzzy))))
(use-package avy
  :bind
  (("C-'" . avy-goto-char-2))
  :config
  (setq avy-keys '(?a ?r ?s ?t ?d ?h ?n ?e ?i ?o)))

Visual

All the icons

(use-package all-the-icons)

Editing

Hungry Delete

(use-package hungry-delete
  :config
  (global-hungry-delete-mode))

SmartParens

(use-package smartparens
  :bind (("M-["              . sp-backward-unwrap-sexp)
         ("M-]"              . sp-unwrap-sexp)
         ("C-M-f"            . sp-forward-sexp)
         ("C-M-b"            . sp-backward-sexp)
         ("C-M-d"            . sp-down-sexp)
         ("C-M-a"            . sp-backward-down-sexp)
         ("C-M-e"            . sp-up-sexp)
         ("C-M-u"            . sp-backward-up-sexp)
         ("C-M-t"            . sp-transpose-sexp)
         ("C-M-n"            . sp-next-sexp)
         ("C-M-p"            . sp-previous-sexp)
         ("C-M-k"            . sp-kill-sexp)
         ("C-M-w"            . sp-copy-sexp)
         ("C-)"              . sp-forward-slurp-sexp)
         ("C-}"              . sp-forward-barf-sexp)
         ("C-("              . sp-backward-slurp-sexp)
         ("C-{"              . sp-backward-barf-sexp)
         ("M-D"              . sp-splice-sexp)
         ("C-]"              . sp-select-next-thing-exchange)
         ("C-<left_bracket>" . sp-select-previous-thing)
         ("C-M-]"            . sp-select-next-thing)
         ("M-F"              . sp-forward-symbol)
         ("M-B"              . sp-backward-symbol)
         ("M-S"              . sp-split-sexp))
  :hook ((minibuffer-setup)  . turn-on-smartparens-strict-mode)
  :config
  (require 'smartparens-config)
  (show-smartparens-global-mode +1)
  (smartparens-global-mode 1)

  (sp-with-modes '(c-mode c++-mode)
    (sp-local-pair "{" nil :post-handlers '(("||\n[i]" "RET")))
    (sp-local-pair "/*" "*/" :post-handlers '((" | " "SPC")
                                              ("* ||\n[i]" "RET")))))

Whitespace

(use-package whitespace
  :bind (("C-x w" . whitespace-mode)))

IEdit

(use-package iedit
  :bind (("C-;" . iedit-mode)))

Expand Region

Expand region is very useful to select words and structures quickly by incrementally selecting more and more of the text.

(use-package expand-region
  :bind ("M-o" . er/expand-region))

Dired

(add-hook 'dired-load-hook
          (function (lambda () (load "dired-x"))))

(setq dired-dwim-target t)

Search

Deadgrep

(use-package deadgrep
  :bind (("C-c d" . deadgrep)))

Yasnippets

(use-package yasnippet
  :config
  (yas-global-mode))

Nix

(use-package direnv
  :config
  (direnv-mode))

Writing

Spellcheck in emacs

(use-package flyspell
  :ensure nil
  :hook
  (text-mode . flyspell-mode)
  :init
  (setq ispell-dictionary "en_GB")
  (setq ispell-dictionary-alist
  '(("en_GB" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_GB") nil utf-8)))
  (setq ispell-program-name (executable-find "hunspell"))
  (setq ispell-really-hunspell t)
  :config
  (define-key flyspell-mode-map (kbd "C-.") nil)
  (define-key flyspell-mode-map (kbd "C-,") nil))

Latex

(use-package latex
  :ensure auctex
  :config
  (require 'tex-site)
  ;; to use pdfview with auctex
  (setq TeX-view-program-selection '((output-pdf "PDF Tools"))
        TeX-view-program-list '(("PDF Tools" TeX-pdf-tools-sync-view))
        TeX-source-correlate-start-server t) ;; not sure if last line is neccessary
  ;; to have the buffer refresh after compilation
  (add-hook 'TeX-after-compilation-finished-functions
            #'TeX-revert-document-buffer)
  (setq TeX-engine 'xetex)
  (setq TeX-auto-save t)
  (setq TeX-parse-self t)
  (setq TeX-command-extra-options "-shell-escape")
  (setq TeX-save-query nil)
  (setq-default TeX-master nil)
  (setq TeX-PDF-mode t)
  (add-hook 'LaTeX-mode-hook 'flyspell-mode)
  (add-hook 'LaTeX-mode-hook 'LaTeX-math-mode)
  (defun turn-on-outline-minor-mode ()
    (outline-minor-mode 1))
  (add-hook 'LaTeX-mode-hook 'turn-on-outline-minor-mode)
  (setq outline-minor-mode-prefix "\C-c \C-o")
  (autoload 'reftex-mode "reftex" "RefTeX Minor Mode" t)
  (autoload 'turn-on-reftex "reftex" "RefTeX Minor Mode" nil)
  (autoload 'reftex-citation "reftex-cite" "Make citation" nil)
  (autoload 'reftex-index-phrase-mode "reftex-index" "Phrase Mode" t)
  (add-hook 'LaTeX-mode-hook 'turn-on-reftex)
  (setq reftex-bibliography-commands '("bibliography" "nobibliography" "addbibresource"))
  (setq org-latex-listings 'minted)
  (require 'ox-latex)
  (add-to-list 'org-latex-packages-alist '("" "minted"))) ; with Emacs latex mode

Markdown

Markdown is the standard for writing documentation. This snippet loads GFM (Github Flavoured Markdown) style.

(use-package markdown-mode
  :commands (markdown-mode gfm-mode)
  :mode (("README\\.md\\'" . gfm-mode)
         ("\\.md\\'"       . markdown-mode)
         ("\\.markdown\\'" . markdown-mode))
  :init (setq markdown-command "multimarkdown"))

Org

(use-package org
  :ensure org-plus-contrib
  :pin org
  :config
  (setq org-log-into-drawer t
        org-log-done "note"
        org-hide-leading-stars t
        org-confirm-babel-evaluate nil
        org-directory (expand-file-name "~/Dropbox/org")
        org-image-actual-width nil
        org-format-latex-options (plist-put org-format-latex-options :scale 1.5)
        org-latex-pdf-process (list "latexmk -lualatex -shell-escape -bibtex -f -pdf %f")
        org-default-notes-file (concat org-directory "/inbox.org")
        org-image-actual-width nil
        org-export-allow-bind-keywords t)

  (eval-after-load "org"
    '(setq org-metaup-hook nil
           org-metadown-hook nil))

  (add-hook 'org-trigger-hook 'save-buffer))

Set up ob for executing code blocks

(use-package ob
  :ensure nil
  :config
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((emacs-lisp . t)
     (js         . t)
     (java       . t)
     (haskell    . t)
     (python     . t)
     (ruby       . t)
     (org        . t)
     (matlab     . t)
     (ditaa      . t)
     (clojure    . t)
     (dot        . t)
     (shell      . t))))

Exporting to html needs htmlize.

(use-package htmlize
  :commands (htmlize-file
             htmlize-buffer
             htmlize-region
             htmlize-many-files
             htmlize-many-files-dired
             htmlize-region-save-screenshot))

Add md backend

(require 'ox-md)

Add org noter

(use-package org-noter
    :after org
    :config (setq org-noter-default-notes-file-names '("notes.org")
                  org-noter-notes-search-path '("~/org/research")
                  org-noter-separate-notes-from-heading t))

(use-package org-ref
  :after org
  :bind (("C-c r" . org-ref-cite-hydra/body)
         ("C-c b" . org-ref-bibtex-hydra/body))
  :init
  (require 'org-ref)
  :config
  (setq org-ref-bibliography-notes "~/Dropbox/bibliography/notes.org"
        org-ref-default-bibliography '("~/Dropbox/bibliography/references.bib")
        org-ref-pdf-directory "~/Dropbox/bibliography/bibtex-pdfs/")
  (setq org-latex-pdf-process (list "latexmk -shell-escape -bibtex -f -pdf %f"))
  (setq org-ref-completion-library 'org-ref-ivy-cite))

Templates

(setq org-capture-templates
      '(("t" "todo" entry (file+headline "~/Dropbox/org/inbox.org" "Tasks")
         "* TODO %?\n\n%i\n%a\n\n")))

Agenda

(setq org-agenda-files (mapcar 'expand-file-name
                               (list "~/Dropbox/org/inbox.org"
                                     "~/Dropbox/org/main.org"
                                     "~/Dropbox/org/tickler.org"
                                     (format-time-string "~/Dropbox/org/journals/%Y-%m.org")))
      org-refile-targets `(("~/Dropbox/org/main.org" :maxlevel . 2)
                           ("~/Dropbox/org/someday.org" :level . 1)
                           ("~/Dropbox/org/tickler.org" :maxlevel . 2)
                           (,(format-time-string "~/Dropbox/org/journals/%Y-%m.org") :maxlevel . 2))
      org-todo-keywords '((sequence "TODO(t)" "WAITING(w)" "|" "DONE(d)" "CANCELLED(c)")))

(setq org-agenda-custom-commands 
      '(("w" "At work" tags-todo "@work"
         ((org-agenda-overriding-header "Work")))
        ("h" "At home" tags-todo "@home"
         ((org-agenda-overriding-header "Home")))
        ("u" "At uni" tags-todo "@uni"
         ((org-agenda-overriding-header "University")))))

Contacts

(setq org-contacts-files (mapcar 'expand-file-name
                                 '("~/Dropbox/org/contacts.org")))

Remove Binding

(define-key org-mode-map (kbd "C-,") nil)

Registers

(set-register ?l (cons 'file "~/.emacs.d/loader.org"))
(set-register ?m (cons 'file "~/Dropbox/org/main.org"))
(set-register ?i (cons 'file "~/Dropbox/org/inbox.org"))
(set-register ?c (cons 'file (format-time-string "~/Dropbox/org/journals/%Y-%m.org")))

Exporting

  (use-package ox-twbs)
  #+EN
** PDF Tools

  (use-package pdf-tools
    :config
    ;; initialise
    (pdf-tools-install)
    ;; open pdfs scaled to fit page
    (setq-default pdf-view-display-size 'fit-page)
    ;; automatically annotate highlights
    (setq pdf-annot-activate-created-annotations t)
    ;; use normal isearch
    (define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward))

Programming

My emacs configuration is mostly focused on programming, therefore there is a lot of different language support.

Version Control and Project Management

Magit

(use-package magit
  :bind (("C-x g" . magit-status))
  :config
  (setq server-switch-hook nil)
  (defadvice forge-create-issue (after adjust-window activate)
    "Adjust the window size using the golden-ratio package when
     creating a new issue"
    (golden-ratio))
  (defadvice magit-status (after adjust-window activate)
    "Adjust the window size using the golden-ratio package when
     getting the status of a repository."
    (golden-ratio)))

Projectile

(use-package projectile
  :config
  (projectile-mode +1)
  (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
  (setq projectile-enable-caching nil)
  (setq projectile-git-submodule-command "")
  (setq projectile-mode-line '(:eval (format " Proj[%s]" (projectile-project-name))))
  (defun projectile-tags-exclude-patterns () ""))

(use-package counsel-projectile
  :config
  (counsel-projectile-mode t))

Diff

(defun command-line-diff (switch)
  (let ((file1 (pop command-line-args-left))
        (file2 (pop command-line-args-left)))
    (ediff file1 file2)))
(add-to-list 'command-switch-alist '("diff" . command-line-diff))
(setq-default ediff-forward-word-function 'forward-char)

Language Support

C++

Setting up CC mode with a hook that uses my settings.

(use-package cc-mode
  :config
  (add-to-list 'auto-mode-alist '("\\.h\\'" . c++-mode))
  (setq c-default-style "linux"
        tab-width 4
        c-indent-level 4)
  (defun my-c++-mode-hook ()
    (c-set-offset 'inline-open 0)
    (c-set-offset 'inline-close 0)
    (c-set-offset 'innamespace 0)
    (c-set-offset 'arglist-cont-nonempty 8)
    (setq indent-tabs-mode nil))
  (add-hook 'c-mode-hook 'my-c++-mode-hook)
  (add-hook 'c++-mode-hook 'my-c++-mode-hook)

  (define-key c-mode-map (kbd "C-c C-c") 'comment-or-uncomment-region))

Adding C headers to company backend for completion.

(use-package irony
  :config
  (add-hook 'c++-mode-hook 'irony-mode)
  (add-hook 'c-mode-hook 'irony-mode)
  (add-hook 'objc-mode-hook 'irony-mode)

  (defun my-irony-mode-hook ()
    (define-key irony-mode-map [remap completion-at-point]
      'irony-completion-at-point-async)
    (define-key irony-mode-map [remap complete-symbol]
      'irony-completion-at-point-async))
  (add-hook 'irony-mode-hook 'my-irony-mode-hook)
  (add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options))

(use-package company-irony)

(use-package flycheck-irony
  :config
  (add-hook 'c++-mode-hook #'flycheck-irony-setup))

(use-package company-c-headers
  :config
  (add-to-list 'company-backends 'company-c-headers)
  (add-to-list 'company-backends 'company-irony)

  (add-hook 'irony-mode-hook 'company-irony-setup-begin-commands))

Using clang format to format the region that is currently being selected (need to install clang format script).

(use-package clang-format
  :bind (("C-c C-i" . 'clang-format-region)
         ("C-c u" . 'clang-format-buffer)))

Clojure

Using Cider for clojure environment.

(use-package cider
  :commands cider-mode
  :config
  (setq cider-repl-display-help-banner nil))

Adding hook to clojure mode to enable strict parentheses mode.

(add-hook 'clojure-mode-hook 'turn-on-smartparens-strict-mode)

CMake

(use-package cmake-mode
  :commands cmake-mode
  :config
  (setq auto-mode-alist
        (append
         '(("CMakeLists\\.txt\\'" . cmake-mode))
         '(("\\.cmake\\'" . cmake-mode))
         auto-mode-alist))
  (autoload 'cmake-mode "~/CMake/Auxiliary/cmake-mode.el" t))

Coq

(use-package proof-general
  :config
  (setq coq-compile-before-require t)
  (defadvice proof-goto-point (after adjust-window-in-proof)
    (golden-ratio)))

Elm

(use-package elm-mode
  :mode ("\\.elm\\'"))

Emacs Lisp

Adding strict parentheses to emacs lisp.

(add-hook 'emacs-lisp-mode-hook 'turn-on-smartparens-strict-mode)

F#

F# mode for uni work.

(use-package fsharp-mode
  :commands fsharp-mode
  :config
  (defun y/fsharp-reload-file ()
    "Reloads the whole file when in fsharp mode."
    (interactive)
    (fsharp-eval-region (point-min) (point-max)))
    (add-hook 'fsharp-mode-hook
            (lambda () (local-set-key (kbd "C-c C-c") #'y/fsharp-reload-file))))

Haskell

Haskell mode with company mode completion.

(defun y/haskell-align-comment (start end)
  (interactive "r")
  (align-regexp start end "\\(\\s-*\\)--"))

(use-package haskell-mode
  :commands haskell-mode
  :bind (("M-." . haskell-mode-jump-to-def))
  :config
  (add-hook 'haskell-mode-hook 'haskell-decl-scan-mode)
  (add-hook 'haskell-mode-hook (lambda ()
                                 (local-set-key (kbd "C-c y a") 'y/haskell-align-comment)))
  (add-hook 'haskell-mode-hook (lambda ()
                                 (local-set-key (kbd "C-c v") 'haskell-add-import)))
  (add-hook 'haskell-mode-hook (lambda ()
                                  (set (make-local-variable 'projectile-tags-command)
                                        "hasktags -Re -f \"%s\" %s \"%s\"")))
  (setq ;;haskell-mode-stylish-haskell-path "brittany"
   haskell-stylish-on-save t
   flycheck-ghc-language-extensions '("OverloadedStrings"))

  (setq haskell-indentation-layout-offset 4
        haskell-indentation-starter-offset 4
        haskell-indentation-left-offset 4
        haskell-indentation-where-pre-offset 2
        haskell-indentation-where-post-offset 2))


(use-package interactive-haskell-mode
  :ensure haskell-mode
  :hook haskell-mode)

Python

Elpy package for python, which provides an IDE type environment for python.

(use-package elpy
  :commands python-mode
  :config
  (elpy-enable)
  (setq py-python-command "python3")
  (setq python-shell-interpreter "python3"))
  (setq tab-width 4)

(with-eval-after-load 'python
  (defun python-shell-completion-native-try ()
    "Return non-nil if can trigger native completion."
    (let ((python-shell-completion-native-enable t)
          (python-shell-completion-native-output-timeout
           python-shell-completion-native-try-output-timeout))
      (python-shell-completion-native-get-completions
       (get-buffer-process (current-buffer))
       nil "_"))))

JSON

JSON files should be opened in js-mode.

(add-to-list 'auto-mode-alist '("\\.json\\'" . js-mode))

SCSS

(use-package css-mode
  :ensure nil
  :commands (scss-mode
             css-mode)
  :config
  (setq css-indent-offset 2))

Scala

(use-package scala-mode)

Shell

(setq sh-basic-offset 2)
(setq sh-indentation 2)

Verilog

(setq flycheck-verilog-verilator-executable "verilator_bin")

Completion Support

Company

(use-package company
  :config
  (add-hook 'after-init-hook 'global-company-mode)
  (setq company-backends (delete 'company-semantic company-backends))

  (define-key c-mode-map (kbd "C-c n") 'company-complete)
  (define-key c++-mode-map (kbd "C-c n") 'company-complete)
  (setq company-dabbrev-downcase 0))

Flycheck

Enabling global flycheck support.

(use-package flycheck
  :config (global-flycheck-mode))

Yasnippets

(use-package yasnippet
  :hook ((org-mode cc-mode) . yas-minor-mode)
  :config
  (yas-minor-mode 1))

SMerge

Shamelessly taken from https://github.com/alphapapa/unpackaged.el#hydra.

(use-package smerge-mode
  :config
  (defhydra unpackaged/smerge-hydra
    (:color pink :hint nil :post (smerge-auto-leave))
    "
^Move^       ^Keep^               ^Diff^                 ^Other^
^^-----------^^-------------------^^---------------------^^-------
_n_ext       _b_ase               _<_: upper/base        _C_ombine
_p_rev       _u_pper              _=_: upper/lower       _r_esolve
^^           _l_ower              _>_: base/lower        _k_ill current
^^           _a_ll                _R_efine
^^           _RET_: current       _E_diff
"
    ("n" smerge-next)
    ("p" smerge-prev)
    ("b" smerge-keep-base)
    ("u" smerge-keep-upper)
    ("l" smerge-keep-lower)
    ("a" smerge-keep-all)
    ("RET" smerge-keep-current)
    ("\C-m" smerge-keep-current)
    ("<" smerge-diff-base-upper)
    ("=" smerge-diff-upper-lower)
    (">" smerge-diff-base-lower)
    ("R" smerge-refine)
    ("E" smerge-ediff)
    ("C" smerge-combine-with-next)
    ("r" smerge-resolve)
    ("k" smerge-kill-current)
    ("ZZ" (lambda ()
            (interactive)
            (save-buffer)
            (bury-buffer))
     "Save and bury buffer" :color blue)
    ("q" nil "cancel" :color blue))
  :hook (magit-diff-visit-file . (lambda ()
                                   (when smerge-mode
                                     (unpackaged/smerge-hydra/body)))))

Look and Feel

Keybindings

(defun y/set-theme (theme)
  (load-theme theme t)
  (toggle-scroll-bar -1))

(defun y/sanityinc-tomorrow-bright ()
  (interactive)
  (y/set-theme 'sanityinc-tomorrow-bright))

(defun y/inkpot ()
  (interactive)
  (y/set-theme 'inkpot))

(defun y/zenburn ()
  (interactive)
  (y/set-theme 'zenburn))

(defun y/solarized-light ()
  (interactive)
  (y/set-theme 'solarized-light))

(defun y/gruvbox ()
  (interactive)
  (y/set-theme 'gruvbox))

(define-key y-map (kbd "1") 'y/sanityinc-tomorrow-bright)
(define-key y-map (kbd "2") 'y/zenburn)
(define-key y-map (kbd "3") 'y/solarized-light)
(define-key y-map (kbd "4") 'y/gruvbox)
(define-key y-map (kbd "5") 'y/inkpot)
(defadvice load-theme
    (before theme-dont-propagate activate)
  (mapc #'disable-theme custom-enabled-themes))

(add-hook 'after-make-frame-functions
              (lambda (frame)
                (select-frame frame)
                (toggle-scroll-bar -1)))

(unless (boundp 'server-process)
  (progn (load-theme 'sanityinc-tomorrow-night t)
         (toggle-scroll-bar -1)))

Conclusion

Setting the gc-cons threshold back to what it was at the beginning.

(server-start)
(setq gc-cons-threshold 10000000)
You can’t perform that action at this time.