;;; init.el --- Tom-Emacs Interface -*- lexical-binding: t; -*- ;; Copyright (C) 2016 Tom Willemse ;; Author: Tom Willemse ;; Keywords: local ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; This is my personal Emacs configuration. The name was inspired by ;; "Ghost in the Shell 2: Man-Machine Interface" and Ryan Rix's ;; "Complete Computing Environment". ;;; Code: ;;;; Package configuration: ;;; Require package.el since we immediately start using its variables ;;; and functions anyway, no need to delay loading. (require 'package) ;; Add the MELPA and org package archives because I like living on the ;; bleeding edge. This should be done both at run-time and ;; compile-time so I can install packages at compile time. (eval-and-compile (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) (add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/"))) ;; Initialize package.el so that packages can be loaded and used. This ;; also needs to be done at both run-time and compile-time so packages ;; can be installed at compile-time. (eval-and-compile (package-initialize)) ;; Refresh the package contents so packages can be installed from all ;; configured archives. Don't do this at run-time because it slows ;; down the process too much. (eval-when-compile (package-refresh-contents)) ;; This macro is inspired by use-package, but I want to maintain some ;; control of the syntax I use to configure my settings. (defmacro ensure-library (library &rest args) "Make sure LIBRARY is installed. ARGS should be a plist which may contain one of the following options: - :package Specify which package should actually be installed to ensure the library named in LIBRARY exists. - :path Specify a path to add to the load path to be able to load this package." (declare (indent 1)) (let ((library-symbol (cl-gensym)) (package-symbol (cl-gensym)) (path-symbol (cl-gensym)) (package (or (plist-get args :package) library)) (path (plist-get args :path))) `(progn (eval-and-compile (let ((,path-symbol ,path)) (if ,path-symbol (add-to-list 'load-path (if (file-name-absolute-p ,path-symbol) ,path-symbol (concat user-emacs-directory ,path-symbol)))))) (eval-when-compile (let ((,library-symbol ',library) (,package-symbol ',package)) (unless (require ,library-symbol nil :noerror) (package-install ,package-symbol) (require ,library-symbol))))))) ;;;; Helper functions: ;; I have noticed that I refer to the combination of ;; `user-emacs-directory' and "data/" a lot, so I wrote this function ;; to make referencing it cleaner. Also useful if I ever want to move ;; my data directory. (defun oni:data-location (file-name) "Return the location of FILE-NAME within my data directory. This is currently the data directory under the `user-emacs-directory'." (concat user-emacs-directory "data/" file-name)) (with-eval-after-load 'ert (ert-deftest oni:data-location () "Test that `oni:data-location' returns the correct locations." (should (string= "~/.emacs.d/data/backup-files/" (oni:data-location "backup-files/"))) (should (string= "~/.emacs.d/data/auto-save-files/" (oni:data-location "auto-save-files/"))) (should (string= "~/.emacs.d/data/auto-save-list/.saves-" (oni:data-location "auto-save-list/.saves-"))))) ;;;; Backups: ;; I don't like having every directory filled with "filename~" ;; files. So instead of saving backup files to the same directory, ;; save them to a special one instead. (setq backup-directory-alist `((".*" . ,(oni:data-location "backup-files/")))) ;;;; Auto saves: ;; I prefer to keep all autosave files in a single directory so they ;; don't clog up my filesystem so much. Usually these files get ;; deleted, but sometimes they don't, and I don't think they look ;; pretty. Add it to the end of the list because the default value ;; stores auto-saves for remote files in /tmp, which is fine by me. (add-to-list 'auto-save-file-name-transforms `(".*" ,(oni:data-location "auto-save-files/") t) :append) ;; Place the files which contain the auto save files in a similar ;; directory. (setq auto-save-list-file-prefix (oni:data-location "auto-save-list/.saves-")) ;;;; Tabs: ;; Generally I prefer using spaces over tabs. Especially for lisp-like ;; languages. (setq-default indent-tabs-mode nil) ;; A tab-width of 8 is too wide for me, and 2 is too narrow. 4 is just ;; right. (setq-default tab-width 4) ;;;; Font: (defvar oni:preferred-font "Fantasque Sans Mono-13" "My personally preferred font.") ;; This sets the font for normal Emacs sessions. This will change the ;; font for all _existing_ frames, any future frames will not be ;; affected by this. (set-frame-font oni:preferred-font nil t) ;; This sets the font for Emacs daemon-mode sessions. This changes the ;; font for all _future_ frames, but doesn't change anything for the ;; currently existing frames. (add-to-list 'default-frame-alist `(font . ,oni:preferred-font)) ;;;; Menu bar: ;; I don't use the menu bar, so it just takes up space. (menu-bar-mode -1) ;;;; Tool bar: ;; I don't use the tool bar, so it just takes up space. (tool-bar-mode -1) ;;;; Scroll bar: ;; I don't use the scroll bar to either navigate my buffers or see ;; whereabouts I am, so they just take up space. (scroll-bar-mode -1) ;;;; Whitespace: ;; I hate it when trailing whitespace is left around a file. I've been ;; using this for years, and apart from having some trouble working ;; with people who don't pay attention to it, it has worked ;; flawlessly. (ensure-library destroy-trailing-whitespace :path "vendor-lisp/destroy-trailing-whitespace") (require 'destroy-trailing-whitespace) (global-destroy-trailing-whitespace-mode) ;; Having a final newline at the end of the file is always a good ;; idea. Some programs just don't work without it and others produce ;; some strange results. Github diffs are an example. (setq require-final-newline t) ;;;; Load theme: (ensure-library eternal-theme :path "vendor-lisp/eternal-theme") (add-to-list 'custom-theme-load-path (concat user-emacs-directory "vendor-lisp/eternal-theme")) (load-theme 'eternal :no-confirm) ;;;; Ivy: ;;; Ivy is a completing read implementation that offers choises ;;; vertically. (ensure-library ivy) (require 'ivy) ;; Use fuzzy matching in Ivy. (with-eval-after-load 'ivy (setq ivy-re-builders-alist '((t . ivy--regex-fuzzy)) ivy-initial-inputs-alist nil)) (ivy-mode) ;;;; Counsel: ;;; Counsel is a group of functions that use Ivy to specialize on ;;; certain built-in commands, such as M-x. (ensure-library counsel) (require 'counsel) (counsel-mode) ;;;; Minor modes: ;;;;; Paredit: (ensure-library paredit) ;;;; Major modes: ;;;;; Emacs lisp mode: (add-hook 'emacs-lisp-mode-hook 'paredit-mode) ;;;;; Scheme mode: ;; Enable paredit-mode. (add-hook 'scheme-mode-hook 'paredit-mode) ;; Add scsh to the list of known interpreters for scheme mode. (add-to-list 'interpreter-mode-alist '("scsh" . scheme-mode)) ;;;;; Inferior Emacs Lisp mode: (add-hook 'inferior-emacs-lisp-mode-hook 'paredit-mode) ;;;;; Mbsync configuration mode: (ensure-library mbsync-conf-mode :path "vendor-lisp/mbsync-conf-mode") (autoload 'mbsync-conf-mode "mbsync-conf-mode" "Major mode for editing mbsync configuration files." :interactive) (add-to-list 'auto-mode-alist '("\\.mbsyncrc\\'" . mbsync-conf-mode)) ;;;;; Git commit mode: ;; Enable `electric-quote-local-mode' to easily type nice-looking ;; quotes while writing commits. (add-hook 'git-commit-mode-hook 'electric-quote-local-mode) ;;;; Applications: ;;;;; Magit: (ensure-library magit) ;;;; Custom: ;; Put the customize settings in a different file so that Emacs ;; doesn't have to modify this file whenever something changes through ;; customize. (setq custom-file (concat user-emacs-directory "custom.el")) (load custom-file) (provide 'init) ;;; init.el ends here