summary refs log tree commit diff stats
path: root/config.org
diff options
context:
space:
mode:
Diffstat (limited to 'config.org')
-rw-r--r--config.org565
1 files changed, 565 insertions, 0 deletions
diff --git a/config.org b/config.org new file mode 100644 index 0000000..3cebb79 --- /dev/null +++ b/config.org
@@ -0,0 +1,565 @@
1#+TITLE: Emacs config
2#+AUTHOR: Case Duckworth
3#+BABEL: :cache yes
4#+PROPERTY: header-args :tangle init.el
5#+BANKRUPTCY_COUNT: 1
6
7* Preamble
8
9I wanted to write my Emacs configuration in [[https://orgmode.org][Org mode]] for a while, but never could quite figure out how. Finally, I found [[https://github.com/larstvei/dot-emacs][Lars Tveito]]'s config, which does exactly what I want: =init.el= is small and simple, and replaced after the first run, and =init.org= is automatically tangled. So I'm very excited.
10
11* Bootstrap
12
13/Check out Lars's config for the reasoning behind this./
14
15When this configuration is loaded for the first time, this ~init.el~ is loaded:
16
17#+BEGIN_SRC emacs-lisp :tangle no
18 ;; This file replaces itself with the actual configuration when first run. To keep only this version in git, run this command:
19 ;; git update-index --assume-unchanged init.el
20 ;;
21 ;; If it needs to be changed, start tracking it again thusly:
22 ;; git update-index --no-assume-unchanged init.el
23
24 (require 'org)
25 (find-file (concat user-emacs-directory "init.org"))
26 (org-babel-tangle)
27 (load-file (concat user-emacs-directory "init.el"))
28 (byte-compile-file (concat user-emacs-directory "init.el"))
29#+END_SRC
30
31** Tangling
32After the first run, the above ~init.el~ will be replaced by the tangled stuff here. However, when /this/ file is edited, we'll need to re-tangle everything. However, nobody has time to do that manually with =C-c C-v t=, /every time/! Luckily, Emacs is highly programmable.
33
34#+NAME: tangle-on-save
35#+BEGIN_SRC emacs-lisp :tangle no
36 (defun acdw/tangle-init ()
37 "If the current buffer is `init.org', the code blocks are tangled,
38 and the tangled file is compiled and loaded."
39 (when (equal (buffer-file-name)
40 (expand-file-name (concat user-emacs-directory "init.org")))
41 ;; Avoid running hooks when tangling.
42 (let ((prog-mode-hook nil))
43 (org-babel-tangle)
44 (load-file (concat user-emacs-directory "early-init.el"))
45 (load-file (concat user-emacs-directory "init.el")))))
46
47 (add-hook 'after-save-hook #'acdw/tangle-init)
48#+END_SRC
49
50* Early initiation
51Emacs 27.1+ uses ~early-init.el~, which is evaluated before things like ~package.el~ and other stuff. So I have a few settings in there.
52
53** Preamble
54Of course, first thing is the modeline. After that, I set ~load-prefer-newer~ because, well, it /should/.
55#+BEGIN_SRC emacs-lisp :tangle early-init.el
56 ;;; early-init.el -*- lexical-binding: t; no-byte-compile: t -*-
57
58(setq load-prefer-newer t)
59#+END_SRC
60
61** Computers
62I have to set these constants before bootstrapping the package manager, since ~straight.el~ depends on Git, and at work, those are in a weird place.
63
64#+BEGIN_SRC emacs-lisp :tangle early-init.el
65 (defconst *acdw/at-work* (eq system-type 'windows-nt))
66 (defconst *acdw/at-larry* (string= (system-name) "larry"))
67 (defconst *acdw/at-bax* (string= (system-name) "bax"))
68 (defconst *acdw/at-home* (or *acdw/at-larry* *acdw/at-bax*))
69#+END_SRC
70
71** Package management
72 I've started using straight.el, which is great. It grabs packages from git, and apparently will let me fork and edit them, which I'll probably get around to ... eventually.
73
74*** At work, Git's in a weird place
75#+BEGIN_SRC emacs-lisp :tangle early-init.el
76 (when *acdw/at-work*
77 (add-to-list 'exec-path "~/bin")
78 (add-to-list 'exec-path "C:/Users/aduckworth/Downloads/PortableGit/bin"))
79#+END_SRC
80
81*** [[https://github.com/raxod502/straight.el][straight.el]]
82I don't know why, but for some reason the bootstrapping doesn't work on Windows. I have to download the repo directly from github and put it in the right place (=~/.emacs.d/straight/repos/straight.el/=).
83
84#+BEGIN_SRC emacs-lisp :tangle early-init.el
85 (defvar bootstrap-version)
86 (let ((bootstrap-file
87 (expand-file-name "straight/repos/straight.el/bootstrap.el"
88 user-emacs-directory))
89 (bootstrap-version 5))
90 (unless (file-exists-p bootstrap-file)
91 (with-current-buffer
92 (url-retrieve-synchronously
93 "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
94 'silent 'inhibit-cookies)
95 (goto-char (point-max))
96 (eval-print-last-sexp)))
97 (load bootstrap-file nil 'nomessage))
98#+END_SRC
99
100*** [[https://github.com/jwiegley/use-package][use-package]]
101Yeah, you know it, I know it, we all love it. It's use-package.
102#+BEGIN_SRC emacs-lisp :tangle early-init.el
103 (setq straight-use-package-by-default t)
104 (straight-use-package 'use-package)
105#+END_SRC
106* Begin init.el
107#+BEGIN_SRC emacs-lisp :noweb tangle
108 ;;; init.el -*- lexical-binding: t; coding: utf-8 -*-
109 <<tangle-on-save>>
110#+END_SRC
111* Macros
112** cuss
113I like ~use-package~, but I don't like doing the weird "pseudo-package" stuff a lot of people do in their emacs configs. Partially because I have to set ~:straight nil~ on a lot of built-in packages, but also because I think being /that/ obsessive over one interface through the whole config is ... I don't know, short-sighted?
114
115Either way, I /do/ like the ~:custom~ interface that ~use-package~ has, so I've re-implemented it in my own macro. This way I don't have to worry about whether to ~setq~ or ~custom-set-variable~ or whatever. Just ~cuss~!
116#+BEGIN_SRC emacs-lisp
117 (defmacro cuss (var val)
118 "Basically `use-package''s `:custom', but without either."
119 `(progn
120 (funcall (or (get ',var 'custom-set) #'set-default)
121 ',var ,val)))
122#+END_SRC
123* Files
124** [[https://github.com/emacscollective/no-littering][Keep .emacs.d tidy]]
125#+BEGIN_SRC emacs-lisp
126 (straight-use-package 'no-littering)
127 (require 'no-littering)
128#+END_SRC
129** Customize
130I don't like the customize interface, but I still sometimes use it when I'm not sure what the name of a variable is. So I save the stuff to a file, I just don't load it or keep track of it.
131#+BEGIN_SRC emacs-lisp
132 (cuss custom-file (no-littering-expand-etc-file-name "custom.el"))
133#+END_SRC
134** Encoding
135#+BEGIN_SRC emacs-lisp
136 (set-charset-priority 'unicode)
137 (set-language-environment "UTF-8")
138 (set-default-coding-systems 'utf-8)
139 (set-terminal-coding-system 'utf-8)
140 (set-keyboard-coding-system 'utf-8)
141 (set-selection-coding-system 'utf-8)
142 (prefer-coding-system 'utf-8)
143#+END_SRC
144** Recent files
145#+BEGIN_SRC emacs-lisp
146 (use-package recentf
147 :config
148 (add-to-list 'recentf-exclude no-littering-var-directory)
149 (add-to-list 'recentf-exclude no-littering-etc-directory)
150 :custom
151 (recentf-max-menu-items 100)
152 (recentf-max-saved-items 100)
153 :config
154 (recentf-mode 1))
155#+END_SRC
156** Backups
157#+BEGIN_SRC emacs-lisp
158 (cuss backup-directory-alist
159 `((".*" . ,(no-littering-expand-var-file-name "backup/"))))
160#+END_SRC
161** [[https://github.com/bbatsov/super-save][Autosave]]
162#+BEGIN_SRC emacs-lisp
163 (use-package super-save
164 :custom
165 (auto-save-default nil)
166 (super-save-auto-save-when-idle t)
167 (super-save-exclude '(".gpg"))
168 :config
169 (super-save-mode 1))
170#+END_SRC
171** Save places
172#+BEGIN_SRC emacs-lisp
173 (use-package saveplace
174 :custom
175 (save-place-file (no-littering-expand-var-file-name "places"))
176 :config
177 (save-place-mode 1))
178#+END_SRC
179** Save history
180#+BEGIN_SRC emacs-lisp
181 (use-package savehist
182 :custom
183 (savehist-addtional-variables
184 '(kill-ring
185 search-ring
186 regexp-search-ring))
187 (savehist-save-minibuffer-history t)
188 :config
189 (savehist-mode 1))
190#+END_SRC
191* User interface
192** Look
193*** Frames and windows
194**** Frame defaults
195#+BEGIN_SRC emacs-lisp
196 (cuss default-frame-alist '((tool-bar-lines . 0)
197 (menu-bar-lines . 0)
198 (vertical-scroll-bars . nil)
199 (horizontal-scroll-bars . nil)
200 (right-divider-width . 2)
201 (bottom-divider-width . 2)
202 (left-fringe-width . 2)
203 (right-fringe-width . 2)))
204
205 ;; also disable these with modes, so I can re-enable them more easily
206 (menu-bar-mode -1)
207 (tool-bar-mode -1)
208 (scroll-bar-mode -1)
209#+END_SRC
210**** Resizing
211#+BEGIN_SRC emacs-lisp
212 (cuss frame-resize-pixelwise t)
213 (cuss window-combination-resize t)
214#+END_SRC
215*** Buffers
216#+BEGIN_SRC emacs-lisp
217 (cuss uniquify-buffer-name-style 'forward)
218
219 (cuss indicate-buffer-boundaries
220 '((top . right)
221 (bottom . right)
222 (t . nil)))
223#+END_SRC
224**** Startup buffer
225#+BEGIN_SRC emacs-lisp
226 (cuss inhibit-startup-buffer-menu t)
227 (cuss inhibit-startup-screen t)
228 (cuss initial-buffer-choice t) ; start in *scratch*
229 (cuss initial-scratch-message nil)
230#+END_SRC
231*** Cursor
232#+BEGIN_SRC emacs-lisp
233 (cuss cursor-type 'bar)
234 (cuss cursor-in-non-selected-windows 'hollow)
235 (blink-cursor-mode 0)
236#+END_SRC
237*** Interactivity
238**** Mouse
239#+BEGIN_SRC emacs-lisp
240 (cuss mouse-yank-at-point t)
241#+END_SRC
242**** Dialogs
243#+BEGIN_SRC emacs-lisp
244 (cuss use-dialog-box nil)
245#+END_SRC
246**** Disabled functions
247#+BEGIN_SRC emacs-lisp
248 (cuss disabled-command-function nil)
249#+END_SRC
250** Themes: [[https://github.com/protesilaos/modus-themes][Modus]]
251#+BEGIN_SRC emacs-lisp
252 (use-package modus-operandi-theme)
253 (use-package modus-vivendi-theme)
254#+END_SRC
255*** [[https://github.com/hadronzoo/theme-changer][Change themes]] based on time of day
256#+BEGIN_SRC emacs-lisp
257 (use-package theme-changer
258 :init
259 (setq calendar-location-name "Baton Rouge, LA"
260 calendar-latitude 30.39
261 calendar-longitude -91.83)
262 :config
263 (change-theme 'modus-operandi 'modus-vivendi))
264#+END_SRC
265** Modeline: [[https://github.com/Malabarba/smart-mode-line][smart-mode-line]]
266#+BEGIN_SRC emacs-lisp
267 (use-package smart-mode-line
268 :config
269 (sml/setup))
270#+END_SRC
271
272I hide all minor-modes by default for a clean modeline. However, I can add them back by adding them to the whitelist with ~(add-to-list 'rm-whitelist " REGEX")~.
273#+BEGIN_SRC emacs-lisp
274 (use-package rich-minority
275 :custom
276 (rm-whitelist '("^$")))
277#+END_SRC
278** Fonts
279I'm sure there's a better way to do this, but for now, this is the best I've got. I append to the ~face-font-family-alternatives~ because I don't know what kind of weird magic they're doing in there.
280#+BEGIN_SRC emacs-lisp
281 (cuss face-font-family-alternatives
282 '(("Monospace" "courier" "fixed")
283 ("Monospace Serif" "Courier 10 Pitch" "Consolas" "Courier Std" "FreeMono" "Nimbus Mono L" "courier" "fixed")
284 ("courier" "CMU Typewriter Text" "fixed")
285 ("Sans Serif" "helv" "helvetica" "arial" "fixed")
286 ("helv" "helvetica" "arial" "fixed")
287 ;; now mine
288 ("FixedPitch" "DejaVu Sans Mono" "Consolas" "fixed")
289 ("VariablePitch" "DejaVu Serif" "Georgia" "fixed")))
290
291 (set-face-attribute 'default nil
292 :family "FixedPitch"
293 :height 110)
294
295 (set-face-attribute 'fixed-pitch nil
296 :family "FixedPitch"
297 :height 110)
298
299 (set-face-attribute 'variable-pitch nil
300 :family "VariablePitch"
301 :height 110)
302#+END_SRC
303
304*** [[https://github.com/rolandwalker/unicode-fonts][Unicode fonts]]
305#+BEGIN_SRC emacs-lisp
306 (use-package persistent-soft)
307
308 (use-package unicode-fonts
309 :after persistent-soft
310 :config
311 (unicode-fonts-setup))
312
313#+END_SRC
314** Interactivity
315#+begin_src emacs-lisp
316 (fset 'yes-or-no-p #'y-or-n-p)
317#+end_src
318* Editing
319** Completion
320I was using company, but I think it might've been causing issues with ~awk-mode~, so I'm trying ~hippie-mode~ right now. So far, I'm also enjoying not having a popup all the time.
321#+BEGIN_SRC emacs-lisp
322 (bind-key "M-/" #'hippie-expand)
323#+END_SRC
324** Ignore case
325#+BEGIN_SRC emacs-lisp
326 (cuss completion-ignore-case t)
327 (cuss read-buffer-completion-ignore-case t)
328 (cuss read-file-name-completion-ignore-case t)
329#+END_SRC
330** Selection & Minibuffer
331*** Ido
332#+begin_src emacs-lisp
333 (use-package ido
334 :custom
335 (ido-everywhere t)
336 (ido-virtual-buffers t)
337 (ido-use-faces t)
338 (ido-default-buffer-method 'selected-window)
339 (ido-auto-merge-work-directories-length -1)
340 :config
341 (ido-mode 1))
342
343 (use-package flx-ido
344 :after ido
345 :config
346 (flx-ido-mode 1))
347
348 (use-package ido-vertical-mode
349 :after ido
350 :config
351 (ido-vertical-mode 1))
352
353 (use-package ido-completing-read+
354 :after ido
355 :custom
356 (ido-ubiquitous-max-items 50000)
357 (ido-cr+-max-items 50000)
358 :config
359 (ido-ubiquitous-mode 1))
360#+end_src
361*** CtrlF for searching
362#+BEGIN_SRC emacs-lisp
363 (use-package ctrlf
364 :custom
365 (ctrlf-show-match-count-at-eol nil)
366 :config
367 (ctrlf-mode +1))
368#+END_SRC
369** Undo
370#+BEGIN_SRC emacs-lisp
371 (use-package undo-fu
372 :bind
373 ("C-/" . undo-fu-only-undo)
374 ("C-?" . undo-fu-only-redo))
375
376 (use-package undo-fu-session
377 :after no-littering
378 :custom
379 (undo-fu-session-incompatible-files
380 '("/COMMIT_EDITMSG\\'"
381 "/git-rebase-todo\\'"))
382 (undo-fu-session-directory
383 (no-littering-expand-var-file-name "undos/"))
384 :config
385 (global-undo-fu-session-mode +1))
386#+END_SRC
387** Visual editing
388*** ~zap-to-char~ replacement
389#+BEGIN_SRC emacs-lisp
390 (use-package zop-to-char
391 :bind
392 ([remap zap-to-char] . zop-to-char)
393 ([remap zap-up-to-char] . zop-up-to-char))
394#+END_SRC
395*** Operate on a line if there's no current region
396#+BEGIN_SRC emacs-lisp
397 (use-package whole-line-or-region
398 :config
399 (whole-line-or-region-global-mode +1))
400#+END_SRC
401*** Expand-region
402#+BEGIN_SRC emacs-lisp
403 (use-package expand-region
404 :bind
405 ("C-=" . er/expand-region)
406 ("C-+" . er/contract-region))
407#+END_SRC
408*** Volatile highlights
409#+BEGIN_SRC emacs-lisp
410 (use-package volatile-highlights
411 :config
412 (volatile-highlights-mode 1))
413#+END_SRC
414*** Visual line mode
415#+BEGIN_SRC emacs-lisp
416 (global-visual-line-mode 1)
417#+END_SRC
418*** A better ~move-beginning-of-line~
419#+BEGIN_SRC emacs-lisp
420 (defun my/smarter-move-beginning-of-line (arg)
421 "Move point back to indentation of beginning of line.
422
423 Move point to the first non-whitespace character on this line.
424 If point is already there, move to the beginning of the line.
425 Effectively toggle between the first non-whitespace character and
426 the beginning of the line.
427
428 If ARG is not nil or 1, move forward ARG - 1 lines first. If
429 point reaches the beginning or end of the buffer, stop there."
430 (interactive "^p")
431 (setq arg (or arg 1))
432
433 ;; Move lines first
434 (when (/= arg 1)
435 (let ((line-move-visual nil))
436 (forward-line (1- arg))))
437
438 (let ((orig-point (point)))
439 (back-to-indentation)
440 (when (= orig-point (point))
441 (move-beginning-of-line 1))))
442
443 (bind-key "C-a" #'my/smarter-move-beginning-of-line)
444#+END_SRC
445** Delete the selection when typing
446#+BEGIN_SRC emacs-lisp
447 (delete-selection-mode 1)
448#+END_SRC
449** Clipboard
450#+BEGIN_SRC emacs-lisp
451 (cuss save-interprogram-paste-before-kill t)
452#+END_SRC
453** Tabs & Spaces
454#+BEGIN_SRC emacs-lisp
455 (cuss indent-tabs-mode nil)
456 (cuss sentence-end-double-space t)
457#+END_SRC
458* Programming
459** Git
460#+BEGIN_SRC emacs-lisp
461 (use-package magit
462 :bind
463 ("C-x g" . magit-status)
464 :config
465 (add-to-list 'magit-no-confirm 'stage-all-changes))
466
467 (when (executable-find "cmake")
468 (use-package libgit)
469 (use-package magit-libgit))
470
471 (use-package forge
472 :after magit
473 :custom
474 (forge-owned-accounts '(("duckwork"))))
475#+END_SRC
476** Code formatting and display
477#+BEGIN_SRC emacs-lisp
478 (use-package format-all
479 :hook
480 (prog-mode . format-all-mode))
481
482 (add-hook 'prog-mode-hook #'prettify-symbols-mode)
483
484#+END_SRC
485*** Parentheses
486#+BEGIN_SRC emacs-lisp
487 (cuss show-paren-style 'mixed)
488 (show-paren-mode +1)
489
490 (use-package smartparens
491 :init
492 (defun acdw/setup-smartparens ()
493 (require 'smartparens-config)
494 (smartparens-mode +1))
495 :hook
496 (prog-mode . acdw/setup-smartparens))
497
498 (use-package rainbow-delimiters
499 :hook
500 (prog-mode . rainbow-delimiters-mode))
501#+END_SRC
502** Line numbers
503#+BEGIN_SRC emacs-lisp
504 (add-hook 'prog-mode-hook
505 (if (and (fboundp 'display-line-numbers-mode)
506 (display-graphic-p))
507 #'display-line-numbers-mode
508 #'linum-mode))
509#+END_SRC
510** Languages
511*** Lua
512#+BEGIN_SRC emacs-lisp
513 (use-package lua-mode
514 :mode "\\.lua\\'"
515 :interpreter "lua")
516#+END_SRC
517*** Fennel
518#+BEGIN_SRC emacs-lisp
519 (use-package fennel-mode
520 :mode "\\.fnl\\'")
521#+END_SRC
522*** Web
523#+BEGIN_SRC emacs-lisp
524 (use-package web-mode
525 :custom
526 (web-mode-markup-indent-offset 2)
527 (web-mode-code-indent-offset 2)
528 (web-mode-css-indent-offset 2)
529 :mode (("\\.ts\\'" . web-mode)
530 ("\\.html?\\'" . web-mode)
531 ("\\.css?\\'" . web-mode)
532 ("\\.js\\'" . web-mode)))
533#+END_SRC
534* Writing
535* Applications
536** Gemini & Gopher
537#+BEGIN_SRC emacs-lisp
538 (use-package elpher
539 :straight (elpher
540 :repo "git://thelambdalab.xyz/elpher.git")
541 :bind (:map elpher-mode-map
542 ("n" . elpher-next-link)
543 ("p" . elpher-prev-link)
544 ("o" . elpher-follow-current-link)
545 ("G" . elpher-go-current)))
546
547 (use-package gemini-mode
548 :straight (gemini-mode
549 :repo "https://git.carcosa.net/jmcbray/gemini.el.git")
550 :mode "\\.\\(gemini|gmi\\)\\'")
551
552 (use-package gemini-write
553 :straight (gemini-write
554 :repo "https://alexschroeder.ch/cgit/gemini-write"))
555
556 (use-package post-to-gemlog-blue
557 :straight (post-to-gemlog-blue
558 :repo "https://git.sr.ht/~acdw/post-to-gemlog-blue.el"))
559#+END_SRC
560** Pastebin
561#+BEGIN_SRC emacs-lisp
562 (use-package 0x0
563 :custom
564 (0x0-default-service 'ttm))
565#+END_SRC