#+TITLE: GNU Emacs Configuration #+DATE: <2017-08-11 Fri> #+AUTHOR: Yann Herklotz Grave * 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. #+BEGIN_SRC (setq init-dir (file-name-directory (or load-file-name (buffer-file-name)))) (org-babel-load-file (expand-file-name "loader.org" init-dir)) #+END_SRC 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][Programming]] section. It also supports academic writing with org mode using the amazing [[https://github.com/jkitchin/org-ref][org-ref]] package to add citations to the LaTeX output. The configuration for that can be found in the [[#Writing][Writing]] section. #+BEGIN_SRC emacs-lisp (setq user-full-name "Yann Herklotz") (setq user-mail-address "yann@yannherklotz.com") #+END_SRC * 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. #+BEGIN_SRC emacs-lisp (setenv "PATH" (concat "/home/ymherklotz/.local/bin" ":" "/home/ymherklotz/.yarn/bin" ":" "/usr/bin/vendor_perl" ":" "/home/ymherklotz/.nix-profile/bin" ":" (getenv "PATH"))) (setq exec-path (append '("/home/ymherklotz/.local/bin" "/home/ymherklotz/.yarn/bin" "/home/ymherklotz/.nix-profile/bin") exec-path)) #+END_SRC 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 [[https://www.emacswiki.org/emacs/mu4e][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. #+BEGIN_SRC emacs-lisp (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))) (setq load-path (cons (expand-file-name "~/.emacs.d/modes") load-path)) #+END_SRC ** 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. #+BEGIN_SRC emacs-lisp (require 'use-package) (setq use-package-always-ensure t) #+END_SRC ** 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. #+BEGIN_SRC emacs-lisp (setq gc-cons-threshold (* 1024 1024 1024)) #+END_SRC ** 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. #+BEGIN_SRC emacs-lisp (setq warning-minimum-level :emergency) (setq inhibit-startup-message t confirm-nonexistent-file-or-buffer nil default-directory "~/") (setq-default fill-column 80) (setq-default truncate-lines t) (tool-bar-mode 0) (unless (string= system-type "darwin") (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/") (add-to-list 'load-path "~/.emacs.d/modes/") (setq ring-bell-function 'ignore) (when (eq system-type 'darwin) (setq dired-use-ls-dired nil)) #+END_SRC #+BEGIN_SRC emacs-lisp (global-unset-key (kbd "C-z")) (when (eq system-type 'darwin) (setq mac-right-option-modifier 'none mac-option-key-is-meta nil mac-command-key-is-meta t mac-command-modifier 'meta mac-option-modifier nil)) (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 "") #'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) #+END_SRC #+begin_src emacs-lisp (global-visual-line-mode t) #+end_src *** Custom modeline Editing the modeline. ~%c~ might be a bit slow though, so that could be removed if that is ever a problem. #+BEGIN_SRC emacs-lisp (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)))))) #+END_SRC Move the backup files into the temporaty directory so that they are out of the way. #+BEGIN_SRC emacs-lisp (setq backup-directory-alist `((".*" . ,temporary-file-directory))) (setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t))) #+END_SRC 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. #+BEGIN_SRC emacs-lisp (setq vc-follow-symlinks t) #+END_SRC This stops paren mode with interfering with the modeline. #+BEGIN_SRC emacs-lisp (show-paren-mode 'expression) #+END_SRC 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. #+BEGIN_SRC emacs-lisp (global-auto-revert-mode 1) (setq auto-revert-verbose nil) #+END_SRC Disable tabs, I want to move towards only using spaces everywhere as that is my preferred style. This is just personal preference though. #+BEGIN_SRC emacs-lisp (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) #+END_SRC Set the line number display very high so that it is always shown in the modeline. #+BEGIN_SRC emacs-lisp (setq line-number-display-limit 2000000) #+END_SRC Set the undo correctly #+BEGIN_SRC emacs-lisp (define-key global-map (kbd "C-\\") 'undo-only) #+END_SRC Setting up my keybindings #+BEGIN_SRC emacs-lisp (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) #+END_SRC Set the font to Hack, which is an opensource monospace font designed for programming and looking at source code. #+BEGIN_SRC text (set-default-font "Misc Tamsyn-16") (setq default-frame-alist '((font . "Misc Tamsyn-16"))) #+END_SRC #+BEGIN_SRC emacs-lisp (if (string= system-type "darwin") (set-face-attribute 'default nil :family "Iosevka" :height 145 :weight 'normal) (progn (set-default-font "Iosevka Medium-16") (setq default-frame-alist '((font . "Iosevka Medium-16"))))) #+END_SRC #+BEGIN_SRC emacs-lisp (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)))) #+END_SRC *** Reload #+BEGIN_SRC emacs-lisp (defun y/reload () (interactive) (load-file (expand-file-name "~/.emacs.d/init.el"))) #+END_SRC * Social ** Mail ~mu4e~ is automatically in the load path when installed through a package manager. For archlinux, the command to install mu4e is: #+BEGIN_SRC shell pacman -S mu #+END_SRC 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. #+BEGIN_SRC text (load-user-file "personal.el") #+END_SRC ** Elfeed #+BEGIN_SRC emacs-lisp (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))) #+END_SRC Define utility functions to make the reader work. #+BEGIN_SRC emacs-lisp (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)) #+END_SRC * Utility ** Zettelkasten #+begin_src emacs-lisp (when (file-directory-p "~/projects/emacs-zettelkasten") (add-to-list 'load-path "~/projects/emacs-zettelkasten") (require 'zettelkasten) (zettelkasten-mode t)) #+end_src ** Navigation Set navigation commands in all the buffers #+BEGIN_SRC emacs-lisp (defun prev-window () (interactive) (other-window -1)) (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)) #+END_SRC Enable winner mode to save window state. #+BEGIN_SRC emacs-lisp (winner-mode 1) #+END_SRC #+BEGIN_SRC emacs-lisp (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)))) #+END_SRC #+begin_src emacs-lisp (use-package avy :bind (("C-'" . avy-goto-char-2)) :config (setq avy-keys '(?a ?r ?s ?t ?d ?h ?n ?e ?i ?o))) #+end_src ** Visual *** All the icons #+BEGIN_SRC emacs-lisp (use-package all-the-icons) #+END_SRC ** Editing *** Hungry Delete #+BEGIN_SRC emacs-lisp (use-package hungry-delete :config (global-hungry-delete-mode)) #+END_SRC *** SmartParens #+BEGIN_SRC emacs-lisp (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-" . 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"))))) #+END_SRC *** Whitespace #+BEGIN_SRC emacs-lisp (use-package whitespace :bind (("C-x w" . whitespace-mode))) #+END_SRC *** IEdit #+BEGIN_SRC emacs-lisp (use-package iedit :bind (("C-;" . iedit-mode))) #+END_SRC *** Expand Region Expand region is very useful to select words and structures quickly by incrementally selecting more and more of the text. #+BEGIN_SRC emacs-lisp (use-package expand-region :bind ("M-o" . er/expand-region)) #+END_SRC *** Dired #+BEGIN_SRC emacs-lisp (add-hook 'dired-load-hook (function (lambda () (load "dired-x")))) (setq dired-dwim-target t) #+END_SRC ** Search *** Deadgrep #+BEGIN_SRC emacs-lisp (use-package deadgrep :bind (("C-c d" . deadgrep))) #+END_SRC ** Yasnippets #+BEGIN_SRC emacs-lisp (use-package yasnippet :config (yas-global-mode)) #+END_SRC ** Nix #+BEGIN_SRC emacs-lisp (use-package direnv :config (direnv-mode)) #+END_SRC * Writing ** Spellcheck in emacs #+BEGIN_SRC emacs-lisp (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)) #+END_SRC ** Latex #+BEGIN_SRC emacs-lisp (use-package tex-site :ensure auctex :mode (".tex'" . latex-mode) :config ;; 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 'luatex) (setq TeX-auto-save t) (setq TeX-parse-self t) (setq-default 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) (add-to-list 'org-latex-packages-alist '("" "minted")) ; with Emacs latex mode (require 'ox-latex)) #+END_SRC ** Markdown Markdown is the standard for writing documentation. This snippet loads GFM (Github Flavoured Markdown) style. #+BEGIN_SRC emacs-lisp (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")) #+END_SRC ** Org #+BEGIN_SRC emacs-lisp (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)) #+END_SRC Set up ob for executing code blocks #+BEGIN_SRC emacs-lisp (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)))) #+END_SRC Exporting to html needs htmlize. #+BEGIN_SRC emacs-lisp (use-package htmlize :commands (htmlize-file htmlize-buffer htmlize-region htmlize-many-files htmlize-many-files-dired htmlize-region-save-screenshot)) #+END_SRC Add md backend #+BEGIN_SRC emacs-lisp (require 'ox-md) #+END_SRC Add org noter #+BEGIN_SRC emacs-lisp (use-package org-noter :after org :config (setq org-noter-default-notes-file-names '("notes.org") org-noter-notes-search-path '("~/org/bibliography") 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/papers/") (setq org-ref-completion-library 'org-ref-ivy-cite)) #+END_SRC *** Org ID #+begin_src emacs-lisp (use-package org-id :ensure nil :after org) #+end_src *** Templates #+BEGIN_SRC emacs-lisp (setq org-capture-templates '(("t" "todo" entry (file+headline "~/Dropbox/org/inbox.org" "Tasks") "* TODO %?\n\n%i\n%a\n\n") ())) #+END_SRC *** Agenda #+BEGIN_SRC emacs-lisp (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"))))) #+END_SRC *** Contacts #+BEGIN_SRC emacs-lisp (setq org-contacts-files (mapcar 'expand-file-name '("~/Dropbox/org/contacts.org"))) #+END_SRC *** Remove Binding #+BEGIN_SRC emacs-lisp (define-key org-mode-map (kbd "C-,") nil) #+END_SRC *** Registers #+BEGIN_SRC emacs-lisp (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"))) #+END_SRC *** Exporting #+BEGIN_SRC emacs-lisp (use-package ox-twbs) #+END_SRC ** PDF Tools #+BEGIN_SRC emacs-lisp (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)) #+END_SRC ** Writeroom #+begin_src emacs-lisp (use-package writeroom-mode :config (setq writeroom-width 100)) #+end_src * Programming My emacs configuration is mostly focused on programming, therefore there is a lot of different language support. ** Version Control and Project Management *** Magit #+BEGIN_SRC emacs-lisp (use-package magit :bind (("C-x g" . magit-status)) :config (setq server-switch-hook nil)) #+END_SRC *** Projectile #+BEGIN_SRC emacs-lisp (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)) #+END_SRC *** Diff #+BEGIN_SRC emacs-lisp (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) #+END_SRC ** Language Support *** C++ Setting up CC mode with a hook that uses my settings. #+BEGIN_SRC emacs-lisp (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)) #+END_SRC Adding C headers to company backend for completion. #+BEGIN_SRC emacs-lisp (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)) #+END_SRC Using clang format to format the region that is currently being selected (need to install clang format script). #+BEGIN_SRC emacs-lisp (use-package clang-format :bind (("C-c C-i" . 'clang-format-region) ("C-c u" . 'clang-format-buffer))) #+END_SRC *** Clojure Using Cider for clojure environment. #+BEGIN_SRC emacs-lisp (use-package cider :commands cider-mode :config (setq cider-repl-display-help-banner nil)) #+END_SRC Adding hook to clojure mode to enable strict parentheses mode. #+BEGIN_SRC emacs-lisp (add-hook 'clojure-mode-hook 'turn-on-smartparens-strict-mode) #+END_SRC *** CMake #+BEGIN_SRC emacs-lisp (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)) #+END_SRC *** Coq #+begin_src emacs-lisp (use-package proof-general :config (setq coq-compile-before-require t) (setq proof-splash-enable nil)) #+end_src *** Elm #+BEGIN_SRC emacs-lisp (use-package elm-mode :mode ("\\.elm\\'")) #+END_SRC *** Emacs Lisp Adding strict parentheses to emacs lisp. #+BEGIN_SRC emacs-lisp (add-hook 'emacs-lisp-mode-hook 'turn-on-smartparens-strict-mode) #+END_SRC *** F# F# mode for uni work. #+BEGIN_SRC emacs-lisp (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)))) #+END_SRC *** Flex #+begin_src emacs-lisp (add-to-list 'auto-mode-alist '("\\.flex\\'" . c-mode)) #+end_src *** Haskell Haskell mode with company mode completion. #+BEGIN_SRC emacs-lisp (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" 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) #+END_SRC *** LLVM IR #+begin_src emacs-lisp (when (file-exists-p "~/.emacs.d/modes/llvm-mode.el") (require 'llvm-mode)) #+end_src *** HOL #+begin_src emacs-lisp (when (file-exists-p "/opt/hol/tools/hol-mode.el") (setq hol-executable "/opt/hol/bin/hol") (load "/opt/hol/tools/hol-mode.el")) #+end_src *** Python Elpy package for python, which provides an IDE type environment for python. #+BEGIN_SRC emacs-lisp (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 "_")))) #+END_SRC *** JSON JSON files should be opened in js-mode. #+BEGIN_SRC emacs-lisp (add-to-list 'auto-mode-alist '("\\.json\\'" . js-mode)) #+END_SRC *** SCSS #+BEGIN_SRC emacs-lisp (use-package css-mode :ensure nil :commands (scss-mode css-mode) :config (setq css-indent-offset 2)) #+END_SRC *** Scala #+begin_src emacs-lisp (use-package scala-mode) #+end_src *** Shell #+BEGIN_SRC emacs-lisp (setq sh-basic-offset 2) (setq sh-indentation 2) #+END_SRC *** SMTLIBv2 #+begin_src emacs-lisp (require 'smtlib-mode) (add-to-list 'auto-mode-alist '("\\.smt\\'" . smtlib-mode)) #+end_src *** Verilog #+begin_src emacs-lisp (setq flycheck-verilog-verilator-executable "verilator_bin") #+end_src ** Completion Support *** Company #+BEGIN_SRC emacs-lisp (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)) #+END_SRC *** Flycheck Enabling global flycheck support. #+BEGIN_SRC emacs-lisp (use-package flycheck :config (global-flycheck-mode)) #+END_SRC *** Yasnippets #+BEGIN_SRC emacs-lisp (use-package yasnippet :hook ((org-mode cc-mode) . yas-minor-mode) :config (yas-minor-mode 1)) #+END_SRC *** SMerge Shamelessly taken from https://github.com/alphapapa/unpackaged.el#hydra. #+BEGIN_SRC emacs-lisp (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))))) #+END_SRC * Look and Feel #+BEGIN_SRC emacs-lisp (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))) #+END_SRC * Conclusion Setting the gc-cons threshold back to what it was at the beginning. #+BEGIN_SRC emacs-lisp (server-start) (setq gc-cons-threshold (* 1024 1024 10)) #+END_SRC