summary refs log tree commit diff stats
path: root/lisp/+emacs.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/+emacs.el')
-rw-r--r--lisp/+emacs.el434
1 files changed, 0 insertions, 434 deletions
diff --git a/lisp/+emacs.el b/lisp/+emacs.el deleted file mode 100644 index 9158b62..0000000 --- a/lisp/+emacs.el +++ /dev/null
@@ -1,434 +0,0 @@
1;;; +emacs.el --- measured defaults for Emacs -*- lexical-binding: t -*-
2
3;;; Commentary:
4
5;; I find myself copy-pasting a lot of "boilerplate" type code when
6;; bankrupting my Emacs config and starting afresh. Instead of doing
7;; that, I'm putting it here, where it'll be easier to include in my
8;; config.
9
10;; Of course, some might say I could just ... stop bankrupting my
11;; Emacs. But like, why would I want to?
12
13;; Other notable packages include
14;; - https://git.sr.ht/~technomancy/better-defaults/
15;; - https://github.com/susam/emfy
16
17;;; Code:
18
19(require 'early-init (locate-user-emacs-file "early-init.el"))
20
21(defun +set-major-mode-from-buffer-name (&optional buf)
22 "Set the major mode for BUF from the buffer's name.
23Do this only if the buffer is not visiting a file."
24 (unless buffer-file-name
25 (let ((buffer-file-name (buffer-name buf)))
26 (set-auto-mode))))
27
28
29;;; General settings
30
31(setq-default
32 apropos-do-all t
33 async-shell-command-buffer 'new-buffer
34 async-shell-command-display-buffer nil
35 auto-hscroll-mode 'current-line
36 auto-revert-verbose t
37 auto-save-default nil
38 auto-save-file-name-transforms `((".*" ,(.etc "auto-save/") ,(car (secure-hash-algorithms)))
39 (".*" ,(.etc "auto-save/") t))
40 auto-save-interval 30
41 auto-save-list-file-prefix (.etc "auto-save/.saves-" t)
42 auto-save-timeout 30
43 auto-save-visited-interval 5
44 auto-window-vscroll nil
45 backup-by-copying t
46 backup-directory-alist `((".*" . ,(.etc "backup/" t)))
47 blink-cursor-blinks 1
48 comp-deferred-compilation nil
49 completion-category-defaults nil
50 completion-category-overrides '((file (styles . (partial-completion))))
51 completion-ignore-case t
52 completion-styles '(substring partial-completion)
53 create-lockfiles nil
54 cursor-in-non-selected-windows 'hollow
55 cursor-type 'bar
56 custom-file (.etc "custom.el")
57 delete-old-versions t
58 echo-keystrokes 0.1
59 ediff-window-setup-function 'ediff-setup-windows-plain
60 eldoc-echo-area-use-multiline-p nil
61 eldoc-idle-delay 0.1
62 enable-recursive-minibuffers t
63 executable-prefix-env t
64 fast-but-imprecise-scrolling t
65 file-name-shadow-properties '(invisible t intangible t)
66 fill-column 80
67 find-file-visit-truename t
68 frame-resize-pixelwise t
69 global-auto-revert-non-file-buffers t
70 global-mark-ring-max 100
71 hscroll-margin 1
72 hscroll-step 1
73 imenu-auto-rescan t
74 image-use-external-converter (or (executable-find "convert")
75 (executable-find "gm")
76 (executable-find "ffmpeg"))
77 indent-tabs-mode nil
78 inhibit-startup-screen t
79 initial-buffer-choice t
80 kept-new-versions 6
81 kept-old-versions 2
82 kill-do-not-save-duplicates t
83 kill-read-only-ok t
84 kill-ring-max 500
85 kmacro-ring-max 20
86 load-prefer-newer noninteractive
87 major-mode '+set-major-mode-from-buffer-name
88 mark-ring-max 50
89 minibuffer-eldef-shorten-default t
90 minibuffer-prompt-properties (list 'read-only t
91 'cursor-intangible t
92 'face 'minibuffer-prompt)
93 mode-require-final-newline 'visit-save
94 mouse-drag-copy-region t
95 mouse-wheel-progressive-speed nil
96 mouse-yank-at-point t
97 native-comp-async-report-warnings-errors 'silent
98 native-comp-deferred-compilation nil
99 read-answer-short t
100 read-buffer-completion-ignore-case t
101 ;; read-extended-command-predicate
102 ;; (when (fboundp
103 ;; 'command-completion-default-include-p)
104 ;; 'command-completion-default-include-p)
105 read-process-output-max (+bytes 1 :mib) ; We’re in the future man. Set that to at least a megabyte
106 recenter-positions '(top middle bottom)
107 regexp-search-ring-max 100
108 regexp-search-ring-max 200
109 save-interprogram-paste-before-kill t
110 save-some-buffers-default-predicate #'+save-some-buffers-p
111 scroll-conservatively 101
112 scroll-down-aggressively 0.01
113 scroll-margin 2
114 scroll-preserve-screen-position 1
115 scroll-step 1
116 scroll-up-aggressively 0.01
117 search-ring-max 200
118 search-ring-max 200
119 sentence-end-double-space t
120 set-mark-command-repeat-pop t
121 show-paren-delay 0
122 show-paren-style 'parenthesis
123 show-paren-when-point-in-periphery t
124 show-paren-when-point-inside-paren t
125 ;;show-trailing-whitespace t
126 tab-bar-show 1
127 tab-width 8 ; so alignment expecting the default looks right
128 tramp-backup-directory-alist backup-directory-alist
129 undo-limit 100000000 ; 10 MB
130 use-dialog-box nil
131 use-file-dialog nil
132 use-short-answers t
133 vc-follow-symlinks t
134 vc-make-backup-files t
135 version-control t
136 view-read-only t
137 visible-bell nil
138 window-resize-pixelwise t
139 x-select-enable-clipboard t
140 x-select-enable-primary t
141 yank-pop-change-selection t
142 )
143
144;; Programming language offsets.
145;; Set these after the initial block so I can use `tab-width'
146(setq-default
147 c-basic-offset tab-width)
148
149;; Emacs 28 ships with an option, `use-short-answers', that makes this form
150;; obsolete, but I still use 27 at work.
151(when (version< emacs-version "28")
152 (fset 'yes-or-no-p 'y-or-n-p))
153
154
155;;; Encodings
156
157;; Allegedly, this is the only one you need...
158(set-language-environment "UTF-8")
159;; But I still set all of these, for fun.
160(setq-default locale-coding-system 'utf-8-unix
161 coding-system-for-read 'utf-8-unix
162 coding-system-for-write 'utf-8-unix
163 buffer-file-coding-system 'utf-8-unix
164 default-process-coding-system '(utf-8-unix . utf-8-unix)
165 x-select-request-type '(UTF8_STRING
166 COMPOUND_TEXT
167 TEXT
168 STRING))
169
170(set-charset-priority 'unicode)
171(prefer-coding-system 'utf-8-unix)
172(set-default-coding-systems 'utf-8-unix)
173(set-terminal-coding-system 'utf-8-unix)
174(set-keyboard-coding-system 'utf-8-unix)
175
176(pcase system-type
177 ((or 'ms-dos 'windows-nt)
178 (set-clipboard-coding-system 'utf-16-le)
179 (set-selection-coding-system 'utf-16-le))
180 (_
181 (set-selection-coding-system 'utf-8)
182 (set-clipboard-coding-system 'utf-8)))
183
184
185;;; Modes
186
187(dolist (enable-mode '(global-auto-revert-mode
188 blink-cursor-mode
189 electric-pair-mode
190 show-paren-mode
191 global-so-long-mode
192 minibuffer-depth-indicate-mode
193 file-name-shadow-mode
194 minibuffer-electric-default-mode
195 delete-selection-mode
196 auto-save-visited-mode
197 ;; column-number-mode
198 ))
199 (when (fboundp enable-mode)
200 (funcall enable-mode +1)))
201
202(dolist (disable-mode '(tooltip-mode
203 tool-bar-mode
204 menu-bar-mode
205 scroll-bar-mode
206 horizontal-scroll-bar-mode))
207 (when (fboundp disable-mode)
208 (funcall disable-mode -1)))
209
210
211;;; Hooks
212
213(add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p)
214(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
215
216(defun +auto-create-missing-dirs ()
217 "Automatically create missing directories when finding a file."
218 ;; https://emacsredux.com/blog/2022/06/12/auto-create-missing-directories/
219 (let ((target-dir (file-name-directory buffer-file-name)))
220 (unless (file-exists-p target-dir)
221 (make-directory target-dir t))))
222
223(add-hook 'find-file-not-found-functions #'+auto-create-missing-dirs)
224
225(defvar +save-some-buffers-debounce-time nil
226 "Last time `+save-some-buffers-debounce' was run.")
227
228(defcustom +save-some-buffers-debounce-timeout 5
229 "Number of seconds to wait before saving buffers again.")
230
231(defun +save-some-buffers-debounce (&rest _)
232 "Run `save-some-buffers', but only if it's been a while."
233 (unless (and +save-some-buffers-debounce-time
234 (< (- (time-convert nil 'integer) +save-some-buffers-debounce-time)
235 +save-some-buffers-debounce-timeout))
236 (save-some-buffers t)
237 (setq +save-some-buffers-debounce-time (time-convert nil 'integer))))
238
239(add-function :after after-focus-change-function #'+save-some-buffers-debounce)
240
241
242;;; Better-default functions ...
243
244(defun +cycle-spacing (&optional n preserve-nl-back mode)
245 "Negate N argument on `cycle-spacing'.
246That is, with a positive N, deletes newlines as well, leaving -N
247spaces. If N is negative, it will not delete newlines and leave
248N spaces. See docstring of `cycle-spacing' for the meaning of
249PRESERVE-NL-BACK and MODE."
250 (interactive "*p")
251 (cycle-spacing (- n) preserve-nl-back mode))
252
253(defun +save-buffers-quit (&optional arg)
254 "Silently save each buffer, then kill the current connection.
255If the current frame has no client, kill Emacs itself using
256`save-buffers-kill-emacs' after confirming with the user.
257
258With prefix ARG, silently save all file-visiting buffers, then
259kill without asking."
260 (interactive "P")
261 (save-some-buffers t)
262 (if (and (not (frame-parameter nil 'client))
263 (and (not arg)))
264 (when (yes-or-no-p "Sure you want to quit? ")
265 (save-buffers-kill-emacs))
266 (delete-frame nil :force)))
267
268(defun +kill-word-backward-or-region (&optional arg backward-kill-word-fn)
269 "Kill active region or ARG words backward.
270BACKWARD-KILL-WORD-FN is the function to call to kill a word
271backward. It defaults to `backward-kill-word'."
272 (interactive "P")
273 (call-interactively (if (region-active-p)
274 #'kill-region
275 (or backward-kill-word-fn #'backward-kill-word))))
276
277(defun +backward-kill-word-wrapper (fn &optional arg)
278 "Kill backward using FN until the beginning of a word, smartly.
279If point is on at the beginning of a line, kill the previous new
280line. If the only thing before point on the current line is
281whitespace, kill that whitespace.
282
283With argument ARG: if ARG is a number, just call FN
284ARG times. Otherwise, just call FN."
285 ;; I want this to be a wrapper so that I can call other word-killing functions
286 ;; with it. It's *NOT* advice because those functions probably use
287 ;; `backward-kill-word' under the hood (looking at you, paredit), so advice
288 ;; will make things weird.
289 (if (null arg)
290 (cond
291 ((looking-back "^" 1)
292 (let ((delete-active-region nil))
293 (delete-backward-char 1)))
294 ((looking-back "^[ ]*")
295 (delete-horizontal-space :backward-only))
296 (t (call-interactively fn)))
297 (funcall fn (if (listp arg) 1 arg))))
298
299(defun +backward-kill-word (&optional arg)
300 "Kill word backward using `backward-kill-word'.
301ARG is passed to `backward-kill-word'."
302 (interactive "P")
303 (+backward-kill-word-wrapper #'backward-kill-word arg))
304
305;;; ... and advice
306
307;; Indent the region after a yank.
308(defun +yank@indent (&rest _)
309 "Indent the current region."
310 (indent-region (min (point) (mark)) (max (point) (mark))))
311(advice-add #'yank :after #'+yank@indent)
312(advice-add #'yank-pop :after #'+yank@indent)
313
314
315;;; Extra functions
316
317(defun +save-some-buffers-p ()
318 "Predicate for `save-some-buffers-default-predicate'.
319It returns nil with remote files and those without attached files."
320 (and (buffer-file-name)
321 (not (file-remote-p (buffer-file-name)))))
322
323;; https://www.wwwtech.de/articles/2013/may/emacs:-jump-to-matching-paren-beginning-of-block
324(defun +goto-matching-paren (&optional arg)
325 "Go to the matching paren, similar to vi's %."
326 (interactive "p")
327 (or arg (setq arg 1))
328 (cond
329 ;; Check for "outside of bracket" positions
330 ((looking-at "[\[\(\{]") (forward-sexp arg))
331 ((looking-back "[\]\)\}]" 1) (backward-sexp arg))
332 ;; Otherwise, move from inside the bracket
333 ((looking-at "[\]\)\}]") (forward-char) (backward-sexp arg))
334 ((looking-back "[\[\(\{]" 1) (backward-char) (forward-sexp arg))
335 (t (up-list arg t t))))
336
337(defun +delete-window-or-bury-buffer ()
338 "Delete the current window, or bury the current buffer.
339If the current window is the only window, bury the buffer."
340 (interactive)
341 (condition-case e
342 (delete-window)
343 (t (bury-buffer))))
344
345
346;;; Bindings
347
348(global-set-key (kbd "C-x C-c") #'+save-buffers-quit)
349(global-set-key (kbd "M-SPC") #'+cycle-spacing)
350(global-set-key (kbd "M-/") #'hippie-expand)
351(global-set-key (kbd "M-=") #'count-words)
352(global-set-key (kbd "C-x C-b") #'ibuffer)
353(global-set-key (kbd "C-s") #'isearch-forward-regexp)
354(global-set-key (kbd "C-r") #'isearch-backward-regexp)
355(global-set-key (kbd "C-M-s") #'isearch-forward)
356(global-set-key (kbd "C-M-r") #'isearch-backward)
357(global-set-key (kbd "C-x 4 n") #'clone-buffer)
358;; https://christiantietze.de/posts/2022/07/shift-click-in-emacs-to-select/
359(global-set-key (kbd "S-<down-mouse-1>") #'mouse-set-mark)
360(global-set-key (kbd "C-x 0") #'+delete-window-or-bury-buffer)
361
362
363;;; Required libraries
364
365(when (require 'uniquify nil :noerror)
366 (setq-default uniquify-buffer-name-style 'forward
367 uniquify-separator path-separator
368 uniquify-after-kill-buffer-p t
369 uniquify-ignore-buffers-re "^\\*"))
370
371(when (require 'goto-addr)
372 (if (fboundp 'global-goto-address-mode)
373 (global-goto-address-mode +1)
374 (add-hook 'after-change-major-mode-hook 'goto-address-mode)))
375
376(when (require 'recentf nil :noerror)
377 (setq-default recentf-save-file (.etc "recentf.el")
378 recentf-max-menu-items 100
379 recentf-max-saved-items nil
380 recentf-auto-cleanup 'mode)
381 (add-to-list 'recentf-exclude .etc)
382 (recentf-mode +1))
383
384(when (require 'savehist nil :noerror)
385 (setq-default history-length t
386 history-delete-duplicates t
387 history-autosave-interval 60
388 savehist-file (.etc "savehist.el")
389 ;; Other variables --- don't truncate any of these.
390 ;; `add-to-history' uses the values of these variables unless
391 ;; they're nil, in which case it falls back to `history-length'.
392 kill-ring-max 100
393 mark-ring-max 100
394 global-mark-ring-max 100
395 regexp-search-ring-max 100
396 search-ring-max 100
397 kmacro-ring-max 100
398 eww-history-limit 100)
399 (dolist (var '(extended-command-history
400 global-mark-ring
401 mark-ring
402 kill-ring
403 kmacro-ring
404 regexp-search-ring
405 search-ring))
406 (add-to-list 'savehist-additional-variables var))
407 (savehist-mode +1))
408
409(when (require 'saveplace nil :noerror)
410 (setq-default save-place-file (.etc "places.el")
411 save-place-forget-unreadable-files (eq system-type 'gnu/linux))
412 (save-place-mode +1))
413
414;; (when (require 'tramp)
415;; ;; thanks Irreal! https://irreal.org/blog/?p=895
416;; (add-to-list 'tramp-default-proxies-alist
417;; '(nil "\\`root\\'" "/ssh:%h:"))
418;; (add-to-list 'tramp-default-proxies-alist
419;; '((regexp-quote (system-name)) nil nil)))
420
421
422;;; Newer features
423;; These aren't in older version of Emacs, but they're so nice.
424
425(when (fboundp 'repeat-mode)
426 (setq-default repeat-exit-key "g"
427 repeat-exit-timeout 5)
428 (repeat-mode +1))
429
430(when (fboundp 'pixel-scroll-precision-mode)
431 (pixel-scroll-precision-mode +1))
432
433(provide '+emacs)
434;;; +emacs.el ends here