1 ;; -*- lexical-binding: t; -*-
8 (let ((lisp-path (expand-file-name "lisp" user-emacs-directory)))
9 (unless (file-exists-p lisp-path)
10 (make-directory lisp-path))
16 (require 'lh-resurrect)
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)
29 (setq org-roam-v2-ack t)
31 (setq lh/dir-documents
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
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)
42 (defadvice split-window-right (after lh/split-window-right activate)
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 ()
55 (let ((file-name (make-temp-file "emacs-diff-"))
56 (original-file-name (buffer-file-name)))
61 (set-visited-file-name file-name)
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)
69 (let ((inhibit-message t))
70 (indent-region start end column)))
72 (defmacro lh/global-set-keys (keys-alist)
76 `(global-set-key (kbd ,(car x)) #',(cdr x)))
79 (defmacro lh/define-keys (keymap keys-alist &optional after)
80 (let ((defines (seq-map
86 ((stringp key) `(kbd ,key))
92 `(with-eval-after-load ',after
96 (("C-x C-M-t" . transpose-regions)
97 ("C-x K" . kill-current-buffer)
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)
141 ("M-." . embark-dwim)
143 ("C-+" . er/expand-region)
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)
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))
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
197 ("M-S" . paredit-splice-sexp))
199 (lh/define-keys elfeed-search-mode-map
200 (("G" . elfeed-update))
202 (lh/define-keys json-mode-map
203 (("C-c C-j" . jq-interactively))
205 (lh/define-keys sly-inspector-mode-map
206 (("<mouse-8>" . sly-inspector-pop)
207 ("<mouse-9>" . sly-inspector-next))
210 (with-eval-after-load 'icomplete
211 (define-key icomplete-minibuffer-map (kbd "C-.") nil))
213 (defun lh/elfeed-show-visit ()
215 (let ((link (elfeed-entry-link elfeed-show-entry)))
216 (if (string-match-p (rx
218 "http" (opt "s") "://"
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))
232 (lh/define-keys elfeed-search-mode-map
233 (("F" . elfeed-tube-fetch)
234 ([remap save-buffer] . elfeed-tube-save))
237 (defun corfu-insert-with-return ()
239 (let ((idx corfu--index))
242 (funcall (key-binding (kbd "RET")))
243 (indent-according-to-mode))))
245 (lh/define-keys corfu-map
246 (("RET" . corfu-insert-with-return))
249 (defun lh/lisp-mode-hook ()
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
259 (aggressive-indent-mode -1)))
260 (add-hook 'embark-collect-mode-hook 'consult-preview-at-point-mode)
261 (add-hook 'prog-mode-hook
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)
269 (string-trim-right x))
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)
280 (copy-sequence (caddr args)))))
282 (advice-add #'completion--replace :around #'lh/advice-fix-minibuffer-consult)
284 ;; file-name-all-completions seems to return file names in whatever order the
285 ;; filesystem feels like returning. This is super annoying with the flex
286 ;; completion style. If the FS returns "barfoo" before "foobar", flex completion
287 ;; will match "barfoo" first. This advice sorts the file name list.
288 (defun lh/advice-sort-file-name-all-completions (files)
289 (sort files #'string<))
291 (advice-add 'file-name-all-completions :filter-return 'lh/advice-sort-file-name-all-completions)
293 (setq completion-ignore-case t)
295 (custom-set-variables
296 ;; custom-set-variables was added by Custom.
297 ;; If you edit it by hand, you could mess it up, so be careful.
298 ;; Your init file should contain only one such instance.
299 ;; If there is more than one, they won't work right.
300 '(aggressive-indent-region-function 'lh/indent-region-inhibit-message)
301 '(all-the-icons-completion-mode t)
302 '(auth-sources '(default))
303 '(aw-dispatch-always t)
304 '(aw-keys '(97 115 100 102 103 104 106 107 108))
306 '(backup-by-copying t)
307 '(before-save-hook '(whitespace-cleanup))
308 '(bookmark-completion-ignore-case nil)
309 '(calendar-christian-all-holidays-flag nil)
310 '(calendar-mark-holidays-flag t)
311 '(calendar-week-start-day 1)
312 '(column-number-mode t)
313 '(completion-ignore-case t t)
314 '(completion-styles '(basic substring initials))
315 '(context-menu-mode t)
317 '(corfu-auto-delay 0.0)
318 '(corfu-auto-prefix 1)
319 '(corfu-popupinfo-delay '(0 . 0))
320 '(corfu-popupinfo-hide nil)
321 '(corfu-popupinfo-mode t)
322 '(corfu-preselect 'prompt)
323 '(corfu-quit-at-boundary t)
324 '(create-lockfiles nil)
326 '(custom-enabled-themes '(modus-operandi))
328 '("1ea82e39d89b526e2266786886d1f0d3a3fa36c87480fad59d8fab3b03ef576e" "3d94d6d1a1c23113a60c8496c9aed094dbc2695f219e8127bb168d17b1e6dab3" "4b026ac68a1aa4d1a91879b64f54c2490b4ecad8b64de5b1865bca0addd053d9" "58264887d7ab17702ef85bbd96e11bd7f613622ff9c63990be860b958c978f09" "611ef0918b8b413badb8055089b5499c1d4ac20f1861efba8f3bfcb36ad0a448" "15604b083d03519b0c2ed7b32da6d7b2dc2f6630bef62608def60cdcf9216184" "88cb0f9c0c11dbb4c26a628d35eb9239d1cf580cfd28e332e654e7f58b4e721b" "69f7e8101867cfac410e88140f8c51b4433b93680901bb0b52014144366a08c8" "21e3d55141186651571241c2ba3c665979d1e886f53b2e52411e9e96659132d4" default))
329 '(delete-old-versions t)
330 '(delete-selection-mode t)
331 '(denote-modules '(project xref ffap))
332 '(denote-modules-global-mode t)
333 '(desktop-save-mode t)
334 '(dired-dwim-target 'dired-dwim-target-next)
335 '(dired-kill-when-opening-new-dired-buffer t)
336 '(dired-mode-hook '(all-the-icons-dired-mode))
337 '(display-buffer-alist
339 (display-buffer-reuse-window display-buffer-below-selected)
341 (window-height . 0.3))
342 ("\\\\*Async Shell Command\\\\*" display-buffer-no-window)))
343 '(ediff-split-window-function 'split-window-horizontally)
344 '(ediff-window-setup-function 'ediff-setup-windows-plain)
345 '(editorconfig-mode t)
346 '(elfeed-tube-auto-save-p t)
348 '(fido-vertical-mode t)
349 '(focus-follows-mouse t)
350 '(frame-resize-pixelwise t)
351 '(global-aggressive-indent-mode t)
352 '(global-auto-revert-mode t)
353 '(global-corfu-mode t)
354 '(global-diff-hl-mode t)
355 '(help-window-select t)
356 '(ibuffer-mode-hook '(all-the-icons-ibuffer-mode))
357 '(ignored-local-variable-values '((sly-load-failed-fasl . ask)))
358 '(indent-tabs-mode nil)
359 '(inferior-lisp-program "sbcl")
360 '(kept-new-versions 10)
361 '(kept-old-versions 5)
362 '(lh/global-resurrect-mode t)
364 '(mouse-autoselect-window 0.2)
365 '(mouse-wheel-progressive-speed nil)
366 '(mouse-wheel-scroll-amount '(5 ((shift) . hscroll) ((meta)) ((control) . text-scale)))
367 '(notmuch-archive-tags '("-inbox" "-unread"))
368 '(org-agenda-custom-commands
369 '(("n" "Agenda and all TODOs"
375 (tags-todo "+aktion+TODO=\"NEXT\""
376 ((org-agenda-overriding-header "Nächste Aktionen:")))
378 ((org-agenda-overriding-header "Projekte:")
379 (org-agenda-skip-function 'lh/org-capture-skip-below-toplevel)))
381 ((org-agenda-overriding-header "Warten auf:"))))
383 '(org-agenda-loop-over-headlines-in-active-region nil)
384 '(org-babel-load-languages '((awk . t) (lisp . t) (shell . t) (emacs-lisp . t)))
385 '(org-html-validation-link "")
386 '(org-log-done 'time)
387 '(org-log-done-with-time t)
388 '(org-refile-use-outline-path 'file)
389 '(org-src-window-setup 'other-window)
390 '(org-startup-folded t)
391 '(org-startup-indented t)
392 '(org-startup-truncated nil)
393 '(package-archive-priorities
399 '(("gnu" . "https://elpa.gnu.org/packages/")
400 ("nongnu" . "https://elpa.nongnu.org/nongnu/")
401 ("melpa-stable" . "https://stable.melpa.org/packages/")
402 ("melpa" . "https://melpa.org/packages/")))
403 '(package-pinned-packages '((sly . "melpa")))
404 '(package-selected-packages
405 '(notmuch substitute highlight-function-calls prism modus-themes imenu-list diff-hl embark-consult embark all-the-icons-completion all-the-icons-ibuffer all-the-icons-dired sly-named-readtables sly-macrostep denote-refs denote-menu denote ox-epub ob-powershell powershell web-mode lexic editorconfig elfeed-tube-mpv elfeed-tube restclient-jq graphviz-dot-mode consult-eglot jq-mode ob-restclient restclient deadgrep helpful pdf-tools paredit-menu paredit corfu sly eglot aggressive-indent project nov nhexl-mode elfeed magit yaml-mode json-mode lua-mode go-mode org-contrib org ace-window expand-region consult marginalia uuidgen diminish which-key))
406 '(pcomplete-ignore-case t t)
407 '(pixel-scroll-precision-mode t)
409 '(read-buffer-completion-ignore-case t)
410 '(read-file-name-completion-ignore-case t)
411 '(reb-re-syntax 'string)
412 '(recentf-max-saved-items 200)
415 '(ring-bell-function 'ignore)
416 '(safe-local-variable-values
417 '((Syntax . ANSI-Common-Lisp) (Package . POSTMODERN) (Base . 10)
418 (Syntax . Ansi-Common-Lisp)))
421 '(scroll-conservatively 100)
422 '(tab-always-indent 'complete)
423 '(use-short-answers t)
424 '(warning-suppress-types '((comp)))
427 ;; custom-set-faces was added by Custom.
428 ;; If you edit it by hand, you could mess it up, so be careful.
429 ;; Your init file should contain only one such instance.
430 ;; If there is more than one, they won't work right.
431 '(default ((t (:family "Go Mono"))))
432 '(variable-pitch ((t (:family "IBM Plex Serif")))))
434 ;; This is the place where I override all customize stuff
436 (with-eval-after-load 'prism
440 :colors (modus-themes-with-colors
458 (let ((feeds (expand-file-name "feeds.el" user-emacs-directory)))
459 (when (file-exists-p feeds)
464 (let ((data-dir (expand-file-name "elfeed" lh/dir-data-home)))
465 (unless (file-exists-p data-dir)
466 (make-directory data-dir))
470 'backup-directory-alist
471 (let ((backup-dir (concat user-emacs-directory "backup")))
472 (unless (file-exists-p backup-dir)
473 (make-directory backup-dir t))
474 `(("." . ,backup-dir))))
476 (let* ((dir (expand-file-name "org" lh/dir-documents))
477 (roam-dir (expand-file-name "notes" dir)))
478 (unless (file-exists-p dir)
479 (make-directory dir t))
480 (unless (file-exists-p roam-dir)
481 (make-directory roam-dir t))
491 (with-eval-after-load "org"
492 (setq org-capture-templates
493 `(("g" "GTD Inbox" entry
494 (file ,(expand-file-name "inbox.org" dir))
498 'dired-guess-shell-alist-user
500 ((eq system-type 'gnu/linux)
501 `((,(rx "." (or "png" "jpg" (seq "jp" (? "e") "g"))) "pqiv")
502 (,(rx "." (or "mkv" "mp4" "webm" "ogv" "avi")) "mpv")
503 (,(rx "." (or "flac" "ogg" "mp3" "wav")) "mpv --force-window")))
506 (diminish 'which-key-mode)
507 (diminish 'aggressive-indent-mode)
508 (diminish 'editorconfig-mode)
510 (let ((path (expand-file-name "private.el" user-emacs-directory)))
511 (when (file-exists-p path)
517 (put 'narrow-to-region 'disabled nil)