about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--emacs515
-rw-r--r--emacs.d/bookmarks33
-rw-r--r--emacs.d/brianna-theme.el7
-rw-r--r--emacs.d/early-init.el282
4 files changed, 690 insertions, 147 deletions
diff --git a/emacs b/emacs index f0f0eb9..5066268 100644 --- a/emacs +++ b/emacs
@@ -1,21 +1,25 @@
1;;; ~/.emacs -*- mode: emacs-lisp; lexical-binding: t; -*- 1;;; ~/.emacs -*- mode: emacs-lisp; lexical-binding: t; -*-
2;; Author Case Duckworth <acdw@acdw.net> 2;; Author: Case Duckworth <acdw@acdw.net>
3;; Bankruptcy: 12 3;; Bankruptcy: 12
4 4
5;;; Initialization -- see also ~/.emacs.d/early-init.el 5;;; Initialization -- see also ~/.emacs.d/early-init.el
6 6
7(setq load-prefer-newer t)
8
7(setopt custom-file (locate-user-emacs-file "custom.el")) 9(setopt custom-file (locate-user-emacs-file "custom.el"))
8(load custom-file :no-error) 10(load custom-file :no-error)
11(add-hook 'Custom-mode-hook
12 (lambda () (run-with-idle-timer 0.25 nil #'custom-show-all-widgets)))
9 13
10(defvar user-private-file (locate-user-emacs-file "private.el") 14(defvar user-private-file (locate-user-emacs-file "private.el")
11 "Private customizations") 15 "Private customizations")
12;; make sure it's really private! 16;; make sure it's really private!
13(and (= (file-attribute-user-id (file-attributes user-private-file)) 17(and (= (file-attribute-user-id (file-attributes user-private-file))
14 (user-uid)) ; is it owned by this me? 18 (user-uid)) ; is it owned by this me?
15 (set-file-modes user-private-file #o600)) 19 (set-file-modes user-private-file #o600))
16(load user-private-file :no-error) 20(load user-private-file :no-error)
17 21
18(load-theme 'brianna :no-confirm) ; see ~/.emacs.d/brianna-theme.el 22(load-theme 'brianna :no-confirm) ; see ~/.emacs.d/brianna-theme.el
19(add-hook 'after-init-hook #'setup-faces) 23(add-hook 'after-init-hook #'setup-faces)
20 24
21(define-advice startup-echo-area-message (:override ()) 25(define-advice startup-echo-area-message (:override ())
@@ -25,16 +29,22 @@
25 29
26;;; Basic settings 30;;; Basic settings
27 31
32;; Auth
33(package-ensure '(keepassxc-shim
34 :url "https://codeberg.org/acdw/keepassxc-shim.el"))
35(keepassxc-shim-activate)
36(setopt auth-sources '("secrets:default"))
37(add-hook 'auth-info-hook #'truncate-lines-local-mode)
38
28;; Environment 39;; Environment
29(setenv "PAGER" "cat") ; emacs is a pager 40(setenv "PAGER" "cat") ; emacs is a pager
30(setenv "TERM" "dumb") ; no fancy graphics! 41(setenv "TERM" "dumb") ; no fancy graphics!
31(setenv "NO_COLOR" "1") ; no color! 42(setenv "NO_COLOR" "1") ; no color!
32 43
33;; Startup 44;; Startup
34(setopt inhibit-startup-screen t) 45(setopt inhibit-startup-screen t)
35(setopt initial-buffer-choice #'eshell) 46(setopt initial-buffer-choice #'eshell)
36(setopt initial-scratch-message ";; *scratch*") 47(setopt initial-scratch-message nil)
37(setopt initial-major-mode #'emacs-lisp-mode)
38 48
39;; Dialogs 49;; Dialogs
40(setopt use-dialog-box nil) 50(setopt use-dialog-box nil)
@@ -47,38 +57,138 @@
47(blink-cursor-mode -1) 57(blink-cursor-mode -1)
48 58
49;; Whitespace 59;; Whitespace
50(setopt whitespace-style '(face trailing tabs tab-mark))
51(setopt whitespace-global-modes '(not rcirc-mode jabber-chat-mode))
52;; (global-whitespace-mode)
53(add-hook 'before-save-hook #'delete-trailing-whitespace-except-current-line) 60(add-hook 'before-save-hook #'delete-trailing-whitespace-except-current-line)
54(set-face-attribute 'whitespace-tab nil :background nil :foreground "#888")
55(setf (alist-get 'tab-mark whitespace-display-mappings)
56 '(9 [?· 9] [?» 9] [?\\ 9]))
57 61
58(add-hook 'after-init-hook 62(setopt whitespace-style '(face trailing tabs tab-mark))
59 (lambda () (add-hook 'before-save-hook #'indent-buffer+))) 63(setopt whitespace-global-modes '(not rcirc-mode jabber-chat-mode))
64(global-whitespace-mode)
65(hide-minor-mode 'global-whitespace-mode)
66(with-eval-after-load 'whitespace
67 (setf/alist whitespace-display-mappings 'tab-mark
68 '(9 [?· 9] [?» 9] [?\\ 9])))
69
70;; Automatically indent buffer when saving
71(define-minor-mode indent-on-save-mode
72 "Automatically re-indent the buffer on save."
73 :lighter " >"
74 (if indent-on-save-mode
75 (add-hook 'before-save-hook #'fixup-whitespace nil t)
76 (remove-hook 'before-save-hook #'fixup-whitespace t)))
77
78(add-hook 'prog-mode-hook #'indent-on-save-mode)
79
80;; Comments
81(setopt comment-column 0)
82(setopt comment-indent-offset 1)
60 83
61;;; UI stuff 84;;; UI stuff
62 85
63(setopt tab-bar-show 1)
64
65;; Elastic-modes
66(package-ensure 'dash) ; requirement for `elastic-modes'
67(package-ensure '(elastic-modes
68 :url "https://github.com/jyp/elastic-modes"
69 :main-file "elastic-pkg.el"))
70(require 'elastic-indent)
71(add-hook 'prog-mode-hook #'elastic-indent-mode)
72 86
73;; Fixed-pitch 87;; Fixed-pitch
74(package-ensure '(fixed-pitch-mode 88(define-minor-mode fixed-pitch-mode
75 :url "https://github.com/cstby/fixed-pitch-mode.git")) 89 "Use a monospace typeface."
76;; (require 'fixed-pitch) 90 :lighter " f"
91 (setq cursor-type (if fixed-pitch-mode 'box 'bar))
92 (buffer-face-set (and fixed-pitch-mode 'fixed-pitch)))
93(define-globalized-minor-mode auto-fixed-pitch-mode
94 fixed-pitch-mode fixed-pitch-mode
95 :predicate '(special-mode
96 prog-mode))
97
77(setopt cursor-type 'bar) 98(setopt cursor-type 'bar)
78;; (setopt fixed-pitch-use-extended-default t) 99(hide-minor-mode 'buffer-face-mode)
79;; (add-to-list 'fixed-pitch-whitelist-hooks 'vc-dir-mode-hook) 100(add-hook 'fixed-pitch-mode-hook #'display-fill-column-indicator-mode)
80;; (hide-minor-mode 'buffer-face-mode) 101(auto-fixed-pitch-mode)
81;; (add-hook 'fixed-pitch-mode-hook #'display-fill-column-indicator-mode) 102
103(package-ensure 'valign) ; needed for variable-pitch org-mode
104(add-hook 'org-mode-hook #'valign-mode)
105(setopt valign-fancy-bar t)
106
107;;; Mode line
108
109(setopt mode-line-position-line-format '("%l"))
110(setopt mode-line-position-column-line-format '("%l:%c"))
111
112(package-ensure 'minions)
113
114(defvar mode-line-major-mode-keymap*
115 (let ((map (make-sparse-keymap)))
116 (bindings--define-key map [mode-line down-mouse-1]
117 `(menu-item "Menu Bar" ignore
118 :filter ,(lambda (_) (mouse-menu-major-mode-map))))
119 (define-key map [mode-line mouse-2] #'describe-mode)
120 (define-key map [mode-line mouse-3] #'minions-minor-modes-menu)
121 map)
122 "Keymap to display on major mode.")
123
124(defun make-mode-line-mode-disabler (lighter help mode)
125 (propertize lighter
126 'help-echo (concat help "\n1:cancel")
127 'face 'italic
128 'mouse-face 'mode-line-highlight
129 'local-map
130 (make-mode-line-mouse-map
131 'mouse-1 (lambda (ev) (interactive "e")
132 (with-selected-window
133 (posn-window (event-start ev))
134 (funcall mode -1)
135 (force-mode-line-update))))))
136
137(setopt mode-line-format
138 `("%e"
139 mode-line-front-space
140 (:propertize ("" mode-line-modified mode-line-remote)
141 display (min-width (5.0)))
142 " %[" mode-line-buffer-identification " %]"
143 (vc-mode (" [" vc-mode "]"))
144 " ( "
145 (:propertize ("" mode-name)
146 help-echo "Major mode\n1:menu\n2:help\n3:minor"
147 mouse-face mode-line-highlight
148 local-map ,mode-line-major-mode-keymap*)
149 (auto-fill-function
150 ,(make-mode-line-mode-disabler "-f" "Auto-filling"
151 #'auto-fill-mode))
152 (visual-line-mode
153 ,(make-mode-line-mode-disabler "-v" "Visual lines"
154 #'visual-line-mode))
155 (truncate-lines-local-mode
156 ,(make-mode-line-mode-disabler "-t" "Truncating lines"
157 #'truncate-lines-local-mode))
158 " "
159 (defining-kbd-macro (:propertize "🔴" help-echo "Defining kbd macro"))
160 (isearch-mode (:propertize "🔍" help-echo "Searching"))
161 (overwrite-mode
162 ,(make-mode-line-mode-disabler "✒️" "Overwriting"
163 #'overwrite-mode))
164 (debug-on-error
165 ,(make-mode-line-mode-disabler "‼️" "Debug on error"
166 (lambda (_)
167 (setq debug-on-error nil))))
168 (debug-on-quit
169 ,(make-mode-line-mode-disabler "🚫" "Debug on quit"
170 (lambda (_)
171 (setq debug-on-quit nil))))
172 ") "
173 (mode-line-process (" " mode-line-process " "))
174 " " (:propertize (line-number-mode
175 (column-number-mode
176 (:propertize "%l/%c" help-echo "Line/column")
177 (:propertize "%l" help-echo "Line"))
178 (column-number-mode
179 (:propertize "/%c" help-echo "Column")
180 ""))
181 display (min-width (5.0)))
182 (:propertize (" [" (-3 "%o") "]")
183 help-echo "Position in buffer"
184 display (min-width (6.0)))
185 ,(propertize "%n"
186 'help-echo "Narrowed\n1:widen"
187 'mouse-face 'mode-line-highlight
188 'local-map (make-mode-line-mouse-map
189 'mouse-1 #'mode-line-widen))
190 (so-long-mode-line-info
191 (" -- " so-long-mode-line-info))))
82 192
83;;; Completions 193;;; Completions
84 194
@@ -99,15 +209,35 @@
99(setopt completions-format 'one-column) 209(setopt completions-format 'one-column)
100(setopt completions-max-height 10) 210(setopt completions-max-height 10)
101 211
212(setf/alist display-buffer-alist "\\`\\*Completions\\*\\'"
213 '(nil (window-parameters (mode-line-format . " --- %b"))))
214
102(keymap-set minibuffer-local-map "C-p" #'minibuffer-previous-completion) 215(keymap-set minibuffer-local-map "C-p" #'minibuffer-previous-completion)
103(keymap-set minibuffer-local-map "C-n" #'minibuffer-next-completion) 216(keymap-set minibuffer-local-map "C-n" #'minibuffer-next-completion)
104(keymap-set minibuffer-local-map "M-DEL" #'minibuffer-delete-directory) 217(keymap-set minibuffer-local-map "M-DEL" #'minibuffer-delete-directory)
218(keymap-set completion-list-mode-map "C-g" #'quit-window) ; is this a good idea?
219
220;; Corfu --- tryin this out
221
222(package-ensure 'corfu t)
223(keymap-set corfu-map "TAB" #'corfu-next)
224(keymap-set corfu-map "<tab>" #'corfu-next)
225(keymap-set corfu-map "S-TAB" #'corfu-previous)
226(keymap-set corfu-map "<backtab>" #'corfu-previous)
227(global-corfu-mode)
228
229;;; Minibuffer
105 230
106(setopt enable-recursive-minibuffers t) 231(setopt enable-recursive-minibuffers t)
107(setopt minibuffer-default-prompt-format " [%s]") 232(setopt minibuffer-default-prompt-format " [%s]")
108(minibuffer-depth-indicate-mode) 233(minibuffer-depth-indicate-mode)
109(minibuffer-electric-default-mode) 234(minibuffer-electric-default-mode)
110 235
236(setopt minibuffer-prompt-properties '( read-only t
237 cursor-intangible t
238 face minibuffer-prompt))
239(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
240
111(setopt file-name-shadow-properties '(invisible t intangible t)) 241(setopt file-name-shadow-properties '(invisible t intangible t))
112(file-name-shadow-mode) 242(file-name-shadow-mode)
113 243
@@ -115,6 +245,18 @@
115(setopt history-delete-duplicates t) 245(setopt history-delete-duplicates t)
116(setopt savehist-save-minibuffer-history t) 246(setopt savehist-save-minibuffer-history t)
117(setopt savehist-autosave-interval 5) 247(setopt savehist-autosave-interval 5)
248(setopt savehist-additional-variables
249 '(kill-ring
250 command-history
251 set-variable-value-history
252 custom-variable-history
253 query-replace-history
254 read-expression-history
255 minibuffer-history
256 read-char-history
257 face-name-history
258 bookmark-history
259 file-name-history))
118(savehist-mode) 260(savehist-mode)
119 261
120(define-minor-mode truncate-lines-local-mode 262(define-minor-mode truncate-lines-local-mode
@@ -131,12 +273,12 @@
131(advice-add 'text-scale-adjust :after #'visual-fill-column-adjust) 273(advice-add 'text-scale-adjust :after #'visual-fill-column-adjust)
132 274
133(package-ensure 'adaptive-wrap) 275(package-ensure 'adaptive-wrap)
134(add-hook 'visual-fill-column-mode #'adaptive-wrap-prefix-mode) 276(add-hook 'visual-line-mode #'adaptive-wrap-prefix-mode)
135 277
136;; Consult/Marginalia 278;;; Completing-read and friends
137 279
138(package-ensure 'consult) 280;; Consult
139(require 'consult) 281(package-ensure 'consult t)
140(keymap-global-set "C-x b" #'consult-buffer) 282(keymap-global-set "C-x b" #'consult-buffer)
141(keymap-global-set "C-x 4 b" #'consult-buffer-other-window) 283(keymap-global-set "C-x 4 b" #'consult-buffer-other-window)
142(keymap-global-set "C-x 5 b" #'consult-buffer-other-frame) 284(keymap-global-set "C-x 5 b" #'consult-buffer-other-frame)
@@ -160,9 +302,32 @@
160(setopt xref-show-definitions-function #'xref-show-definitions-completing-read) 302(setopt xref-show-definitions-function #'xref-show-definitions-completing-read)
161(setopt consult-preview-key "M-.") 303(setopt consult-preview-key "M-.")
162 304
305(define-advice completing-read-multiple (:filter-args (args) indicator)
306 (cons (format "[CRM%s] %s"
307 (replace-regexp-in-string
308 "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
309 crm-separator)
310 (car args))
311 (cdr args)))
312
313;; Marginalia
163(package-ensure 'marginalia) 314(package-ensure 'marginalia)
164(marginalia-mode) 315(marginalia-mode)
165 316
317;; Embark
318(package-ensure 'embark)
319(package-ensure 'embark-consult)
320(keymap-global-set "M-." #'embark-dwim)
321(keymap-global-set "C-." #'embark-act)
322(keymap-global-set "C-h B" #'embark-bindings)
323(add-to-list 'display-buffer-alist
324 '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" nil
325 (window-parameters (mode-line-format . none))))
326(add-hook 'embark-collect-mode #'consult-preview-at-point-mode)
327(setopt embark-indicators '(embark-mixed-indicator
328 embark-highlight-indicator
329 embark-isearch-highlight-indicator))
330
166;;; Frames / Windows 331;;; Frames / Windows
167 332
168(winner-mode) 333(winner-mode)
@@ -174,14 +339,14 @@
174(global-auto-revert-mode) 339(global-auto-revert-mode)
175 340
176(setopt create-lockfiles nil) 341(setopt create-lockfiles nil)
177(setopt mode-require-final-newline t) 342(setopt require-final-newline t)
178(setopt view-read-only t) 343(setopt view-read-only t)
179(setopt save-silently t) 344(setopt save-silently t)
180(setopt delete-by-moving-to-trash t) 345(setopt delete-by-moving-to-trash t)
181(setopt auto-save-default nil) 346(setopt auto-save-default t)
182(setopt auto-save-no-message t) 347(setopt auto-save-no-message t)
183(setopt auto-save-interval 2) 348(setopt auto-save-interval 30)
184(setopt auto-save-timeout 2) 349(setopt auto-save-timeout 5)
185(setopt auto-save-visited-interval 5) 350(setopt auto-save-visited-interval 5)
186(setopt remote-file-name-inhibit-auto-save t) 351(setopt remote-file-name-inhibit-auto-save t)
187(setopt remote-file-name-inhibit-auto-save-visited t) 352(setopt remote-file-name-inhibit-auto-save-visited t)
@@ -189,6 +354,19 @@
189 `(".*" ,(locate-user-emacs-file "auto-save/") t)) 354 `(".*" ,(locate-user-emacs-file "auto-save/") t))
190(auto-save-visited-mode) 355(auto-save-visited-mode)
191 356
357(add-hook 'window-selection-change-functions
358 (defun save-old-selected-window-buffer (frame)
359 (with-current-buffer
360 (window-buffer (frame-old-selected-window))
361 (when (and (buffer-file-name) (buffer-modified-p))
362 (save-buffer)))))
363
364(add-hook 'buffer-list-update-hook
365 (defun save-other-buffer ()
366 (with-current-buffer (other-buffer)
367 (when (and (buffer-file-name) (buffer-modified-p))
368 (save-buffer)))))
369
192(add-function :after after-focus-change-function 370(add-function :after after-focus-change-function
193 (defun focus-out-save () 371 (defun focus-out-save ()
194 (save-some-buffers t))) 372 (save-some-buffers t)))
@@ -224,6 +402,8 @@
224 402
225;; Unique names 403;; Unique names
226(setopt uniquify-buffer-name-style 'forward) 404(setopt uniquify-buffer-name-style 'forward)
405(setopt uniquify-after-kill-buffer-p t)
406(setopt uniquify-ignore-buffers-re "^\\*")
227 407
228;; Persistent undo 408;; Persistent undo
229(package-ensure 'undo-fu-session) 409(package-ensure 'undo-fu-session)
@@ -256,7 +436,7 @@
256(setopt isearch-lazy-count nil) 436(setopt isearch-lazy-count nil)
257(setopt isearch-regexp-lax-whitespace t) 437(setopt isearch-regexp-lax-whitespace t)
258(setopt isearch-wrap-pause 'no) 438(setopt isearch-wrap-pause 'no)
259(setopt search-whitespace-regexp "[ ]+") 439(setopt search-whitespace-regexp "[ ]+")
260(setopt search-ring-max 256) 440(setopt search-ring-max 256)
261(setopt regexp-search-ring-max 256) 441(setopt regexp-search-ring-max 256)
262 442
@@ -265,35 +445,43 @@
265 (unless (string-equal "" isearch-string) 445 (unless (string-equal "" isearch-string)
266 (isearch-update-ring isearch-string isearch-regexp))) 446 (isearch-update-ring isearch-string isearch-regexp)))
267 447
268(package-ensure 'isearch-mb) 448(package-ensure 'isearch-mb t)
269(with-eval-after-load 'isearch-mb 449(add-to-list 'isearch-mb--with-buffer #'consult-isearch-history)
270 (with-eval-after-load 'consult 450(keymap-set isearch-mb-minibuffer-map "M-r" #'consult-isearch-history)
271 (add-to-list 'isearch-mb--with-buffer #'consult-isearch-history) 451(add-to-list 'isearch-mb--after-exit #'consult-line)
272 (keymap-set isearch-mb-minibuffer-map "M-r" #'consult-isearch-history) 452(keymap-set isearch-mb-minibuffer-map "M-s l" #'consult-line)
273 (add-to-list 'isearch-mb--after-exit #'consult-line)
274 (keymap-set isearch-mb-minibuffer-map "M-s l" #'consult-line)))
275(isearch-mb-mode) 453(isearch-mb-mode)
276 454
277;; Default to regexen 455;; Default to regexen
278(setopt search-default-mode t) ; Isearch 456(setopt search-default-mode t) ; Isearch
279(keymap-global-set "M-%" #'query-replace-regexp) 457(keymap-global-set "M-%" #'query-replace-regexp)
280(keymap-global-set "C-M-%" #'query-replace) 458(keymap-global-set "C-M-%" #'query-replace)
281 459
282;;; Keybinds 460;;; Keybindings
283 461
462(repeat-mode)
463
464;; Separate C-<key> and control keys from halcyon ascii days
465;; (define-key input-decode-map [?\C-i] [C-i])
466;; (define-key input-decode-map [?\C-m] [C-m])
467
468;; Modified default keybindings
284(keymap-global-set "C-x C-k" #'kill-buffer-dwim) 469(keymap-global-set "C-x C-k" #'kill-buffer-dwim)
285(keymap-global-set "M-o" #'other-window-dwim) 470(keymap-global-set "M-o" #'other-window-dwim)
286(keymap-global-set "C-x o" #'other-window-dwim) 471(keymap-global-set "C-x o" #'other-window-dwim)
287(keymap-global-set "C-x 0" #'delete-window-dwim) 472(keymap-global-set "C-x 0" #'delete-window-dwim)
288(keymap-global-set "M-SPC" #'cycle-spacing*) 473(keymap-global-set "M-SPC" #'cycle-spacing*)
289(keymap-global-set "C-M-\\" #'indent-buffer+)
290
291(keymap-global-set "C-x C-c" #'save-buffers-kill*) 474(keymap-global-set "C-x C-c" #'save-buffers-kill*)
475(keymap-global-set "C-g" #'keyboard-quit*)
476(keymap-global-set "C-M-\\" #'fixup-whitespace)
477
478;; New bindings for existing stuff
292(keymap-global-set "C-x C-b" #'ibuffer) 479(keymap-global-set "C-x C-b" #'ibuffer)
293(keymap-global-set "M-/" #'hippie-expand) 480(keymap-global-set "M-/" #'hippie-expand)
294(keymap-global-set "M-u" #'universal-argument) 481(keymap-global-set "M-u" #'universal-argument)
295(keymap-set universal-argument-map "M-u" #'universal-argument-more) 482(keymap-set universal-argument-map "M-u" #'universal-argument-more)
296 483
484;; Prefix maps
297(keymap-global-set "C-c d" 485(keymap-global-set "C-c d"
298 (defun insert-current-iso8601 () 486 (defun insert-current-iso8601 ()
299 (interactive) 487 (interactive)
@@ -309,6 +497,8 @@
309 "p" (find-user-file private) 497 "p" (find-user-file private)
310 "t" (find-user-file brianna 498 "t" (find-user-file brianna
311 (locate-user-emacs-file "brianna-theme.el")) 499 (locate-user-emacs-file "brianna-theme.el"))
500 "x" (find-user-file exwm
501 (expand-file-name "~/.exwm"))
312 "s" #'scratch-buffer)) 502 "s" #'scratch-buffer))
313 503
314(keymap-global-set "C-c t" 504(keymap-global-set "C-c t"
@@ -319,14 +509,28 @@
319 "c" #'column-number-mode 509 "c" #'column-number-mode
320 "l" #'line-number-mode 510 "l" #'line-number-mode
321 "L" #'display-line-numbers-mode 511 "L" #'display-line-numbers-mode
322 "t" #'truncate-lines-local-mode)) 512 "t" #'truncate-lines-local-mode
513 "o" #'overwrite-mode
514 "f" #'auto-fill-mode))
323 515
324;; Un-keybinds 516(keymap-global-set "M-c"
517 (define-keymap
518 :prefix 'case-map
519 "M-u" #'upcase-dwim "u" #'upcase-dwim
520 "M-c" #'capitalize-dwim "c" #'capitalize-dwim
521 "M-l" #'downcase-dwim "l" #'downcase-dwim))
522(put 'upcase-dwim 'repeat-map 'case-map)
523(put 'capitalize-dwim 'repeat-map 'case-map)
524(put 'downcase-dwim 'repeat-map 'case-map)
525
526;;; Un-keybinds
527;; Why do I want to zoom with the mouse?
325(keymap-global-unset "C-<wheel-down>" t) 528(keymap-global-unset "C-<wheel-down>" t)
326(keymap-global-unset "C-<wheel-up>" t) 529(keymap-global-unset "C-<wheel-up>" t)
327;; I only ever fat-finger this key and never want to change encoding 530;; These are ripe for re-binding
328(keymap-global-unset "C-\\" t) 531(keymap-global-unset "C-\\" t)
329(keymap-global-unset "C-z" t) 532(keymap-global-unset "M-l" t)
533(keymap-global-unset "<f2>" t)
330 534
331;; Key settings 535;; Key settings
332(setopt set-mark-command-repeat-pop t) 536(setopt set-mark-command-repeat-pop t)
@@ -337,8 +541,11 @@
337(package-ensure 'hungry-delete) 541(package-ensure 'hungry-delete)
338(setopt hungry-delete-chars-to-skip " \t") 542(setopt hungry-delete-chars-to-skip " \t")
339(with-eval-after-load 'hungry-delete 543(with-eval-after-load 'hungry-delete
340 (add-to-list 'hungry-delete-except-modes 'eshell-mode) 544 (dolist (m '( eshell-mode
341 (add-to-list 'hungry-delete-except-modes 'eww-mode)) 545 eww-mode
546 special-mode
547 jabber-chat-mode))
548 (add-to-list 'hungry-delete-except-modes m)))
342(global-hungry-delete-mode) 549(global-hungry-delete-mode)
343 550
344;;; Writing 551;;; Writing
@@ -364,12 +571,13 @@
364 css-mode) 571 css-mode)
365 "Modes to indent with spaces, not tabs.") 572 "Modes to indent with spaces, not tabs.")
366 573
367;; (add-hook 'prog-mode-hook 574(add-hook 'prog-mode-hook
368;; (defun indent-tabs-mode-maybe () 575 (defun indent-tabs-mode-maybe ()
369;; (setq indent-tabs-mode 576 (setq indent-tabs-mode
370;; (if (apply #'derived-mode-p space-indent-modes) nil t)))) 577 (if (apply #'derived-mode-p space-indent-modes) nil t))))
371 578
372(indent-tabs-mode -1) 579;; Eldoc
580(setopt eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly)
373 581
374;; Elisp 582;; Elisp
375(keymap-set emacs-lisp-mode-map "C-c C-c" #'eval-defun) 583(keymap-set emacs-lisp-mode-map "C-c C-c" #'eval-defun)
@@ -385,11 +593,9 @@
385(setopt makefile-cleanup-continuations t) 593(setopt makefile-cleanup-continuations t)
386 594
387(add-hook 'makefile-mode-hook 595(add-hook 'makefile-mode-hook
388 (defun makefile-stop-complaining () 596 (^local-unhook 'write-file-functions 'makefile-warn-suspicious-lines))
389 (remove-hook 'write-file-functions 597(add-hook 'makefile-mode-hook
390 'makefile-warn-suspicious-lines t) 598 (^local-unhook 'write-file-functions 'makefile-warn-continuations))
391 (remove-hook 'write-file-functions
392 'makefile-warn-continuations t)))
393 599
394;; Scheme -- CHICKEN 600;; Scheme -- CHICKEN
395(setopt scheme-program-name (or (executable-find "csi"))) 601(setopt scheme-program-name (or (executable-find "csi")))
@@ -416,10 +622,7 @@
416(advice-add 'geiser-eval-region :after #'pulse@eval) 622(advice-add 'geiser-eval-region :after #'pulse@eval)
417 623
418;; VC 624;; VC
419(keymap-global-set "C-x v j" 625(keymap-global-set "C-x m" #'vc-jump)
420 (defun vc-jump ()
421 (interactive)
422 (vc-dir default-directory)))
423 626
424;;; Compilation 627;;; Compilation
425 628
@@ -430,37 +633,66 @@
430 633
431(package-ensure 'gemtext-mode) 634(package-ensure 'gemtext-mode)
432 635
433;;; Miscellaneous settings 636;;; Miscellaneous
434 637
638;; Settings
435(add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p) 639(add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p)
436;; (add-hook 'prog-mode-hook #'auto-fill-mode) 640(add-hook 'messages-buffer-mode-hook
641 (^turn-off 'display-fill-column-indicator-mode))
642(add-hook 'prog-mode-hook #'auto-fill-mode)
437(add-hook 'prog-mode-hook #'electric-pair-local-mode) 643(add-hook 'prog-mode-hook #'electric-pair-local-mode)
438(setopt x-underline-at-descent-line t) 644(add-to-list 'warning-suppress-types 'comp)
439(setopt scroll-conservatively 101) 645(context-menu-mode)
440(setopt display-fill-column-indicator-character ?·) 646(delete-selection-mode)
647(global-goto-address-mode)
648(global-so-long-mode)
649(pixel-scroll-precision-mode)
650(setopt bookmark-save-flag 1)
441(setopt disabled-command-function nil) 651(setopt disabled-command-function nil)
652(setopt display-fill-column-indicator-character ?·)
442(setopt electric-pair-skip-whitespace 'chomp) 653(setopt electric-pair-skip-whitespace 'chomp)
654(setopt eval-expression-print-length nil)
655(setopt eval-expression-print-level nil)
443(setopt fill-column 80) 656(setopt fill-column 80)
444(setopt finger-X.500-host-regexps '(".*tilde.*")) 657(setopt finger-X.500-host-regexps '(".*tilde.*"))
658(setopt help-window-keep-selected t)
659(setopt help-window-select t)
660(setopt read-extended-command-predicate #'command-completion-default-include-p)
445(setopt recenter-positions '(top middle bottom)) 661(setopt recenter-positions '(top middle bottom))
446(setopt eval-expression-print-level nil) 662(setopt scroll-conservatively 101)
447(setopt eval-expression-print-length nil)
448(setopt show-paren-delay 0.01) 663(setopt show-paren-delay 0.01)
449(setopt show-paren-style 'parenthesis) 664(setopt show-paren-style 'parenthesis)
450(setopt show-paren-when-point-in-periphery t) 665(setopt show-paren-when-point-in-periphery t)
451(setopt show-paren-when-point-inside-paren t) 666(setopt show-paren-when-point-inside-paren t)
667(setopt switch-to-buffer-obey-display-actions t)
668(setopt tmm-completion-prompt nil)
669(setopt tmm-mid-prompt " -- ")
670(setopt x-underline-at-descent-line t)
452(show-paren-mode) 671(show-paren-mode)
453(delete-selection-mode)
454(global-so-long-mode)
455(global-goto-address-mode)
456(context-menu-mode)
457(tooltip-mode -1) 672(tooltip-mode -1)
458 673
674;; Advice & Hooks
675
676(define-advice canonically-space-region
677 (:around (orig &rest args) double-space-sentences)
678 "Always double-space sentences canonically."
679 (let ((sentence-end-double-space t))
680 (apply orig args)))
681
682(define-advice switch-to-buffer (:after (&rest _) normal-mode)
683 "Automatically determine the mode for non-file buffers."
684 (when-let ((_ (and (eq major-mode 'fundamental-mode)
685 (not buffer-file-name)))
686 (buffer-file-name (buffer-name)))
687 (normal-mode)))
688
459(add-hook 'special-mode-hook 689(add-hook 'special-mode-hook
460 (defun hl-line@special-mode () 690 (defun hl-line@special-mode ()
461 (unless (derived-mode-p 'help-mode ; add other modes here 691 (unless (derived-mode-p 'help-mode ; add other modes here
462 'Info-mode 692 'Info-mode
463 'eww-mode) 693 'Man-mode
694 'eww-mode
695 'elpher-mode)
464 (hl-line-mode)))) 696 (hl-line-mode))))
465(add-hook 'dired-mode-hook #'hl-line-mode) 697(add-hook 'dired-mode-hook #'hl-line-mode)
466 698
@@ -486,6 +718,26 @@
486(setopt jabber-groupchat-buffer-format "%b") 718(setopt jabber-groupchat-buffer-format "%b")
487(setopt jabber-muc-private-buffer-format "%n<%g>") 719(setopt jabber-muc-private-buffer-format "%n<%g>")
488 720
721(defun esc/mls (str) ; escape-mode-line-string
722 (string-replace "%" "%%" str))
723
724(setopt jabber-chat-header-line-format
725 '(" " (:eval (esc/mls (jabber-jid-displayname jabber-chatting-with)))
726 " :: " (:eval (esc/mls (jabber-fix-status
727 (get (jabber-jid-symbol jabber-chatting-with)
728 'status))))
729 " :: " (:eval (esc/mls jabber-events-message)) ;see jabber-events.el
730 " :: " (:eval (esc/mls jabber-chatstates-message))))
731(setopt jabber-muc-header-line-format
732 '(" " (:eval (esc/mls (jabber-jid-displayname jabber-group)))
733 " :: " (:eval (esc/mls jabber-muc-topic))))
734(setopt jabber-muc-private-header-line-format
735 '(" " (:eval (esc/mls (jabber-jid-resource jabber-chatting-with)))
736 " in " (:eval (esc/mls (jabber-jid-displayname
737 (jabber-jid-user jabber-chatting-with))))
738 " :: " (:eval (esc/mls jabber-events-message))
739 " :: " (:eval (esc/mls jabber-chatstates-message))))
740
489(add-hook 'jabber-post-connect-hooks #'jabber-enable-carbons) 741(add-hook 'jabber-post-connect-hooks #'jabber-enable-carbons)
490(add-hook 'jabber-chat-mode-hook #'visual-line-mode) 742(add-hook 'jabber-chat-mode-hook #'visual-line-mode)
491(remove-hook 'jabber-alert-muc-hooks #'jabber-muc-echo) 743(remove-hook 'jabber-alert-muc-hooks #'jabber-muc-echo)
@@ -493,8 +745,8 @@
493 745
494;;; Eshell 746;;; Eshell
495 747
496(setopt eshell-banner-message 748(setopt cookie-file (expand-file-name "~/cloud/oblique.txt"))
497 (format "%s\n\n" (string-join (process-lines "fortune" "-s") "\n"))) 749(setopt eshell-banner-message (format "%s\n" (cookie cookie-file)))
498(setopt eshell-prompt-function 750(setopt eshell-prompt-function
499 (defun @eshell-prompt () 751 (defun @eshell-prompt ()
500 (let ((rootp (zerop (user-uid)))) 752 (let ((rootp (zerop (user-uid))))
@@ -514,17 +766,7 @@
514(setopt eshell-scroll-to-bottom-on-input 'this) 766(setopt eshell-scroll-to-bottom-on-input 'this)
515(setopt eshell-history-size nil) 767(setopt eshell-history-size nil)
516 768
517(keymap-global-set "C-z" 769(keymap-global-set "C-z" #'popup-eshell)
518 (lambda (arg) (interactive "P")
519 (let ((dd default-directory))
520 (eshell arg)
521 (unless (equal dd default-directory)
522 (setq default-directory dd)
523 ;; Is this a good idea, really?
524 (eshell-bol)
525 (unless (eolp)
526 (insert "# "))
527 (eshell-send-input)))))
528(add-hook 'eshell-first-time-mode-hook 770(add-hook 'eshell-first-time-mode-hook
529 (defun @eshell-once () 771 (defun @eshell-once ()
530 (keymap-set eshell-mode-map "C-z" #'quit-window))) 772 (keymap-set eshell-mode-map "C-z" #'quit-window)))
@@ -532,18 +774,22 @@
532;;; Browsing 774;;; Browsing
533 775
534;; Dired (files) 776;; Dired (files)
777(add-hook 'dired-mode-hook #'dired-hide-details-mode)
778(add-hook 'dired-mode-hook #'truncate-lines-local-mode)
779(setopt dired-auto-revert-buffer t)
780(setopt dired-clean-confirm-killing-deleted-buffers nil)
781(setopt dired-create-destination-dirs 'always)
782(setopt dired-do-revert-buffer t)
535(setopt dired-dwim-target t) 783(setopt dired-dwim-target t)
536(setopt dired-listing-switches "-AlF") 784(setopt dired-hide-details-hide-symlink-targets nil)
785(setopt dired-listing-switches "-AlFhv --group-directories-first")
537(setopt dired-ls-F-marks-symlinks t) 786(setopt dired-ls-F-marks-symlinks t)
787(setopt dired-no-confirm '(byte-compile load chgrp chmod chown copy move
788 hardlink symlink shell touch))
538(setopt dired-recursive-copies 'always) 789(setopt dired-recursive-copies 'always)
539(setopt dired-recursive-deletes 'always) 790(setopt dired-recursive-deletes 'always)
540(setopt dired-auto-revert-buffer t)
541(setopt dired-hide-details-hide-symlink-targets nil)
542(add-hook 'dired-mode-hook #'dired-hide-details-mode)
543(add-hook 'dired-mode-hook #'truncate-lines-local-mode)
544(with-eval-after-load 'dired 791(with-eval-after-load 'dired
545 (require 'dired-x) 792 (require 'dired-x)
546 (keymap-set dired-mode-map "C-j" #'dired-up-directory)
547 (setopt dired-omit-files (regexp-concat dired-omit-files 793 (setopt dired-omit-files (regexp-concat dired-omit-files
548 "^\\..+$" 794 "^\\..+$"
549 ;; CHICKEN ... this may be overkill 795 ;; CHICKEN ... this may be overkill
@@ -551,18 +797,75 @@
551 "\\.import\\.scm$" 797 "\\.import\\.scm$"
552 "\\.\\(build\\|install\\)\\.sh$" 798 "\\.\\(build\\|install\\)\\.sh$"
553 "\\.link$")) 799 "\\.link$"))
800 (keymap-set dired-mode-map "C-j" #'dired-up-directory)
554 (add-hook 'dired-mode-hook #'dired-omit-mode) 801 (add-hook 'dired-mode-hook #'dired-omit-mode)
555 (keymap-set dired-mode-map ")" #'dired-omit-mode)) 802 (keymap-set dired-mode-map ")" #'dired-omit-mode))
556 803
557;; Elpher (gemini/gopher) 804;; Elpher (gemini/gopher)
558(package-ensure 'elpher) 805(package-ensure 'elpher)
806(with-eval-after-load 'elpher
807 ;; Try to emulate eww bindings if possible
808 (keymap-set elpher-mode-map "l" #'elpher-back)
809 (keymap-set elpher-mode-map "g" #'elpher-reload)
810 (keymap-set elpher-mode-map "G" #'elpher-go)
811 (keymap-set elpher-mode-map "v" #'elpher-view-raw)
812 (keymap-set elpher-mode-map "E" #'elpher-set-gopher-coding-system))
559 813
560;;; HTTP browsing 814;;; HTTP browsing
561 815
562;; SHR 816;; Eww / Shr
563(setopt shr-max-width (+ fill-column 10)) 817(setopt shr-max-width nil) ; covered in hook below
818(setopt shr-max-image-proportion 0.9)
819(setopt shr-discard-aria-hidden t)
820(setopt eww-auto-rename-buffer
821 (defun title+url ()
822 (when (eq major-mode 'eww-mode)
823 (let ((title (plist-get eww-data :title))
824 (url (plist-get eww-data :url)))
825 (cond
826 ((and title url) (format "*eww: %s :: %s" title url))
827 ((or title url) (format "*eww: %s") (or title url)))))))
828(add-hook 'eww-after-render-hook
829 (defun eww@visual-line ()
830 (visual-fill-column-mode)
831 (eww-reload t)))
832(with-eval-after-load 'eww
833 (setopt eww-use-browse-url ".")
834 (keymap-set eww-mode-map "B" #'bookmark-jump)
835 (keymap-set eww-mode-map "b" #'bookmark-set)
836 (keymap-unset eww-mode-map "M-n" t)
837 (keymap-unset eww-mode-map "M-p" t))
564 838
565;; Browse-url 839;; Browse-url
566(setopt browse-url-new-window-flag t) 840(setopt browse-url-browser-function #'eww-browse-url)
567(setopt browse-url-firefox-arguments '("--new-tab")) 841(setopt browse-url-firefox-arguments '("--new-tab"))
568(setopt browse-url-firefox-new-window-is-tab t) 842(setopt browse-url-firefox-new-window-is-tab t)
843(setopt browse-url-generic-args browse-url-firefox-arguments)
844(setopt browse-url-generic-program "firefox")
845
846(setopt browse-url-secondary-browser-function #'browse-url-firefox)
847
848(package-ensure 'link-hint)
849(keymap-global-set "M-l"
850 (define-keymap
851 :prefix 'link-map
852 "M-l" #'link-hint-open-link "l" #'link-hint-open-link
853 "M-w" #'link-hint-copy-link "w" #'link-hint-copy-link))
854;; With link-hint we get avy "for free"
855(keymap-global-set "M-j" #'avy-goto-char-timer)
856
857;; PDFs
858(package-ensure 'pdf-tools)
859(pdf-loader-install)
860
861;;; EXWM
862
863(setf/alist display-buffer-alist shell-command-buffer-name-async
864 '(display-buffer-no-window))
865
866(when (getenv "DISPLAY")
867 (package-ensure 'exwm t)
868 (load (expand-file-name "~/.exwm")))
869
870;;; Mu4e
871
diff --git a/emacs.d/bookmarks b/emacs.d/bookmarks new file mode 100644 index 0000000..05ee99e --- /dev/null +++ b/emacs.d/bookmarks
@@ -0,0 +1,33 @@
1;;;; Emacs Bookmark Format Version 1;;;; -*- coding: utf-8; mode: lisp-data -*-
2;;; This format is meant to be slightly human-readable;
3;;; nevertheless, you probably don't want to edit it.
4;;; -*- End Of Bookmark File Format Version Stamp -*-
5(("~elly/pub"
6 (filename . "/sshx:town:/home/elly/pub/")
7 (front-context-string . " /sshx:town:/ho")
8 (rear-context-string)
9 (position . 1)
10 (last-modified 26236 19926 867955 868000))
11("Planet ACDW"
12 (front-context-string . "mars, but with e")
13 (rear-context-string)
14 (position . 1)
15 (last-modified 26235 32833 754178 60000)
16 (location . "https://planet.acdw.net/")
17 (handler . eww-bookmark-jump))
18("CHICKEN API"
19 (front-context-string . "chickadee\n\nIdent")
20 (rear-context-string)
21 (position . 1)
22 (last-modified 26219 43014 969496 46000)
23 (location . "http://api.call-cc.org/5/doc/")
24 (handler . eww-bookmark-jump))
25(#1="set-face-attribute"
26 (position . 1)
27 (last-modified 26219 41950 249141 418000)
28 (help-fn . describe-function--helper)
29 (help-args set-face-attribute "brianna-theme.el")
30 (position . 1)
31 (handler . help-bookmark-jump)
32 (defaults #1# "*Help*"))
33)
diff --git a/emacs.d/brianna-theme.el b/emacs.d/brianna-theme.el index 0b16a41..43223f6 100644 --- a/emacs.d/brianna-theme.el +++ b/emacs.d/brianna-theme.el
@@ -93,12 +93,12 @@
93 '(header-line ((t (:background "lavender" :inherit variable-pitch)))) 93 '(header-line ((t (:background "lavender" :inherit variable-pitch))))
94 '(minibuffer-prompt ((t (:inherit brianna-prompt)))) 94 '(minibuffer-prompt ((t (:inherit brianna-prompt))))
95 '(mode-line ((t (:background "lavender" :inherit variable-pitch)))) 95 '(mode-line ((t (:background "lavender" :inherit variable-pitch))))
96 '(mode-line-active ((t ( :box t :background "light goldenrod" 96 '(mode-line-active ((t ( :box "black" :background "light goldenrod"
97 :inherit mode-line)))) 97 :inherit mode-line))))
98 '(mode-line-inactive ((t ( :box "pale goldenrod" :background "pale goldenrod" 98 '(mode-line-inactive ((t ( :box "pale goldenrod" :background "pale goldenrod"
99 :inherit mode-line)))) 99 :inherit mode-line))))
100 '(tab-bar ((t (:inherit mode-line-inactive)))) 100 '(tab-bar ((t (:inherit mode-line-inactive))))
101 '(tab-bar-tab ((t ( :background "light goldenrod" :box t 101 '(tab-bar-tab ((t ( :weight bold :underline t
102 :inherit variable-pitch)))) 102 :inherit variable-pitch))))
103 '(tab-bar-tab-inactive ((t ( :background "pale goldenrod" 103 '(tab-bar-tab-inactive ((t ( :background "pale goldenrod"
104 :inherit variable-pitch)))) 104 :inherit variable-pitch))))
@@ -165,9 +165,12 @@
165 ;; Sh 165 ;; Sh
166 '(sh-heredoc ((t ( :background "azure" :extend t 166 '(sh-heredoc ((t ( :background "azure" :extend t
167 :inherit font-lock-string-face)))) 167 :inherit font-lock-string-face))))
168 '(sh-quoted-exec ((t ())))
168 ;; Widgets 169 ;; Widgets
169 '(widget-field ((t (:inherit brianna-input-field)))) 170 '(widget-field ((t (:inherit brianna-input-field))))
170 '(widget-single-line-field ((t (:inherit brianna-input-field)))) 171 '(widget-single-line-field ((t (:inherit brianna-input-field))))
172 ;; Whitespace-mode
173 '(whitespace-tab ((t (:foreground "#888"))))
171 ) 174 )
172 175
173(provide-theme 'brianna) 176(provide-theme 'brianna)
diff --git a/emacs.d/early-init.el b/emacs.d/early-init.el index 7374bd1..b2de2f2 100644 --- a/emacs.d/early-init.el +++ b/emacs.d/early-init.el
@@ -10,18 +10,21 @@
10 (vertical-scroll-bars) 10 (vertical-scroll-bars)
11 (horizontal-scroll-bars))) 11 (horizontal-scroll-bars)))
12 12
13(when (getenv "IN_EXWM")
14 (add-to-list 'default-frame-alist '(fullscreen . fullboth)))
15
13(defvar *fonts* 16(defvar *fonts*
14 '((default 17 (let ((fixed "Recursive Mono Casual Static")
15 :family ;;("Recursive Mono Casual Static" "DejaVu Sans Mono") 18 (variable "Recursive Sans Casual Static"))
16 ("Public Sans" "DejaVu Sans") 19 `((default
17 :height 100) 20 :family ,variable
18 (variable-pitch 21 :height 100)
19 :family ("Public Sans" "DejaVu Sans") 22 (variable-pitch
20 :height 1.0) 23 :family ,variable)
21 (fixed-pitch 24 (fixed-pitch
22 :family ("Recursive Mono Casual Static" "DejaVu Sans Mono")) 25 :family ,fixed)
23 (fixed-pitch-serif 26 (fixed-pitch-serif
24 :family ("Recursive Mono Linear Static" "DejaVu Sans Mono")))) 27 :family "Recursive Mono Linear Static"))))
25 28
26(require 'package) 29(require 'package)
27(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) 30(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
@@ -47,24 +50,6 @@
47 (delete-trailing-whitespace (line-end-position) 50 (delete-trailing-whitespace (line-end-position)
48 (point-max)))) 51 (point-max))))
49 52
50(defun run-after-frame-init (func)
51 "Run FUNC after the first frame is initialized.
52If already so, run FUNC immediately."
53 (cond
54 ((daemonp)
55 (add-hook 'server-after-make-frame-hook func)
56 (advice-add func :after (lambda ()
57 (remove-hook 'server-after-make-frame-hook
58 func)
59 (advice-remove func
60 'after-frame-init-removing-advice))
61
62
63 '((name . after-frame-init-removing-advice))))
64 ((not after-init-time)
65 (add-hook 'after-init-hook func))
66 (:else (funcall func))))
67
68(defun first-found-font (&rest cands) 53(defun first-found-font (&rest cands)
69 "Return the first font of CANDS that is installed, or nil." 54 "Return the first font of CANDS that is installed, or nil."
70 (cl-loop with ffl = (font-family-list) 55 (cl-loop with ffl = (font-family-list)
@@ -77,8 +62,7 @@ If already so, run FUNC immediately."
77 ;; Default faces 62 ;; Default faces
78 (cl-loop for (face . spec) in *fonts* 63 (cl-loop for (face . spec) in *fonts*
79 do (set-face-attribute face nil 64 do (set-face-attribute face nil
80 :family (apply #'first-found-font 65 :family (plist-get spec :family)
81 (plist-get spec :family))
82 :height (or (plist-get spec :height) 66 :height (or (plist-get spec :height)
83 'unspecified))) 67 'unspecified)))
84 ;; Specialized fonts 68 ;; Specialized fonts
@@ -171,20 +155,40 @@ With ARG, edit in the other window." file-name)
171 (funcall (if arg #'find-file-other-window #'find-file) 155 (funcall (if arg #'find-file-other-window #'find-file)
172 ,file-name)))) 156 ,file-name))))
173 157
174(defun indent-buffer+ () 158(defun fixup-whitespace ()
175 "Indent the current buffer and (un)`tabify'. 159 "Indent the current buffer and (un)`tabify'.
176Whether it tabifies or untabifies depends on `space-indent-modes'." 160Whether it tabifies or untabifies depends on `space-indent-modes'."
177 (interactive) 161 (interactive)
178 (save-mark-and-excursion 162 (save-mark-and-excursion
179 (indent-region (point-min) (point-max)) 163 (indent-region (point-min) (point-max))
180 (if (apply #'derived-mode-p space-indent-modes) 164 (if indent-tabs-mode
181 (untabify (point-min) (point-max)) 165 (tabify (point-min) (point-max))
182 (tabify (point-min) (point-max))))) 166 (untabify (point-min) (point-max)))
167 (replace-regexp-in-region " $" "" (point-min) (point-max))))
183 168
184(defun package-ensure (pkg) 169(defun package-ensure (pkgspec &optional require)
185 "Install PKG if it's not already installed." 170 "Install PKG if it's not already installed.
186 (unless (package-installed-p pkg) 171REQUIRE means require it after ensuring it's installed."
187 (package-vc-install pkg))) 172 (let ((pkg (if (listp pkgspec) (car pkgspec) pkgspec)))
173 (unless (package-installed-p pkg)
174 (if (symbolp pkgspec)
175 (or (ignore-errors
176 (package-install pkg)
177 t)
178 (ignore-errors
179 (message "Package `%s' not found, refreshing packages" pkg)
180 (package-refresh-contents)
181 (package-install pkg)
182 t)
183 (ignore-errors
184 (message "Package `%s' still not found, trying `%s'"
185 pkg 'pkg-vc-install)
186 (package-vc-install pkgspec)
187 t)
188 (if no-error nil
189 (error "Can't find package: %s" pkg))))
190 (package-vc-install pkgspec))
191 (when require (require pkg))))
188 192
189(defun minibuffer-delete-directory () 193(defun minibuffer-delete-directory ()
190 "Delete the last directory in a file-completing minibuffer." 194 "Delete the last directory in a file-completing minibuffer."
@@ -214,3 +218,203 @@ If ARG is 16, kill emacs without asking about processes."
214 218
215(defun regexp-concat (&rest regexps) 219(defun regexp-concat (&rest regexps)
216 (string-join regexps "\\|")) 220 (string-join regexps "\\|"))
221
222;; There is a bug in M-x finger
223(defun acdw/finger (user host)
224 "Finger USER on HOST.
225This command uses `finger-X.500-host-regexps'
226and `network-connection-service-alist', which see."
227 ;; One of those great interactive statements that's actually
228 ;; longer than the function call! The idea is that if the user
229 ;; uses a string like "pbreton@cs.umb.edu", we won't ask for the
230 ;; host name. If we don't see an "@", we'll prompt for the host.
231 (interactive
232 (let* ((answer (let ((default (ffap-url-at-point)))
233 (read-string (format-prompt "Finger User" default) nil nil default)))
234 (index (string-match (regexp-quote "@") answer)))
235 (if index
236 (list (substring answer 0 index)
237 (substring answer (1+ index)))
238 (list answer
239 (let ((default (ffap-machine-at-point)))
240 (read-string (format-prompt "At Host" default) nil nil default))))))
241 (let* ((user-and-host (concat user "@" host))
242 (process-name (concat "Finger [" user-and-host "]"))
243 (regexps finger-X.500-host-regexps)
244 ) ;; found
245 (and regexps
246 (while (not (string-match (car regexps) host))
247 (setq regexps (cdr regexps))))
248 (when regexps
249 (setq user-and-host user))
250 (run-network-program
251 process-name
252 host
253 (cdr (assoc 'finger network-connection-service-alist))
254 user-and-host)))
255
256(advice-add 'finger :override #'acdw-finger)
257
258(defun hide-minor-mode (mode &optional hook)
259 "Hide MODE from the mode-line.
260HOOK is used to trigger the action, and defaults to MODE-hook."
261 (setf (alist-get mode minor-mode-alist) (list ""))
262 (add-hook (intern (or hook (format "%s-hook" mode)))
263 (lambda () (hide-minor-mode mode))))
264
265(defun switch-to-other-buffer ()
266 "Switch to the `other-buffer'."
267 (interactive)
268 (switch-to-buffer nil))
269
270(defun popup-eshell (arg)
271 "Popup an eshell buffer in the current window."
272 (interactive "P")
273 (let ((dd default-directory))
274 (eshell arg)
275 (unless (equal dd default-directory)
276 (setq default-directory dd)
277 ;; Is this a good idea, really?
278 (eshell-bol)
279 (unless (eolp)
280 (insert "# "))
281 (eshell-send-input))))
282
283(defun vc-jump (arg)
284 "Jump to the current project's VC buffer.
285With ARG, prompt for the directory."
286 (interactive "P")
287 (if arg
288 (let ((current-prefix-arg nil))
289 (call-interactively #'vc-dir))
290 (project-vc-dir)))
291
292(defun custom-show-all-widgets ()
293 "toggle all \"More/Hide\" widgets in the current buffer."
294 ;; From unpackaged
295 (interactive)
296 (widget-map-buttons (lambda (widget _)
297 (pcase (widget-get widget :off)
298 ("More" (widget-apply-action widget)))
299 nil)))
300
301(defun quit-minibuffer ()
302 (interactive)
303 (switch-to-minibuffer)
304 (minibuffer-keyboard-quit))
305
306(defun keyboard-quit* (arg)
307 (interactive "P")
308 (if arg
309 (quit-minibuffer)
310 (keyboard-quit)))
311
312(defun sort-sexps (beg end)
313 "Sort sexps in region.
314Comments stay with the code below."
315 ;; From unpackaged
316 (interactive "r")
317 (cl-flet ((skip-whitespace () (while (looking-at (rx (1+ (or space "\n"))))
318 (goto-char (match-end 0))))
319 (skip-both () (while (cond ((or (nth 4 (syntax-ppss))
320 (ignore-errors
321 (save-excursion
322 (forward-char 1)
323 (nth 4 (syntax-ppss)))))
324 (forward-line 1))
325 ((looking-at (rx (1+ (or space "\n"))))
326 (goto-char (match-end 0)))))))
327 (save-excursion
328 (save-restriction
329 (narrow-to-region beg end)
330 (goto-char beg)
331 (skip-both)
332 (cl-destructuring-bind (sexps markers)
333 (cl-loop do (skip-whitespace)
334 for start = (point-marker)
335 for sexp = (ignore-errors
336 (read (current-buffer)))
337 for end = (point-marker)
338 while sexp
339 ;; Collect the real string, then one used for sorting.
340 collect (cons (buffer-substring (marker-position start)
341 (marker-position end))
342 (save-excursion
343 (goto-char (marker-position start))
344 (skip-both)
345 (buffer-substring (point)
346 (marker-position end))))
347 into sexps
348 collect (cons start end)
349 into markers
350 finally return (list sexps markers))
351 (setq sexps (sort sexps (lambda (a b)
352 (string< (cdr a) (cdr b)))))
353 (cl-loop for (real . sort) in sexps
354 for (start . end) in markers
355 do (progn
356 (goto-char (marker-position start))
357 (insert-before-markers real)
358 (delete-region (point) (marker-position end)))))))))
359
360(defun ^turn-off (mode)
361 "Higher-order function: returns a lambda to turn off MODE."
362 (lambda ()
363 (funcall mode -1)))
364
365(defun ^local-hook (hook fn)
366 "Hook FN to HOOK locally in a lambda.
367Good for adding to an add-hook."
368 (lambda () (add-hook hook fn t)))
369
370(defun ^local-unhook (hook fn)
371 "Remove FN from HOOK locally."
372 (lambda () (remove-hook hook fn t)))
373
374;; This needs to be a macro to take advantage of setf magic
375(defmacro setf/alist (alist key val &optional testfn)
376 `(setf (alist-get ,key ,alist nil nil (or ,testfn #'equal))
377 ,val))
378
379(defun unfill-region (beg end)
380 (interactive "*r")
381 (let ((fill-column most-positive-fixnum))
382 (fill-region beg end)))
383
384(defun unfill-paragraph ()
385 (interactive)
386 (let ((fill-column most-positive-fixnum))
387 (fill-paragraph beg end)))
388
389(defun unfill-buffer ()
390 (interactive)
391 (unfill-region (point-min) (point-max)))
392
393(defun unfill-buffer/force ()
394 (interactive)
395 (let ((buffer-read-only nil))
396 (unfill-buffer)
397 (visual-line-mode t)))
398
399(defmacro after (event &rest body)
400 "Do BODY after EVENT, which can be:
401- A feature
402- A hook -- if it requires arguments they'll be in the list `args'
403- The symbol 'init, which runs on after-init-hook"
404 (declare (indent 1))
405 (let ((lambda-form `(lambda (&rest args) ,@body)))
406 (pcase event
407 (`(timer ,ev) `(run-with-timer ,ev nil ,lambda-form))
408 (`(idle ,ev) `(run-with-idle-timer ,ev nil ,lambda-form))
409 (`(hook ,ev) `(add-hook ',ev ,lambda-form))
410 (`init `(after (hook after-init-hook) ,@body))
411 ((pred numberp) `(after (timer ,event) ,@body))
412 ((pred (lambda (ev)
413 (and (symbolp ev)
414 (or (string-suffix-p "-hook" (symbol-name ev))
415 (string-suffix-p "-function" (symbol-name ev))
416 (string-suffix-p "-functions" (symbol-name ev))))))
417 `(after (hook ,event) ,@body))
418 ((pred symbolp) `(with-eval-after-load ',event ,@body))
419
420 (_ (error "Can't determine event type" event)))))