summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--init.el292
1 files changed, 286 insertions, 6 deletions
diff --git a/init.el b/init.el index 4648042..c654c07 100644 --- a/init.el +++ b/init.el
@@ -9,12 +9,188 @@
9;; 9;;
10;; For the tenth time! 10;; For the tenth time!
11 11
12;;; Packages 12;;; Code:
13
14(load (locate-user-emacs-file "private"))
15
16
17;;; Definitions:
18
19(defun other-window-or-switch-buffer (&optional arg)
20 "Switch to the other window.
21If a window is the only buffer on a frame, switch buffer. When
22run with \\[universal-argument], unconditionally switch buffer."
23 (interactive "P")
24 (if (or arg (one-window-p))
25 (switch-to-buffer (other-buffer) nil t)
26 (other-window 1)))
27
28(defun cycle-spacing@ (&optional n)
29 ;; `cycle-spacing' is wildly different in 29.1 over 28.
30 "Negate N argument on `cycle-spacing'.
31That is, with a positive N, deletes newlines as well, leaving -N
32spaces. If N is negative, it will not delete newlines and leave
33N spaces."
34 (interactive "*p")
35 (cycle-spacing (- n)))
36
37(defun first-frame@set-fonts ()
38 (remove-hook 'server-after-make-frame-hook
39 #'first-frame@set-fonts)
40 (face-spec-set 'default
41 `((t :family "Recursive Mono Casual Static"
42 :height 110)))
43 ;; Emojis
44 (cl-loop with ffl = (font-family-list)
45 for font in '("Noto Emoji" "Noto Color Emoji"
46 "Segoe UI Emoji" "Apple Color Emoji"
47 "FreeSans" "FreeMono" "FreeSerif"
48 "Unifont" "Symbola")
49 if (member font ffl)
50 do (set-fontset-font t 'symbol font))
51 ;; International fonts
52 (cl-loop with ffl = (font-family-list)
53 for (charset . font)
54 in '((latin . "Noto Sans")
55 (han . "Noto Sans CJK SC Regular")
56 (kana . "Noto Sans CJK JP Regular")
57 (hangul . "Noto Sans CJK KR Regular")
58 (cjk-misc . "Noto Sans CJK KR Regular")
59 (khmer . "Noto Sans Khmer")
60 (lao . "Noto Sans Lao")
61 (burmese . "Noto Sans Myanmar")
62 (thai . "Noto Sans Thai")
63 (ethiopic . "Noto Sans Ethiopic")
64 (hebrew . "Noto Sans Hebrew")
65 (arabic . "Noto Sans Arabic")
66 (gujarati . "Noto Sans Gujarati")
67 (devanagari . "Noto Sans Devanagari")
68 (kannada . "Noto Sans Kannada")
69 (malayalam . "Noto Sans Malayalam")
70 (oriya . "Noto Sans Oriya")
71 (sinhala . "Noto Sans Sinhala")
72 (tamil . "Noto Sans Tamil")
73 (telugu . "Noto Sans Telugu")
74 (tibetan . "Noto Sans Tibetan"))
75 if (member font ffl)
76 do (set-fontset-font t charset font))
77 ;; XXX: tab-bar does a weird thing, so i set it up here....
78 (setopt tab-bar-show t)
79 (tab-bar-mode))
80
81(defun renz/sort-by-alpha-length (elems)
82 "Sort ELEMS first alphabetically, then by length."
83 (sort elems (lambda (c1 c2)
84 (or (string-version-lessp c1 c2)
85 (< (length c1) (length c2))))))
86
87(defun renz/sort-by-history (elems)
88 "Sort ELEMS by minibuffer history.
89Use `mct-sort-sort-by-alpha-length' if no history is available."
90 (if-let ((hist (and (not (eq minibuffer-history-variable t))
91 (symbol-value minibuffer-history-variable))))
92 (minibuffer--sort-by-position hist elems)
93 (renz/sort-by-alpha-length elems)))
94
95(defun renz/completion-category ()
96 "Return completion category."
97 (when-let ((window (active-minibuffer-window)))
98 (with-current-buffer (window-buffer window)
99 (completion-metadata-get
100 (completion-metadata (buffer-substring-no-properties
101 (minibuffer-prompt-end)
102 (max (minibuffer-prompt-end) (point)))
103 minibuffer-completion-table
104 minibuffer-completion-predicate)
105 'category))))
106
107(defun renz/sort-multi-category (elems)
108 "Sort ELEMS per completion category."
109 (pcase (renz/completion-category)
110 ('nil elems) ; no sorting
111 ('kill-ring elems)
112 ('project-file (renz/sort-by-alpha-length elems))
113 (_ (renz/sort-by-history elems))))
114
115(defvar no-tabs-modes '(emacs-lisp-mode
116 lisp-mode
117 scheme-mode
118 python-mode
119 haskell-mode)
120 "Modes /not/ to indent with tabs.")
121
122(defun indent-tabs-mode-maybe ()
123 (if (apply #'derived-mode-p no-tabs-modes)
124 (indent-tabs-mode -1)
125 (indent-tabs-mode 1)))
126
127(define-minor-mode truncate-lines-mode
128 "Buffer-local mode to toggle `truncate-lines'."
129 :lighter ""
130 (setq-local truncate-lines truncate-lines-mode))
131
132;;; Region or buffer stuff
133
134(defun call-with-region-or-buffer (fn &rest _r)
135 "Call function FN with current region or buffer.
136Good to use for :around advice."
137 (if (region-active-p)
138 (funcall fn (region-beginning) (region-end))
139 (funcall fn (point-min) (point-max))))
140
141(defun delete-trailing-whitespace-except-current-line ()
142 (save-excursion
143 (delete-trailing-whitespace (point-min)
144 (line-beginning-position))
145 (delete-trailing-whitespace (line-end-position)
146 (point-max))))
147
148(defun create-missing-directories ()
149 "Automatically create missing directories."
150 (let ((target-dir (file-name-directory buffer-file-name)))
151 (unless (file-exists-p target-dir)
152 (make-directory target-dir :parents))))
153
154
155(defun vc-remote-off ()
156 "Turn VC off when remote."
157 (when (file-remote-p (buffer-file-name))
158 (setq-local vc-handled-backends nil)))
159
160(defun +titlecase-sentence-style-dwim (&optional arg)
161 "Titlecase a sentence.
162With prefix ARG, toggle the value of
163`titlecase-downcase-sentences' before sentence-casing."
164 (interactive "P")
165 (let ((titlecase-downcase-sentences (if arg (not titlecase-downcase-sentences)
166 titlecase-downcase-sentences)))
167 (titlecase-dwim 'sentence)))
168
169(defun +titlecase-org-headings ()
170 (interactive)
171 (require 'org)
172 (save-excursion
173 (goto-char (point-min))
174 ;; See also `org-map-tree'. I'm not using that function because I want to
175 ;; skip the first headline. A better solution would be to patch
176 ;; `titlecase-line' to ignore org-mode metadata (TODO cookies, tags, etc).
177 (let ((level (funcall outline-level))
178 (org-special-ctrl-a/e t))
179 (while (and (progn (outline-next-heading)
180 (> (funcall outline-level) level))
181 (not (eobp)))
182 (titlecase-region (progn (org-beginning-of-line) (point))
183 (progn (org-end-of-line) (point)))))))
184
185
186;;; Packages:
13 187
14(require 'package) 188(require 'package)
15(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) 189(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
16(package-initialize) 190(package-initialize)
17 191
192;; Install packages here. Acutal configuration is done in the Configuration
193;; section.
18(dolist (pkg `(consult 194(dolist (pkg `(consult
19 marginalia 195 marginalia
20 visual-fill-column 196 visual-fill-column
@@ -31,9 +207,95 @@
31 (package-refresh-contents) 207 (package-refresh-contents)
32 (package-install pkg)))) 208 (package-install pkg))))
33 209
34(load (locate-user-emacs-file "definitions")) 210(dolist (local-pkg `(scule
35(load (locate-user-emacs-file "packages")) 211 frowny
36(load (locate-user-emacs-file "private")) 212 hippie-completing-read
213 mode-line-bell
214 titlecase
215 jabber))
216 (add-to-list 'load-path
217 (expand-file-name
218 (format "~/src/%s.el"
219 (symbol-name local-pkg)))))
220
221;;; Jabber
222
223(use-package jabber
224 :load-path "~/src/jabber.el"
225 :defer t
226 :bind-keymap (("C-c j" . jabber-global-keymap))
227 :preface nil
228 (setq-default jabber-chat-buffer-format "*%n*"
229 jabber-browse-buffer-format "*%n*"
230 jabber-groupchat-buffer-format "*%n*"
231 jabber-muc-private-buffer-format "*%n*")
232 :custom-face
233 (jabber-activity-face ((t :inherit jabber-chat-prompt-foreign
234 :foreground unspecified
235 :weight normal)))
236 (jabber-activity-personal-face ((t :inherit jabber-chat-prompt-local
237 :foreground unspecified
238 :weight bold)))
239 (jabber-chat-prompt-local ((t :inherit minibuffer-prompt
240 :foreground unspecified
241 :weight normal
242 :slant italic)))
243 (jabber-chat-prompt-foreign ((t :inherit warning
244 :foreground unspecified
245 :weight normal)))
246 (jabber-chat-prompt-system ((t :inherit font-lock-doc-face
247 :foreground unspecified)))
248 (jabber-rare-time-face ((t :inherit font-lock-comment-face
249 :foreground unspecified
250 :underline nil)))
251 :config
252 (require 'jabber-httpupload nil t)
253 (setopt jabber-auto-reconnect t
254 jabber-last-read-marker "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~"
255 jabber-muc-decorate-presence-patterns
256 '(("\\( enters the room ([^)]+)\\| has left the chatroom\\)$" . nil)
257 ("Mode #.*" . jabber-muc-presence-dim)
258 ("." . jabber-muc-presence-dim))
259 jabber-activity-make-strings #'jabber-activity-make-strings-shorten
260 jabber-rare-time-format
261 (format " - - - - - %%H:%d %%F"
262 (let ((min (string-to-number (format-time-string "%M"))))
263 (* 5 (floor min 5))))
264 jabber-muc-header-line-format '(" " jabber-muc-topic))
265
266 (setopt jabber-groupchat-prompt-format "%n. "
267 jabber-chat-local-prompt-format "%n. "
268 jabber-chat-foreign-prompt-format "%n. "
269 jabber-muc-private-foreign-prompt-format "%g/%n. ")
270
271 (keymap-global-set "C-c C-SPC" #'jabber-activity-switch-to)
272 (map-keymap (lambda (key command)
273 (define-key jabber-global-keymap (vector (+ key #x60)) command))
274 jabber-global-keymap)
275 (keymap-global-set "C-x C-j" #'dired-jump)
276
277 (add-hook 'jabber-post-connect-hooks #'jabber-enable-carbons)
278 (remove-hook 'jabber-alert-muc-hooks 'jabber-muc-echo)
279 (remove-hook 'jabber-alert-presence-hooks 'jabber-presence-echo)
280 (add-hook 'jabber-chat-mode-hook 'visual-line-mode)
281 (add-hook 'jabber-chat-mode-hook (defun jabber-no-position ()
282 (setq-local mode-line-position nil)))
283
284 (add-hook 'jabber-alert-muc-hooks
285 (defun jabber@highlight-acdw (&optional _ _ buf _ _)
286 (when buf
287 (with-current-buffer buf
288 (let ((regexp (rx word-boundary
289 "acdw" ; maybe get from the config?
290 word-boundary)))
291 (hi-lock-unface-buffer regexp)
292 (highlight-regexp regexp 'jabber-chat-prompt-local))))))
293
294 (when (fboundp 'jabber-chat-update-focus)
295 (add-hook 'window-configuration-change-hook #'jabber-chat-update-focus)))
296
297
298;;; Configuration:
37 299
38(setopt custom-file (locate-user-emacs-file "custom.el")) 300(setopt custom-file (locate-user-emacs-file "custom.el"))
39(load custom-file :noerror) 301(load custom-file :noerror)
@@ -355,11 +617,12 @@
355(defun tab-bar-end-space () 617(defun tab-bar-end-space ()
356 `((end menu-item " " ignore))) 618 `((end menu-item " " ignore)))
357 619
358(setopt tab-bar-show t) 620
359(add-to-list 'tab-bar-format 'tab-bar-format-align-right :append) 621(add-to-list 'tab-bar-format 'tab-bar-format-align-right :append)
360(add-to-list 'tab-bar-format 'tab-bar-format-global :append) 622(add-to-list 'tab-bar-format 'tab-bar-format-global :append)
361(add-to-list 'tab-bar-format 'tab-bar-end-space :append) 623(add-to-list 'tab-bar-format 'tab-bar-end-space :append)
362(tab-bar-mode) 624;;(setopt tab-bar-show t)
625;;(tab-bar-mode) ; done after setting fonts
363 626
364;;; Org mode 627;;; Org mode
365 628
@@ -472,3 +735,20 @@ ORG-EXPORT-ARGS are passed to `org-export-to-file'."
472 735
473(keymap-global-set "C-x C-b" #'ibuffer) 736(keymap-global-set "C-x C-b" #'ibuffer)
474(add-hook 'ibuffer-hook #'hl-line-mode) 737(add-hook 'ibuffer-hook #'hl-line-mode)
738
739(autoload 'scule-map "scule" nil nil 'keymap)
740(keymap-global-set "M-c" 'scule-map)
741(with-eval-after-load 'scule
742 (keymap-set scule-map "M-t" #'titlecase-dwim))
743
744;; Use M-u for prefix keys
745(keymap-global-set "M-u" #'universal-argument)
746(keymap-set universal-argument-map "M-u" #'universal-argument-more)
747
748(add-hook 'jabber-chat-mode-hook #'frowny-mode)
749
750(keymap-global-set "M-/" #'hippie-completing-read)
751
752(setopt mode-line-bell-flash-time 0.25)
753(autoload 'mode-line-bell-mode "mode-line-bell" nil t)
754(mode-line-bell-mode)