diff options
-rw-r--r-- | config.org | 345 |
1 files changed, 151 insertions, 194 deletions
diff --git a/config.org b/config.org index a1bd3e6..08a5418 100644 --- a/config.org +++ b/config.org | |||
@@ -1,136 +1,66 @@ | |||
1 | #+TITLE: Emacs config | 1 | #+TITLE: Emacs configuration, literate style |
2 | #+AUTHOR: Case Duckworth | 2 | #+AUTHOR: Case Duckworth |
3 | # -*- encoding: utf-8-unix -*- | ||
4 | #+BABEL: :cache yes | ||
5 | #+PROPERTY: header-args :tangle init.el | 3 | #+PROPERTY: header-args :tangle init.el |
6 | #+OPTIONS: toc:nil | 4 | #+OPTIONS: toc:nil |
7 | #+BANKRUPTCY_COUNT: 1.5 | 5 | #+BANKRUPTCY_COUNT: 2 |
8 | |||
9 | * Preamble | ||
10 | |||
11 | ** Inspiration | ||
12 | |||
13 | I've been inspired by [[https://github.com/larstvei/dot-emacs][Lars Tveito]]'s config, which does exactly what I | ||
14 | want: =init.el= is small and simple, and is replaced after the first | ||
15 | run by the tangled contents of this file -- =config.org= -- which is | ||
16 | furthermore automatically tangled. | ||
17 | |||
18 | ** Problems with this setup | ||
19 | |||
20 | + While =config.org= automatically tangles, I can't run =(load-file | ||
21 | init.el)= -- it results in an endless loop for some reason. I might | ||
22 | need to look into a hook of some kind. | ||
23 | |||
24 | * License | ||
25 | |||
26 | Copyright © 2020 Case Duckworth <acdw@acdw.net> | ||
27 | |||
28 | This work is free. You can redistribute it and/or modify it under the | ||
29 | terms of the Do What the Fuck You Want To Public License, Version 2, | ||
30 | as published by Sam Hocevar. See the LICENSE file, or below, for more | ||
31 | details. | ||
32 | |||
33 | NOTE: the WTFPL is probably (most definitely!) not compatible with GNU | ||
34 | Emacs's license, and I'm not sure, though I'm pretty confident, that | ||
35 | my =config.org= would be classified as a /derivative work/ under those | ||
36 | terms. Therefore, me licensing my =config.org= under the WTFPL is at | ||
37 | best, unenforceable, and at worst, downright in violation of the GPL. | ||
38 | |||
39 | SUE ME, RMS !!! | ||
40 | |||
41 | #+begin_src text :tangle LICENSE | ||
42 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | ||
43 | |||
44 | Version 2, December 2004 | ||
45 | |||
46 | Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> | ||
47 | |||
48 | Everyone is permitted to copy and distribute verbatim or modified copies of | ||
49 | this license document, and changing it is allowed as long as the name is changed. | ||
50 | |||
51 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | ||
52 | |||
53 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||
54 | |||
55 | 0. You just DO WHAT THE FUCK YOU WANT TO. | ||
56 | |||
57 | #+end_src | ||
58 | 6 | ||
59 | * Bootstrap | 7 | * Bootstrap |
60 | 8 | ||
61 | When this configuration is loaded for the first time, /this/ =init.el= | 9 | ** Original init.el |
62 | is loaded: | ||
63 | 10 | ||
64 | #+begin_src emacs-lisp :tangle no | 11 | #+begin_src emacs-lisp :tangle no |
65 | ;; This file replaces itself with the actual configuration when first | 12 | ;; This file replaces itself with the actual configuration when |
66 | ;; run. To keep only this version tracked by git, run the command | 13 | ;; first run. To keep only this version in git, run this command: |
67 | ;; | 14 | ;; |
68 | ;; git update-index --assume-unchanged init.el | 15 | ;; git update-index --assume-unchanged init.el |
69 | ;; | 16 | ;; |
70 | ;; If it needs to be changed, start tracking it again with the command | 17 | ;; If it needs to be changed, start tracking it again thusly: |
71 | ;; | 18 | ;; |
72 | ;; git update-index --no-assume-unchanged init.el | 19 | ;; git update-index --no-assume-unchanged init.el |
73 | ;; | 20 | |
74 | ;; edit as needed, and run the first command again. | ||
75 | (require 'org) | 21 | (require 'org) |
76 | (find-file (concat user-emacs-directory "config.org")) | 22 | (find-file (concat user-emacs-directory "config.org")) |
77 | (org-babel-tangle) | 23 | (org-babel-tangle) |
78 | (load-file (concat-user-emacs-directory "early-init.el")) | 24 | (load-file (concat user-emacs-directory "early-init.el")) |
79 | (load-file (concat-user-emacs-directory "init.el")) | 25 | (load-file (concat user-emacs-directory "init.el")) |
26 | (byte-compile-file (concat user-emacs-directory "init.el")) | ||
80 | #+end_src | 27 | #+end_src |
81 | 28 | ||
82 | ** Tangling | 29 | ** Tangling |
83 | 30 | ||
84 | After first running Emacs with this config, the above snippet will be | ||
85 | replaced by the result of tangling this file. However, when we edit | ||
86 | =config.org=, we'll need to retangle it. The default keybinding to | ||
87 | tangle is =C-c C-v t=, which takes a while and is easy to forget. So | ||
88 | let's automatically tangle =config.org= on save. | ||
89 | |||
90 | #+NAME: tangle-on-save | ||
91 | #+begin_src emacs-lisp | 31 | #+begin_src emacs-lisp |
92 | ;;; init.el -*- lexical-binding: t; coding: utf-8-unix -*- | 32 | ;; init.el -*- lexical-binding: t -*- |
33 | |||
93 | (defun acdw/tangle-init () | 34 | (defun acdw/tangle-init () |
94 | "If the current buffer is `config.org', the code blocks are | 35 | "If the current buffer is `config.org', tangle it, then compile |
95 | tangled, and the tangled file is compiled and loaded." | 36 | and load the resulting files." |
37 | (when (equal (buffer-file-name) | ||
38 | (expand-file-name | ||
39 | (concat user-emacs-directory "config.org"))) | ||
40 | (let ((prog-mode-hook nil)) | ||
41 | (require 'org) | ||
42 | (org-babel-tangle-file | ||
43 | (expand-file-name | ||
44 | (concat user-emacs-directory "config.org")))))) | ||
45 | |||
46 | (defun acdw/load-init () | ||
96 | (interactive) | 47 | (interactive) |
97 | (let (config-org (expand-file-name | 48 | (load-file (expand-file-name |
98 | (concat user-emacs-directory "config.org"))) | 49 | (concat user-emacs-directory "early-init.el"))) |
99 | (when (equal (buffer-file-name) config-org) | 50 | (load-file (expand-file-name |
100 | (require 'async) | 51 | (concat user-emacs-directory "init.el")))) |
101 | (async-start | ||
102 | `(lambda () | ||
103 | ;; Avoid running hooks when tangling. | ||
104 | (let ((prog-mode-hook nil)) | ||
105 | (require 'org) | ||
106 | (org-babel-tangle-file config-org))) | ||
107 | (lambda (_) | ||
108 | (message "Tangle complete.")))))) | ||
109 | |||
110 | ;; Add a hook to tangle config.org. | ||
111 | (add-hook 'after-save-hook #'acdw/tangle-init) | ||
112 | #+end_src | 52 | #+end_src |
113 | 53 | ||
114 | * Early initiation | 54 | * Early initiation |
115 | 55 | ||
116 | Emacs 27.1+ uses =early-init.el= /in addition to/ =init.el=, mostly | ||
117 | for settings related to packags. Since I use =straight.el= for | ||
118 | package management, I need to specify that in this file. | ||
119 | |||
120 | #+begin_src emacs-lisp :tangle early-init.el | 56 | #+begin_src emacs-lisp :tangle early-init.el |
121 | ;;; early-init.el -*- lexical-binding: t; no-byte-compile: t -*- | 57 | ;; early-init.el -*- lexical-binding: t; no-byte-compile: t -*- |
122 | ;; DO NOT EDIT THIS FILE BY HAND. Edit =config.org= instead! | ||
123 | 58 | ||
124 | (setq load-prefer-newer t) | 59 | (setq load-prefer-newer t) |
125 | 60 | ||
126 | (when (eq system-type 'windows-nt) ; I'm at work | 61 | (when (eq system-type 'windows-nt) |
127 | (add-to-list 'exec-path "~/bin") | 62 | (add-to-list 'exec-path "~/bin") |
128 | (add-to-list 'exec-path | 63 | (add-to-list 'exec-path "C:/Users/aduckworth/Downloads/PortableGit/bin")) |
129 | "C:/Users/aduckworth/Downloads/PortableGit/bin")) | ||
130 | |||
131 | ;; This DOES NOT WORK on Windows. | ||
132 | ;; Download the repo directly from Github and unzip it into | ||
133 | ;; ~/.emacs.d/straight/repos/straight.el. | ||
134 | 64 | ||
135 | (defvar bootstrap-version) | 65 | (defvar bootstrap-version) |
136 | (let ((bootstrap-file | 66 | (let ((bootstrap-file |
@@ -146,128 +76,155 @@ package management, I need to specify that in this file. | |||
146 | (eval-print-last-sexp))) | 76 | (eval-print-last-sexp))) |
147 | (load bootstrap-file nil 'nomessage)) | 77 | (load bootstrap-file nil 'nomessage)) |
148 | 78 | ||
149 | ;; Use-package | ||
150 | |||
151 | (setq straight-use-package-by-default t) | 79 | (setq straight-use-package-by-default t) |
152 | (straight-use-package 'use-package) | 80 | (straight-use-package 'use-package) |
153 | |||
154 | ;; Use-package extra keywords | ||
155 | |||
156 | (use-package use-package-custom-update | ||
157 | :straight (use-package-custom-update | ||
158 | :host github | ||
159 | :repo "a13/use-package-custom-update")) | ||
160 | |||
161 | #+end_src | 81 | #+end_src |
162 | 82 | ||
163 | * Macros | 83 | * Theme |
164 | 84 | ||
165 | ** cuss | 85 | I want to try using the [[https://github.com/kunalb/poet][Poet]] theme. |
166 | 86 | ||
167 | I like =use-package= a lot, but I don't like the weird | 87 | #+begin_src emacs-lisp |
168 | "pseudo-package" things you see with a lot of =use-package= setups | 88 | (use-package poet-theme) |
169 | around the Internet. They're cludgy, they /don't/ actually, in my | 89 | #+end_src |
170 | opinion anyway, make the config any easier to read (how am I supposed | ||
171 | to know what options are in =mule=, for example?!), and most | ||
172 | importantly, =straight.el= doesn't really like them that much. | ||
173 | 90 | ||
174 | *However*, I really like the =:custom= keyword in =use-package=, | 91 | I also want to switch themes between night and day. |
175 | enough to implement it as my own macro. =cuss= will automagically | ||
176 | call =custom-set-variable= or =setq=, whichever is best for the | ||
177 | variable being tweaked. I pulled this straight from =use-package=, | ||
178 | so I /know/ it works! :P | ||
179 | 92 | ||
180 | #+begin_src emacs-lisp | 93 | #+begin_src emacs-lisp |
181 | (defmacro cuss (var val) | 94 | (use-package theme-changer |
182 | "Basically the `:custom' macro from `use-package', by itself." | 95 | :custom |
183 | `(progn | 96 | (calendar-latitude 30.39) |
184 | (funcall (or (get ',var 'custom-set) #'set-default) | 97 | (calendar-longitude -91.83) |
185 | ',var ,val))) | 98 | :config |
186 | ;;; test | 99 | (change-theme 'poet 'poet-dark)) |
187 | #+end_src | 100 | #+end_src |
188 | 101 | ||
189 | * Machines | 102 | * Simplify GUI |
190 | 103 | ||
191 | I use Emacs on a couple of different computers: my two at home, and | 104 | #+begin_src emacs-lisp |
192 | assorted Windows machines at work. I define a couple of constants to | 105 | (menu-bar-mode -1) |
193 | easily keep track of which computer I'm using. | 106 | (tool-bar-mode -1) |
107 | (scroll-bar-mode -1) | ||
108 | |||
109 | (global-visual-line-mode 1) | ||
110 | #+end_src | ||
111 | |||
112 | * Fonts | ||
194 | 113 | ||
195 | #+begin_src emacs-lisp | 114 | #+begin_src emacs-lisp |
196 | (defconst *acdw/at-work* (eq system-type 'windows-nt)) | 115 | (require 'cl) |
116 | (defun font-candidate (&rest fonts) | ||
117 | (loop for font in fonts | ||
118 | when (find-font (font-spec :name font)) | ||
119 | return font)) | ||
120 | |||
121 | (set-face-attribute 'default nil | ||
122 | :font | ||
123 | (font-candidate | ||
124 | "Go Mono-11" | ||
125 | "Consolas-11")) | ||
126 | |||
127 | (set-face-attribute 'fixed-pitch nil | ||
128 | :font | ||
129 | (font-candidate | ||
130 | "Go Mono-11" | ||
131 | "Consolas-11")) | ||
132 | |||
133 | (set-face-attribute 'variable-pitch nil | ||
134 | :font | ||
135 | (font-candidate | ||
136 | "Go-12" | ||
137 | "Georgia-11")) | ||
138 | #+end_src | ||
197 | 139 | ||
198 | (defconst *acdw/at-larry* (string= (system-name) "larry")) | 140 | ** Unicode |
199 | (defconst *acdw/at-bax* (string= (system-name) "bax")) | 141 | |
200 | (defconst *acdw/at-home* (or *acdw/at-larry* *acdw/at-bax*)) | 142 | #+begin_src emacs-lisp |
143 | (use-package unicode-fonts | ||
144 | :config | ||
145 | (unicode-fonts-setup)) | ||
201 | #+end_src | 146 | #+end_src |
202 | 147 | ||
203 | * Files | 148 | ** Variable pitch faces |
204 | 149 | ||
205 | ** Keep .emacs.d tidy | 150 | #+begin_src emacs-lisp |
151 | (add-hook 'text-mode-hook | ||
152 | (lambda () | ||
153 | (variable-pitch-mode 1))) | ||
154 | #+end_ | ||
206 | 155 | ||
207 | By default, Emacs keeps files all over the damn place. I like the | 156 | * TODO Emacs configuration [meta] |
208 | =no-littering= package to keep files in one of two directories -- | ||
209 | =etc/= and =var/=. I'm going to require it right away so that I can | ||
210 | immediately use it. | ||
211 | 157 | ||
212 | #+begin_src emacs-lisp | 158 | ** Keep =~/.emacs.d= tidy |
213 | (use-package no-littering) | ||
214 | (require 'no-littering) | ||
215 | #+end_src | ||
216 | 159 | ||
217 | ** Customize | 160 | * TODO Ease of use |
218 | 161 | ||
219 | I don't use the customize interface -- but sometimes it's good to | 162 | ** Selectrum |
220 | figure out what settings are available for a package. So I keep the | ||
221 | customizations in a file (some people just throw it in =/dev/null=), | ||
222 | but I /don't/ load the file. | ||
223 | 163 | ||
224 | #+begin_src emacs-lisp | 164 | ** Prescient |
225 | (cuss custom-file (no-littering-expand-etc-file-name "custom.el")) | ||
226 | #+end_src | ||
227 | 165 | ||
228 | ** Encoding | 166 | ** CtrlF |
229 | 167 | ||
230 | It's 2020 -- let's use UTF-8 everywhere. Furthermore, even Notepad | 168 | ** Startup |
231 | can figure out Unix line endings (=LF=) -- so let's only use that. | ||
232 | 169 | ||
233 | I'm going to be perfectly honest here. I'm not sure what like, any of | 170 | ** Ignore case |
234 | these do. I just threw everything =utf-8-unix= into a block and hope | ||
235 | for the best. | ||
236 | 171 | ||
237 | #+begin_src emacs-lisp | 172 | * TODO Persistence |
238 | (prefer-coding-system 'utf-8-unix) | 173 | |
239 | (set-default-coding-systems 'utf-8-unix) | 174 | ** Auto-saves |
240 | (set-terminal-coding-system 'utf-8-unix) | 175 | |
241 | (set-keyboard-coding-system 'utf-8-unix) | 176 | ** Backup files |
242 | (set-selection-coding-system 'utf-8-unix) | ||
243 | (set-file-name-coding-system 'utf-8-unix) | ||
244 | (set-clipboard-coding-system 'utf-8-unix) | ||
245 | (set-buffer-file-coding-system 'utf-8-unix) | ||
246 | (cuss locale-coding-system 'utf-8-unix) | ||
247 | (cuss x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)) | ||
248 | #+end_src | ||
249 | 177 | ||
250 | ** Recent files | 178 | ** Recent files |
251 | 179 | ||
252 | Though I haven't used this feature ... yet, maybe if I use the =C-x | 180 | ** Save places in visited files |
253 | C-r= binding that is suggested (like /everywhere/), it'll be easier | ||
254 | for me to use. | ||
255 | 181 | ||
256 | I'm putting =recentf= in a =use-package= declaration, by the way, | 182 | ** Save history |
257 | because even though it's a part of Emacs, it's conveniently in its own | ||
258 | package. | ||
259 | 183 | ||
260 | #+begin_src emacs-lisp | 184 | ** Undo |
261 | (use-package recentf | 185 | |
262 | :custom-update | 186 | * TODO General editing |
263 | (recentf-exclude | 187 | |
264 | (no-littering-var-directory | 188 | ** Undo |
265 | no-littering-etc-directory)) | 189 | |
266 | :custom | 190 | ** Find/replace |
267 | (recentf-max-menu-items 100) | 191 | |
268 | (recentf-max-saved-items 100) | 192 | ** Expand region |
269 | :bind | 193 | |
270 | ("C-x C-r" . recentf-open-files) | 194 | * TODO Writing |
271 | :config | 195 | |
272 | (recentf-mode 1)) | 196 | ** Word count |
273 | #+end_src | 197 | |
198 | ** Visual fill column mode | ||
199 | |||
200 | ** Org mode | ||
201 | |||
202 | * TODO Coding | ||
203 | |||
204 | ** Display | ||
205 | |||
206 | *** Prettify symbols mode | ||
207 | |||
208 | *** Parentheses and frens | ||
209 | |||
210 | *** Line numbers | ||
211 | |||
212 | ** Git | ||
213 | |||
214 | ** Programming languages | ||
215 | |||
216 | *** Shell | ||
217 | |||
218 | *** Lisp | ||
219 | |||
220 | *** Fennel | ||
221 | |||
222 | *** Lua | ||
223 | |||
224 | *** Web (HTML/CSS/JS) | ||
225 | |||
226 | * Applications | ||
227 | |||
228 | ** Elpher | ||
229 | |||
230 | ** Pastebin (0x0) | ||