~hristoast/hristoast

hristoast/site/blog/my-custom-emacs-setup.html -rw-r--r-- 13.1 KiB
27ec638fHristos N. Triantafillou Typo 29 days ago
                                                                                
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
<h1 id="title">My Custom Emacs Setup</h1>

<div id="dates">
  <span>Posted: <time id="post-date">2021-03-06</time></span>
</div>

<p id="post-excerpt">
  It seems to be widely accepted that creating a powerful, useful Emacs setup "by hand" is just too much trouble, and you should choose a "distro" like Doom Emacs. But is it really all so bad? If you go the route of "hand-made", will you suffer through endless nights of fixing your setup? The answer is: probably not, but read on for more details! <span class="footnote"> <a href="https://github.com/hlissner/doom-emacs#doom-emacs">https://github.com/hlissner/doom-emacs#doom-emacs</a> This seems to be one of the more popular Emacs distros at the moment.</span>
</p>

<div id="toc"></div>

<h3>Why Custom?</h3>

<p>
  I've got a lot of respect for the various Emacs "distros" out there, but my inclination for DIY as well as for understanding my tools keeps me from going that route. I'd rather spend some time reading and researching than running a prefab setup that's effectively a mystery to me.
</p>

<p>
  At the end of the day I do spend time on my configuration, but it's hardly the part-time job folks make it out to be. And throughout the years, I've learned a substantial amount about how Emacs actually works.
</p>

<p>
  Prefab setups are usually nice until you hit some usability wall, or find a leak in the abstraction. Sometimes, you end up putting as much effort into learning your abstraction as you would have put into just learning the thing you tried to abstract. This is why I'm fine with getting my hands dirty with Emacs.
</p>

<h3>Desired Features</h3>

<p>
  Before getting into the details of customizing Emacs, it's good to lay out some goals. This will help keep the project focused and prevent you from bloating your setup with things you don't really need. For me, the list looks something like this:
</p>

<ul>
  <li>Automated, idempotent setup that can be repeated easily</li>
  <li>Declaratively install packages</li>
  <li>LSP support for languages that have a supporting server, powerful autocompletion for those that don't</li>
  <li>Quality-of-life packages and modes</li>
  <li>A wealth of custom keybindings to make life better</li>
</ul>

<p>
  I personally don't need a full-on project management system, or deep IDE-like integration, but indeed all of that is available if you'd want it. Anyways, with these goals in mind, let's begin to discuss implementation.
</p>

<h4>Automatic, Idempotent Setup</h4>

