#+TITLE: GNU Emacs Configuration #+DATE: <2017-08-11 Fri> #+AUTHOR: Yann Herklotz Grave * Introduction This is my GNU Emacs Configuration that is mostly focused on C++ development, but also has support for Python, F#, Haskell and Clojure. #+BEGIN_SRC emacs-lisp (setq user-full-name "Yann Herklotz") (setq user-mail-address "ymherklotz@gmail.com") #+END_SRC #+RESULTS: : ymherklotz@gmail.com * Setup Set path so that it picks up some executables that I use #+BEGIN_SRC emacs-lisp (setenv "PATH" (concat "/home/yannherklotz/.local/bin" ":" "/home/yannherklotz/.yarn/bin" ":" "/usr/bin/vendor_perl" ":" (getenv "PATH"))) #+END_SRC #+RESULTS: : /home/yannherklotz/.local/bin:/home/yannherklotz/.yarn/bin:/usr/bin/vendor_perl:/home/yannherklotz/.local/bin:/home/yannherklotz/.yarn/bin:/usr/local/sbin:/usr/local/bin:/usr/bin #+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))) #+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. #+BEGIN_SRC emacs-lisp (require 'package) (defvar gnu '("gnu" . "https://elpa.gnu.org/packages/")) (defvar melpa '("melpa" . "https://melpa.org/packages/")) (defvar melpa-stable '("melpa-stable" . "https://stable.melpa.org/packages/")) (defvar org-elpa '("org" . "https://orgmode.org/elpa/")) (setq package-archives nil) (add-to-list 'package-archives melpa-stable t) (add-to-list 'package-archives melpa t) (add-to-list 'package-archives gnu t) (add-to-list 'package-archives org-elpa t) (setq package-enable-at-startup nil) (package-initialize) #+END_SRC #+RESULTS: 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 #+RESULTS: : t ** GC Threshold Threshold for faster startup. #+BEGIN_SRC emacs-lisp (setq gc-cons-threshold 500000000) #+END_SRC #+RESULTS: : 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. #+BEGIN_SRC emacs-lisp (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) #+END_SRC #+RESULTS: : t #+BEGIN_SRC emacs-lisp (global-set-key (kbd "M-u") 'upcase-dwim) (global-set-key (kbd "M-l") 'downcase-dwim) (global-set-key (kbd "M-c") 'capitalize-dwim) #+END_SRC #+RESULTS: : capitalize-dwim *** 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))))) (defvar y/mode-line-vc '(: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) "Formats the current directory.") (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)) (setq-default mode-line-format (list " " mode-line-modified " %[" mode-line-buffer-identification "%] %6l:%3c %6 " mode-line-modes " %6 " y/mode-line-vc mode-line-end-spaces)) #+END_SRC #+RESULTS: | | (%1* %1+) | %[ | (%12b) | %] %6l:%3c %6 | (%[ ( (:propertize ( mode-name) help-echo Major mode | 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 #+RESULTS: | .* | /tmp/ | 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. #+BEGIN_SRC emacs-lisp (setq vc-follow-symlinks t) #+END_SRC #+RESULTS: : t Make it easier to refresh the buffer by setting it to ~~. #+BEGIN_SRC emacs-lisp (global-set-key (kbd "") 'revert-buffer) #+END_SRC #+RESULTS: : revert-buffer This stops paren mode with interfering with the modeline. #+BEGIN_SRC emacs-lisp (show-paren-mode 'expression) #+END_SRC #+RESULTS: : t 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 #+RESULTS: 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) (defvaralias 'python-indent-offset 'tab-width) (defvaralias 'c-basic-offset 'tab-width) #+END_SRC #+RESULTS: : tab-width 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 #+RESULTS: : 2000000 Set the undo correctly #+BEGIN_SRC emacs-lisp (define-key global-map (kbd "C-\\") 'undo-only) #+END_SRC #+RESULTS: : undo-only 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) (global-set-key (kbd "C-c q") 'y/exit-emacs-client) (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) #+END_SRC #+RESULTS: : password-store-generate Set the font to Hack, which is an opensource monospace font designed for programming and looking at source code. #+BEGIN_SRC emacs-lisp (set-default-font "Misc Tamsyn-16") (setq default-frame-alist '((font . "Misc Tamsyn-16"))) #+END_SRC #+RESULTS: : ((font . Misc Tamsyn-16)) #+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))) (global-set-key (kbd "C-c i") #'y/eshell-here)) #+END_SRC #+RESULTS: : eshell * Utility ** Navigation Set navigation commands in all the buffers #+BEGIN_SRC emacs-lisp (defun prev-window () (interactive) (other-window -1)) (global-set-key (kbd "C-.") #'other-window) (global-set-key (kbd "C-,") #'prev-window) (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")) (global-set-key (kbd "C-`") 'push-mark-no-activate) (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)) (global-set-key (kbd "M-`") 'jump-to-mark) #+END_SRC #+RESULTS: : jump-to-mark Enable winner mode to save window state. #+BEGIN_SRC emacs-lisp (winner-mode 1) #+END_SRC ** Editing *** Hungry Delete #+BEGIN_SRC emacs-lisp (use-package hungry-delete :config (global-hungry-delete-mode)) #+END_SRC *** Dired #+BEGIN_SRC emacs-lisp (add-hook 'dired-load-hook (function (lambda () (load "dired-x")))) (setq dired-dwim-target t) #+END_SRC * Conclusion Setting the gc-cons threshold back to what it was at the beginning. #+BEGIN_SRC emacs-lisp (setq gc-cons-threshold 10000000) #+END_SRC