dotfiles/emacs/.emacs.d/init.el
2016-07-26 02:04:25 +02:00

270 lines
8.6 KiB
EmacsLisp

;;; init.el --- Tom-Emacs Interface -*- lexical-binding: t; -*-
;; Copyright (C) 2016 Tom Willemse
;; Author: Tom Willemse <tom@ryuslash.org>
;; 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 <http://www.gnu.org/licenses/>.
;;; 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)
;;;; Ido:
;; Enable ido.
(ido-mode)
;; Add smex, an ido-like M-x alternative.
(ensure-library smex)
(with-eval-after-load 'smex
(setq smex-save-file (oni:data-location "smex-items")))
(global-set-key (kbd "M-x") 'smex)
(global-set-key (kbd "M-X") 'smex-major-mode-commands)
;; Add ido-ubiquitous, use ido (almost) everywhere.
(ensure-library ido-ubiquitous)
(require 'ido-ubiquitous)
(ido-ubiquitous-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