<p>
  I want to be able to erase my entire setup, clone it down from a git repo, run Emacs, and be back to where I was before I nuked it all (assuming I've got no local, uncommitted changes). Additionally: I want to have a lockfile-like setup for freezing package versions.
</p>

<h5>straight.el</h5>

<p>
  The <a href="https://github.com/raxod502/straight.el">straight.el</a> package manager is extremely powerful and allows for extreme reproducibility. It does so via:
</p>

<ul>
  <li>Installing packages via git clone versus a tarball or some other archive <span class="footnote"> <a href="https://github.com/raxod502/straight.el/blob/e1390a933b6f5a15079d6dec91eac97a17aad10c/README.md#where-do-packages-come-from">The straight.el README: Where do packages come from?</a></span></li>
  <li>Easy integration of customized packages into your own setup, if desired <span class="footnote"> <a href="https://github.com/raxod502/straight.el/blob/e1390a933b6f5a15079d6dec91eac97a17aad10c/README.md#but-what-about-my-fork-of-obscure-el-package">The straight.el README: But what about my fork of (obscure .el package)?</a></span></li>
  <li>A lockfile for controlling versions of each package <span class="footnote"> <a href="https://github.com/raxod502/straight.el/blob/e1390a933b6f5a15079d6dec91eac97a17aad10c/README.md#lockfile-management">The straight.el README: Lockfile management</a></span></li>
  <li>Integration with <code>use-package</code> (more on that <a href="">later</a>) <span class="footnote"> <a href="https://github.com/raxod502/straight.el/blob/e1390a933b6f5a15079d6dec91eac97a17aad10c/README.md#integration-with-use-package">The straight.el README: Integration with <code>use-package</code></a></span></li>
</ul>

<p>
  The straight.el bootstrap process allows for a totally self-installing setup. For example, with my configuration you just clone my repo to <code>~/.emacs.d</code> and run Emacs; straight.el bootstraps itself and handles installing everything that I need.
</p>

<p>
  Check out the exquisite straight.el documentation or <a href="/init.el">my own init.el</a> file for details about how to get setup. It can do far more than what I've described here, so prepare for a deep dive. <span class="footnote"> <a href="https://github.com/raxod502/straight.el/blob/master/README.md">Here's a straight.el documentation link</a></span>
</p>

<h4>Declarative Package Installation</h4>

<p>
  As described above and in the project README, straight.el brings a nice element of reproducibility and control over packages and versions, but to take it even further I handle all package installations and their related config with <a href="https://jwiegley.github.io/use-package/">use-package</a>.
</p>

<p>
  Integrating use-package with straight.el does require some configuration; again: see the straight.el documentation or <a href="/init.el">my own init.el</a> file for specifics. I strongly advise giving the project README a good look, it is high-quality documentation. <span class="footnote"> <a href="https://github.com/jwiegley/use-package/blob/master/README.md">Here's a use-package documenation link</a></span>
</p>

<h5>use-package: Installing</h5>

<p>
  use-package is extremely powerful and also very simple to use. The straight.el integration is done well too; consider this example for setting up OCaml support:
</p>

<pre><code class="language-lisp">(use-package tuareg :defer t :straight t)</code></pre>

<p>
  The use-package syntax is simple and explicit, but what's happening here?
</p>

<ol>
  <li>I'm installing the <code>tuareg-mode</code> package <span class="footnote"> <a href="https://github.com/ocaml/tuareg">https://github.com/ocaml/tuareg</a></span></li>
  <li>I'm telling use-package to not load this package until it's needed</li>
  <li>I'm telling straight.el to handle the installation</li>
  <li>By default, straight.el will try to find the package on Github</li>
</ol>

<p>
  Of course that's a very simple example; the use-package readme describes all the various features you can use to tune your setup.
</p>

<h5>use-package: Configuring</h5>

<p>
  use-package allows configuring packages before and after they are loaded via the <code>:init</code> and <code>:config</code> keyword arguments, respectively.
</p>

<pre><code class="language-lisp">(use-package flycheck-status-emoji
  :straight t
  :config
  (flycheck-status-emoji-mode))</code></pre>

<pre><code class="language-lisp">(use-package marginalia
  :straight t
  :init
  (marginalia-mode))</code></pre>

<h5>use-package: Key Binds</h5>

<p>
  use-package also allows for configuring key binds on package load:
</p>

<pre><code class="language-lisp">(use-package windmove
  :straight t
  :bind
  ("M-e" . windmove-left)
  ("M-u" . windmove-right)
  ("M-k" . windmove-up)
  ("M-j" . windmove-down))</code></pre>

<p>
  All keybinds then live in your configuration, nicely inside the package declarations themselves.
</p>

<h5>use-package: Hooks</h5>

<p>
  The last feature I'm going to discuss is use-package's syntax for hooks:
</p>

<pre><code class="language-lisp">(use-package html-mode
  :no-require t
  :hook (web-mode . skewer-html-mode))</code></pre>

<p>
  This should be starting to feel familiar, and again it's nice to have hooks defined with the related packages in an idiomatic way.
</p>

<h4>Language Server</h4>

<p>
  But enough about the awesomeness of straight.el and use-package! One of the main things I wanted when I moved to Emacs was a powerful system for auto-completing code. Emacs has several ways to achieve this, but what I've come to use for almost every mode is <a href="https://emacs-lsp.github.io/lsp-mode/">lsp-mode</a> for integrating <a href="https://microsoft.github.io/language-server-protocol/">language server</a> capabilities into Emacs.
</p>

<p>
  I'm using lsp-mode with almost all of the languages I work with regularly, except Lua. At least for now and for me, the current LSP experience with Lua wasn't as good as using company-mode. I'll definitely revisit that in the future though.
</p>

<p>
  There's isnt much else to say that isn't better said on the project documentation: but you can also refer to <a href="https://git.sr.ht/~hristoast/dot-emacs/tree/2bb9a7dd5ca8cb281c4f8a9a8bea0508464b5c63/item/lib/h-lsp.el">my configuration</a> for usage examples if desired.
</p>

<h4>Quality Of Life</h4>

<p>
  Aside from that, there are a number of other things I've tuned to make my Emacs experience more to my liking:
</p>

<ul>
  <li>A dark theme for the editing area <span class="footnote"> <a href="https://git.sr.ht/~hristoast/dot-emacs/tree/2bb9a7dd5ca8cb281c4f8a9a8bea0508464b5c63/item/lib/ui.el#L152"> Via the excellent Material theme</a></span></li>
  <li>A dark theme for the mode line <span class="footnote"> <a href="https://git.sr.ht/~hristoast/dot-emacs/tree/2bb9a7dd5ca8cb281c4f8a9a8bea0508464b5c63/item/lib/ui.el#L132"> Via Smart Mode Line</a></span></li>
  <li>A dashboard or "startup page" <span class="footnote"> <a href="https://git.sr.ht/~hristoast/dot-emacs/tree/2bb9a7dd5ca8cb281c4f8a9a8bea0508464b5c63/item/lib/ui.el#L40"> Via Emacs Dashboard</a></span></li>
  <li>Emoji icons for Flycheck status <span class="footnote"> <a href="https://git.sr.ht/~hristoast/dot-emacs/tree/2bb9a7dd5ca8cb281c4f8a9a8bea0508464b5c63/item/lib/ui.el#L112"> Via the Flycheck Status Emoji package</a></span></li>
  <li>A handful of helper functions</li>
  <li>ws-butler, to clean up whitespace in edited files <span class="footnote"> ws-butler, as seen <a href="https://git.sr.ht/~hristoast/dot-emacs/tree/2bb9a7dd5ca8cb281c4f8a9a8bea0508464b5c63/item/lib/ui.el#L112"> here</a></span></li>
  <li>"TODO" keyword highlighting <span class="footnote"> <a href="https://git.sr.ht/~hristoast/dot-emacs/tree/2bb9a7dd5ca8cb281c4f8a9a8bea0508464b5c63/item/lib/editing.el#L92"> Via hl-todo</a></span></li>
  <li>Rainbow parenthesis <span class="footnote"> <a href="https://git.sr.ht/~hristoast/dot-emacs/tree/2bb9a7dd5ca8cb281c4f8a9a8bea0508464b5c63/item/lib/editing.el#L116"> Via rainbow-delimiters</a></span></li>
  <li>Yasnippet for inserting various snippets <span class="footnote"> Yasnippet, as seen <a href="https://git.sr.ht/~hristoast/dot-emacs/tree/2bb9a7dd5ca8cb281c4f8a9a8bea0508464b5c63/item/lib/editing.el#L209">here</a></span></li>
  <li>And many many more</li>
</ul>

<p>
  Software that's as endlessly customizeable as Emacs allows for all kinds of personal tweaks and touches. Over the year's I've built up my own collection of these and it continues to grow as I learn new things about Emacs.
</p>

<h4>Custom Keybindings</h4>

<p>
  Last but not least: most folks will end up wanting to change a key binding at some point. Some go as far as to change the entire paradigm of the keybinds to do something like offer Vim bindings.
</p>

<p>
  I keep most of the default Emacs bindings but have changed more than a handful to suit my own needs. Some of these are defined with their related packages, others are just general additions or changes to some default Emacs binding. <span class="footnote"> My keybindings, as seen <a href="https://git.sr.ht/~hristoast/dot-emacs/tree/2bb9a7dd5ca8cb281c4f8a9a8bea0508464b5c63/item/lib/keybindings.el">here</a></span>
</p>

<p>
  If you've never done so, I highly encourage taking a look at <code>M-x describe-bindings RET</code>. It's a high-level view of all bindings in your setup.
</p>

<h3>No Abstractions?</h3>

<p>
  Someone on reddit has pointed out that straight.el and use-package are in fact both abstractions. That's a fair point, but in this case I am talking about tools versus kitchen sinks. The abstractions I mentioned in this entry's intro are the kitchen sink variety, whereas straight.el and use-package are more like the tools you would use to build the kitchen sink. <span class="footnote"> <a href="https://old.reddit.com/r/emacs/comments/m0i1s4/my_custom_emacs_setup_hristos_n_triantafillou/gqb6t6c/">https://old.reddit.com/r/emacs/comments/m0i1s4/my_custom_emacs_setup_hristos_n_triantafillou/gqb6t6c/</a></span>
</p>

<p>
  I don't intend to make the argument "abstractions are bad"; they are not in and of themselves a bad thing, of course. Opinions may vary on when one crosses that line, though.
</p>

<h3>Conclusion</h3>

<p>
  This was definitely not written for the unitiated, but I hope it was somewhat useful as a reference to "modding" Emacs.
</p>

<p>
  In particular, I'd like to highlight the power and usefulness of managing the editor configuration with Lisp code rather than clicking endlessly through some user interface (the general experience of most other editors).
</p>

<p>
  Having Lisp specifically and having it so tightly integrated with Emacs is where the majority of this power comes from. Learning to use it and work with it has been and continues to be a really great experience for me.
</p>

<h3>Footnotes And References</h3>

<div id="footnotes"></div>