1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
|
;;; 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.
(require 'ido)
(ido-mode)
(ido-everywhere)
;; 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)
;; Add ido-flx for flex matching in ido.
(ensure-library flx-ido)
(require 'flx-ido)
;; Enable flex matching and disable faces so `flx-ido-mode' can do its
;; thing.
(with-eval-after-load 'ido
(setq ido-enable-flex-matching t
ido-use-faces nil))
(flx-ido-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
|