Blob


1 ;; -*- lexical-binding: t; -*-
2 (require 'seq)
3 (require 'xdg)
5 (package-initialize)
7 (push
8 (let ((lisp-path (expand-file-name "lisp" user-emacs-directory)))
9 (unless (file-exists-p lisp-path)
10 (make-directory lisp-path))
11 lisp-path)
12 load-path)
14 (require 'lh)
15 (require 'lh-insert)
16 (require 'lh-resurrect)
17 (require 'iso-transl)
18 (require 'substitute)
20 (with-eval-after-load 'paredit
21 (require 'paredit-menu))
22 (with-eval-after-load 'restclient
23 (require 'restclient-capf))
24 (with-eval-after-load 'elfeed
25 (require 'elfeed-tube)
26 (require 'elfeed-tube-mpv)
27 (elfeed-tube-setup))
29 (setq org-roam-v2-ack t)
31 (setq lh/dir-documents
32 (expand-file-name
33 (cond ((eq system-type 'gnu/linux) (or (xdg-user-dir "DOCUMENTS") "~/Documents"))
34 ((eq system-type 'windows-nt) "~/Documents"))))
35 (setq lh/dir-data-home
36 (expand-file-name
37 (cond ((eq system-type 'gnu/linux) (or (xdg-data-home) "~/.local/share"))
38 ((eq system-type 'windows-nt) (getenv "APPDATA")))))
40 (defadvice split-window-below (after lh/split-window-below activate)
41 (other-window 1))
42 (defadvice split-window-right (after lh/split-window-right activate)
43 (other-window 1))
44 (defadvice toggle-frame-fullscreen (before lh/toggle-frame-fullscreen-bars activate)
45 (menu-bar-mode (if menu-bar-mode -1 1))
46 (tool-bar-mode (if tool-bar-mode -1 1))
47 (scroll-bar-mode (if scroll-bar-mode -1 1)))
49 (defun lh/org-capture-skip-below-toplevel ()
50 (when (> (org-current-level) 1)
51 (save-excursion (org-end-of-subtree t))))
53 (defun lh/diff-file-changes ()
54 (interactive)
55 (let ((file-name (make-temp-file "emacs-diff-"))
56 (original-file-name (buffer-file-name)))
57 (unwind-protect
58 (progn
59 (unwind-protect
60 (progn
61 (set-visited-file-name file-name)
62 (save-buffer))
63 (set-visited-file-name original-file-name))
64 (diff original-file-name file-name nil t))
65 (delete-file file-name))))
67 (defun lh/indent-region-inhibit-message (start end &optional column)
68 (interactive "r\nP")
69 (let ((inhibit-message t))
70 (indent-region start end column)))
72 (defmacro lh/global-set-keys (keys-alist)
73 `(progn
74 ,@(seq-map
75 (lambda (x)
76 `(global-set-key (kbd ,(car x)) #',(cdr x)))
77 keys-alist)))
79 (defmacro lh/define-keys (keymap keys-alist &optional after)
80 (let ((defines (seq-map
81 (lambda (x)
82 `(define-key
83 ,keymap
84 ,(let ((key (car x)))
85 (cond
86 ((stringp key) `(kbd ,key))
87 (t key)))
88 #',(cdr x)))
89 keys-alist)))
90 (if (null after)
91 (cons 'progn defines)
92 `(with-eval-after-load ',after
93 ,@defines))))
95 (lh/global-set-keys
96 (("C-x C-M-t" . transpose-regions)
97 ("C-x K" . kill-current-buffer)
98 ("C-x C-b" . ibuffer)
100 ;;;; Consult bindings
101 ;; C-c bindings (mode-specific-map)
102 ("C-c h" . consult-history)
103 ("C-c m" . consult-mode-command)
104 ("C-c b" . consult-bookmark)
105 ("C-c k" . consult-kmacro)
106 ;; C-x bindings (ctl-x-map)
107 ("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
108 ("C-x b" . consult-buffer) ;; orig. switch-to-buffer
109 ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
110 ("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
111 ;; Custom M-# bindings for fast register access
112 ("M-#" . consult-register-load)
113 ("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
114 ("C-M-#" . consult-register)
115 ;; Other custom bindings'
116 ("<help> a" . consult-apropos) ;; orig. apropos-command
117 ;; M-g bindings (goto-map)
118 ("M-g e" . consult-compile-error)
119 ("M-g f" . consult-flymake) ;; Alternative: consult-flycheck
120 ("M-g g" . consult-goto-line) ;; orig. goto-line
121 ("M-g M-g" . consult-goto-line) ;; orig. goto-line
122 ("M-g o" . consult-outline) ;; Alternative: consult-org-heading
123 ("M-g m" . consult-mark)
124 ("M-g k" . consult-global-mark)
125 ("M-g i" . consult-imenu)
126 ("M-g I" . consult-imenu-multi)
127 ;; M-s bindings (search-map)
128 ("M-s f" . consult-find)
129 ("M-s L" . consult-locate)
130 ("M-s g" . consult-grep)
131 ("M-s G" . consult-git-grep)
132 ("M-s l" . consult-line)
133 ("M-s m" . consult-multi-occur)
134 ("M-s k" . consult-keep-lines)
135 ("M-s u" . consult-focus-lines)
136 ("M-s s" . consult-eglot-symbols)
137 ;; Isearch integration
138 ("M-s e" . consult-isearch)
140 ("C-." . embark-act)
141 ("M-." . embark-dwim)
143 ("C-+" . er/expand-region)
145 ("M-o" . ace-window)
147 ("C-c '" . imenu-list-smart-toggle)
149 ("C-c r l" . org-roam-buffer-toggle)
150 ("C-c r f" . org-roam-node-find)
151 ("C-c r i" . org-roam-node-insert)
153 ("C-h f" . helpful-callable)
154 ("C-h F" . helpful-function)
155 ("C-h C" . helpful-command)
156 ("C-h v" . helpful-variable)
157 ("C-h k" . helpful-key)
158 ("C-c C-d" . helpful-at-point)
160 ("C-S-p" . lh/move-line-up)
161 ("M-<up>" . lh/move-line-up)
162 ("C-S-n" . lh/move-line-down)
163 ("M-<down>" . lh/move-line-down)
165 ("M-s r" . deadgrep)
167 ("C-c p" . lh/pop-out-buffer)
168 ("C-c n" . lh/buffer-create-new)
169 ("C-c a" . org-agenda)
170 ("C-c c" . org-capture)
171 ("C-c l" . org-store-link)
172 ("C-c s" . substitute-prefix-map)
174 ("C-c i j" . lh/insert-json-encoded)
175 ("C-c i i s" . lh/insert-random-sha1)
176 ("C-c i i u" . uuidgen)
177 ("C-c i r f" . lh/insert-number-from-register-format)
179 ("C-c e x" . lh/xml-escape-region)
181 ("<mouse-8>" . xref-go-back)
182 ("<mouse-9>" . xref-go-forward)))
184 (lh/define-keys icomplete-fido-mode-map
185 (("TAB" . icomplete-force-complete)
186 ("<left>" . left-char)
187 ("<right>" . right-char)
188 ("^" . icomplete-fido-backward-updir)
189 ("DEL" . backward-delete-char))
190 icomplete)
191 (lh/define-keys isearch-mode-map
192 (("M-e" . consult-isearch)
193 ("M-s e" . consult-isearch)
194 ("M-s l" . consult-line)))
195 (lh/define-keys paredit-mode-map
196 (("M-s" . nil)
197 ("M-S" . paredit-splice-sexp))
198 paredit)
199 (lh/define-keys elfeed-search-mode-map
200 (("G" . elfeed-update))
201 elfeed)
202 (lh/define-keys json-mode-map
203 (("C-c C-j" . jq-interactively))
204 json-mode)
205 (lh/define-keys sly-inspector-mode-map
206 (("<mouse-8>" . sly-inspector-pop)
207 ("<mouse-9>" . sly-inspector-next))
208 sly)
210 (with-eval-after-load 'icomplete
211 (define-key icomplete-minibuffer-map (kbd "C-.") nil))
213 (defun lh/elfeed-show-visit ()
214 (interactive)
215 (let ((link (elfeed-entry-link elfeed-show-entry)))
216 (if (string-match-p (rx
217 line-start
218 "http" (opt "s") "://"
219 (opt "www.")
220 "youtube.com/")
221 link)
222 (elfeed-tube-mpv (point))
223 (elfeed-show-visit))))
225 (lh/define-keys elfeed-show-mode-map
226 (("b" . lh/elfeed-show-visit)
227 ("F" . elfeed-tube-fetch)
228 ([remap save-buffer] . elfeed-tube-save)
229 ("C-c C-f" . elfeed-tube-mpv-follow-mode)
230 ("C-c C-w" . elfeed-tube-mpv-where))
231 elfeed)
232 (lh/define-keys elfeed-search-mode-map
233 (("F" . elfeed-tube-fetch)
234 ([remap save-buffer] . elfeed-tube-save))
235 elfeed)
237 (defun corfu-insert-with-return ()
238 (interactive)
239 (let ((idx corfu--index))
240 (corfu-insert)
241 (when (< idx 0)
242 (funcall (key-binding (kbd "RET")))
243 (indent-according-to-mode))))
245 (lh/define-keys corfu-map
246 (("RET" . corfu-insert-with-return))
247 corfu)
249 (defun lh/lisp-mode-hook ()
250 (paredit-mode 1)
251 (prism-mode 1)
252 (highlight-function-calls-mode 1))
254 (add-hook 'lisp-mode-hook 'lh/lisp-mode-hook)
255 (add-hook 'emacs-lisp-mode-hook 'lh/lisp-mode-hook)
256 ;; Aggressive Intent mode causes 100% CPU for me whenever the sly repl prints warnings
257 (add-hook 'sly-mrepl-mode-hook
258 (lambda ()
259 (aggressive-indent-mode -1)))
260 (add-hook 'embark-collect-mode-hook 'consult-preview-at-point-mode)
261 (add-hook 'prog-mode-hook
262 (lambda ()
263 (setq-local show-trailing-whitespace t)))
265 ;; notmuch's tag selection doesnt work with consult-completing-read-multiple
266 ;; items need to be trimmed
267 (defun lh/notmuch-read-tag-changes-trim (tags)
268 (seq-map (lambda (x)
269 (string-trim-right x))
270 tags))
272 (advice-add #'notmuch-read-tag-changes :filter-return #'lh/notmuch-read-tag-changes-trim)
274 ;; Fixes bug in minibuffer.el that causes consult to not work without any text
275 ;; https://github.com/minad/consult/issues/566
276 ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=55205
277 (defun lh/advice-fix-minibuffer-consult (func &rest args)
278 (apply func (list (car args)
279 (cadr args)
280 (copy-sequence (caddr args)))))
282 (advice-add #'completion--replace :around #'lh/advice-fix-minibuffer-consult)
284 (defun lh/advice-fido-setup (func &rest args)
285 (prog1
286 (apply func args)
287 (setq-local completion-styles '(basic substring initials flex))))
289 (advice-add 'icomplete--fido-mode-setup :around #'lh/advice-fido-setup)
291 (setq completion-ignore-case t)
293 (custom-set-variables
294 ;; custom-set-variables was added by Custom.
295 ;; If you edit it by hand, you could mess it up, so be careful.
296 ;; Your init file should contain only one such instance.
297 ;; If there is more than one, they won't work right.
298 '(aggressive-indent-region-function 'lh/indent-region-inhibit-message)
299 '(all-the-icons-completion-mode t)
300 '(auth-sources '(default))
301 '(aw-dispatch-always t)
302 '(aw-keys '(97 115 100 102 103 104 106 107 108))
303 '(aw-scope 'frame)
304 '(backup-by-copying t)
305 '(before-save-hook '(whitespace-cleanup))
306 '(bookmark-completion-ignore-case nil)
307 '(calendar-christian-all-holidays-flag nil)
308 '(calendar-mark-holidays-flag t)
309 '(calendar-week-start-day 1)
310 '(column-number-mode t)
311 '(completion-ignore-case t t)
312 '(completion-styles '(basic substring initials))
313 '(context-menu-mode t)
314 '(corfu-auto t)
315 '(corfu-auto-delay 0.0)
316 '(corfu-auto-prefix 1)
317 '(corfu-popupinfo-delay '(0 . 0))
318 '(corfu-popupinfo-hide nil)
319 '(corfu-popupinfo-mode t)
320 '(corfu-preselect 'prompt)
321 '(corfu-quit-at-boundary t)
322 '(create-lockfiles nil)
323 '(cursor-type 'bar)
324 '(custom-enabled-themes '(modus-operandi))
325 '(custom-safe-themes
326 '("1ea82e39d89b526e2266786886d1f0d3a3fa36c87480fad59d8fab3b03ef576e"
327 "3d94d6d1a1c23113a60c8496c9aed094dbc2695f219e8127bb168d17b1e6dab3"
328 "4b026ac68a1aa4d1a91879b64f54c2490b4ecad8b64de5b1865bca0addd053d9"
329 "58264887d7ab17702ef85bbd96e11bd7f613622ff9c63990be860b958c978f09"
330 "611ef0918b8b413badb8055089b5499c1d4ac20f1861efba8f3bfcb36ad0a448"
331 "15604b083d03519b0c2ed7b32da6d7b2dc2f6630bef62608def60cdcf9216184"
332 "88cb0f9c0c11dbb4c26a628d35eb9239d1cf580cfd28e332e654e7f58b4e721b"
333 "69f7e8101867cfac410e88140f8c51b4433b93680901bb0b52014144366a08c8"
334 "21e3d55141186651571241c2ba3c665979d1e886f53b2e52411e9e96659132d4"
335 default))
336 '(delete-old-versions t)
337 '(delete-selection-mode t)
338 '(denote-modules '(project xref ffap))
339 '(denote-modules-global-mode t)
340 '(desktop-save-mode t)
341 '(dired-dwim-target 'dired-dwim-target-next)
342 '(dired-kill-when-opening-new-dired-buffer t)
343 '(dired-mode-hook '(all-the-icons-dired-mode))
344 '(display-buffer-alist
345 '(("\\\\*sly-db for"
346 (display-buffer-reuse-window display-buffer-below-selected)
347 (dedicated . t) (window-height . 0.3))
348 ("\\\\*Async Shell Command\\\\*" display-buffer-no-window)))
349 '(ediff-split-window-function 'split-window-horizontally)
350 '(ediff-window-setup-function 'ediff-setup-windows-plain)
351 '(editorconfig-mode t)
352 '(elfeed-tube-auto-save-p t)
353 '(fido-mode t)
354 '(fido-vertical-mode t)
355 '(focus-follows-mouse t)
356 '(frame-resize-pixelwise t)
357 '(global-aggressive-indent-mode t)
358 '(global-auto-revert-mode t)
359 '(global-corfu-mode t)
360 '(global-diff-hl-mode t)
361 '(help-window-select t)
362 '(ibuffer-mode-hook '(all-the-icons-ibuffer-mode))
363 '(ignored-local-variable-values '((Package . SIMPLE-DATE) (sly-load-failed-fasl . ask)))
364 '(indent-tabs-mode nil)
365 '(inferior-lisp-program "sbcl")
366 '(kept-new-versions 10)
367 '(kept-old-versions 5)
368 '(lh/global-resurrect-mode t)
369 '(marginalia-mode t)
370 '(mouse-autoselect-window 0.2)
371 '(mouse-wheel-progressive-speed nil)
372 '(mouse-wheel-scroll-amount '(5 ((shift) . hscroll) ((meta)) ((control) . text-scale)))
373 '(notmuch-archive-tags '("-inbox" "-unread"))
374 '(org-agenda-custom-commands
375 '(("n" "Agenda and all TODOs" ((agenda "" nil) (alltodo "" nil)) nil)
376 ("g" "GTD View"
377 ((agenda "" nil)
378 (tags-todo "+aktion+TODO=\"NEXT\""
379 ((org-agenda-overriding-header "Nächste Aktionen:")))
380 (tags "projekt"
381 ((org-agenda-overriding-header "Projekte:")
382 (org-agenda-skip-function
383 'lh/org-capture-skip-below-toplevel)))
384 (tags-todo "WAITING"
385 ((org-agenda-overriding-header "Warten auf:"))))
386 nil nil)))
387 '(org-agenda-loop-over-headlines-in-active-region nil)
388 '(org-babel-load-languages '((awk . t) (lisp . t) (shell . t) (emacs-lisp . t)))
389 '(org-html-validation-link "")
390 '(org-log-done 'time)
391 '(org-log-done-with-time t)
392 '(org-refile-use-outline-path 'file)
393 '(org-src-window-setup 'other-window)
394 '(org-startup-folded t)
395 '(org-startup-indented t)
396 '(org-startup-truncated nil)
397 '(package-archive-priorities
398 '(("gnu" . 3) ("nongnu" . 2) ("melpa-stable" . 1) ("melpa" . 0)))
399 '(package-archives
400 '(("gnu" . "https://elpa.gnu.org/packages/")
401 ("nongnu" . "https://elpa.nongnu.org/nongnu/")
402 ("melpa-stable" . "https://stable.melpa.org/packages/")
403 ("melpa" . "https://melpa.org/packages/")))
404 '(package-pinned-packages '((sly . "melpa")))
405 '(package-selected-packages
406 '(ace-window aggressive-indent all-the-icons-completion
407 all-the-icons-dired all-the-icons-ibuffer
408 atomic-chrome consult consult-eglot corfu deadgrep
409 denote denote-menu denote-refs diff-hl diminish
410 editorconfig eglot elfeed elfeed-tube elfeed-tube-mpv
411 embark embark-consult expand-region go-mode
412 graphviz-dot-mode helpful highlight-function-calls
413 imenu-list jq-mode json-mode lexic lua-mode magit
414 marginalia modus-themes nhexl-mode notmuch nov
415 ob-powershell ob-restclient org org-contrib ox-epub
416 paredit paredit-menu pdf-tools powershell prism
417 project restclient restclient-jq sly sly-macrostep
418 sly-named-readtables substitute uuidgen web-mode
419 which-key yaml-mode))
420 '(pixel-scroll-precision-mode t)
421 '(prism-parens t)
422 '(read-buffer-completion-ignore-case t)
423 '(read-file-name-completion-ignore-case t)
424 '(reb-re-syntax 'string)
425 '(recentf-max-saved-items 200)
426 '(recentf-mode t)
427 '(repeat-mode t)
428 '(ring-bell-function 'ignore)
429 '(safe-local-variable-values
430 '((Syntax . ANSI-Common-Lisp) (Package . POSTMODERN) (Base . 10)
431 (Syntax . Ansi-Common-Lisp)))
432 '(save-place-mode t)
433 '(savehist-mode t)
434 '(scroll-conservatively 100)
435 '(tab-always-indent 'complete)
436 '(use-short-answers t)
437 '(warning-suppress-types '((comp)))
438 '(which-key-mode t))
439 (custom-set-faces
440 ;; custom-set-faces was added by Custom.
441 ;; If you edit it by hand, you could mess it up, so be careful.
442 ;; Your init file should contain only one such instance.
443 ;; If there is more than one, they won't work right.
444 '(default ((t (:family "Go Mono"))))
445 '(variable-pitch ((t (:family "IBM Plex Serif")))))
447 ;; This is the place where I override all customize stuff
449 (with-eval-after-load 'prism
450 (prism-set-colors
451 :desaturations '(0)
452 :lightens '(0)
453 :colors (modus-themes-with-colors
454 (list fg-main
455 magenta
456 cyan-cooler
457 magenta-cooler
458 blue
459 magenta-warmer
460 cyan-warmer
461 red-cooler
462 green
463 fg-main
464 cyan
465 yellow
466 blue-warmer
467 red-warmer
468 green-cooler
469 yellow-faint))))
471 (let ((feeds (expand-file-name "feeds.el" user-emacs-directory)))
472 (when (file-exists-p feeds)
473 (load feeds)))
475 (customize-set-value
476 'elfeed-db-directory
477 (let ((data-dir (expand-file-name "elfeed" lh/dir-data-home)))
478 (unless (file-exists-p data-dir)
479 (make-directory data-dir))
480 data-dir))
482 (customize-set-value
483 'backup-directory-alist
484 (let ((backup-dir (concat user-emacs-directory "backup")))
485 (unless (file-exists-p backup-dir)
486 (make-directory backup-dir t))
487 `(("." . ,backup-dir))))
489 (let* ((dir (expand-file-name "org" lh/dir-documents))
490 (notes-dir (expand-file-name "notes" dir)))
491 (unless (file-exists-p dir)
492 (make-directory dir t))
493 (unless (file-exists-p notes-dir)
494 (make-directory notes-dir t))
495 (setopt org-directory dir
496 org-agenda-files (list dir)
497 denote-directory notes-dir
498 org-capture-templates `(("i" "Inbox" entry
499 (file ,(expand-file-name "inbox.org" dir))
500 "* %?"))))
502 (customize-set-value
503 'dired-guess-shell-alist-user
504 (cond
505 ((eq system-type 'gnu/linux)
506 `((,(rx "." (or "png" "jpg" (seq "jp" (? "e") "g"))) "pqiv")
507 (,(rx "." (or "mkv" "mp4" "webm" "ogv" "avi")) "mpv")
508 (,(rx "." (or "flac" "ogg" "mp3" "wav")) "mpv --force-window")))
509 (t nil)))
511 (diminish 'which-key-mode)
512 (diminish 'aggressive-indent-mode)
513 (diminish 'editorconfig-mode)
515 (let ((path (expand-file-name "private.el" user-emacs-directory)))
516 (when (file-exists-p path)
517 (load path)))
519 (pdf-loader-install)
521 (server-start)
522 (put 'narrow-to-region 'disabled nil)