dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

init.el (14667B)


      1 ;; -*- lexical-binding: t; -*-
      2 (require 'seq)
      3 (require 'xdg)
      4 
      5 (package-initialize)
      6 
      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)
     13 
     14 (require 'lh)
     15 (require 'lh-insert)
     16 (require 'lh-resurrect)
     17 (require 'iso-transl)
     18 
     19 (with-eval-after-load 'paredit
     20   (require 'paredit-menu))
     21 (with-eval-after-load 'restclient
     22   (require 'restclient-capf))
     23 (with-eval-after-load 'elfeed
     24   (require 'elfeed-tube)
     25   (require 'elfeed-tube-mpv)
     26   (elfeed-tube-setup))
     27 
     28 (setq org-roam-v2-ack t)
     29 
     30 (setq lh/dir-documents
     31       (expand-file-name
     32        (cond ((eq system-type 'gnu/linux) (or (xdg-user-dir "DOCUMENTS") "~/Documents"))
     33              ((eq system-type 'windows-nt) "~/Documents"))))
     34 (setq lh/dir-data-home
     35       (expand-file-name
     36        (cond ((eq system-type 'gnu/linux) (or (xdg-data-home) "~/.local/share"))
     37              ((eq system-type 'windows-nt) (getenv "APPDATA")))))
     38 
     39 (defadvice split-window-below (after lh/split-window-below activate)
     40   (other-window 1))
     41 (defadvice split-window-right (after lh/split-window-right activate)
     42   (other-window 1))
     43 (defadvice toggle-frame-fullscreen (before lh/toggle-frame-fullscreen-bars activate)
     44   (menu-bar-mode (if menu-bar-mode -1 1))
     45   (tool-bar-mode (if tool-bar-mode -1 1))
     46   (scroll-bar-mode (if scroll-bar-mode -1 1)))
     47 
     48 (defun lh/org-capture-skip-below-toplevel ()
     49   (when (> (org-current-level) 1)
     50     (save-excursion (org-end-of-subtree t))))
     51 
     52 (defun lh/diff-file-changes ()
     53   (interactive)
     54   (let ((file-name (make-temp-file "emacs-diff-"))
     55         (original-file-name (buffer-file-name)))
     56     (unwind-protect
     57         (progn
     58           (unwind-protect
     59               (progn
     60                 (set-visited-file-name file-name)
     61                 (save-buffer))
     62             (set-visited-file-name original-file-name))
     63           (diff original-file-name file-name nil t))
     64       (delete-file file-name))))
     65 
     66 (defmacro lh/global-set-keys (keys-alist)
     67   `(progn
     68      ,@(seq-map
     69         (lambda (x)
     70           `(global-set-key (kbd ,(car x)) #',(cdr x)))
     71         keys-alist)))
     72 
     73 (defmacro lh/define-keys (keymap keys-alist &optional after)
     74   (let ((defines (seq-map
     75                   (lambda (x)
     76                     `(define-key
     77                       ,keymap
     78                       ,(let ((key (car x)))
     79                          (cond
     80                           ((stringp key) `(kbd ,key))
     81                           (t key)))
     82                       #',(cdr x)))
     83                   keys-alist)))
     84     (if (null after)
     85         (cons 'progn defines)
     86       `(with-eval-after-load ',after
     87          ,@defines))))
     88 
     89 (lh/global-set-keys
     90  (("C-x C-M-t" . transpose-regions)
     91   ("C-x K" . kill-this-buffer)
     92 
     93   ;;;; Consult bindings
     94   ;; C-c bindings (mode-specific-map)
     95   ("C-c h" . consult-history)
     96   ("C-c m" . consult-mode-command)
     97   ("C-c b" . consult-bookmark)
     98   ("C-c k" . consult-kmacro)
     99   ;; C-x bindings (ctl-x-map)
    100   ("C-x M-:" . consult-complex-command)     ;; orig. repeat-complex-command
    101   ("C-x b" . consult-buffer)                ;; orig. switch-to-buffer
    102   ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
    103   ("C-x 5 b" . consult-buffer-other-frame)  ;; orig. switch-to-buffer-other-frame
    104   ;; Custom M-# bindings for fast register access
    105   ("M-#" . consult-register-load)
    106   ("M-'" . consult-register-store)          ;; orig. abbrev-prefix-mark (unrelated)
    107   ("C-M-#" . consult-register)
    108   ;; Other custom bindings'
    109   ("<help> a" . consult-apropos)            ;; orig. apropos-command
    110   ;; M-g bindings (goto-map)
    111   ("M-g e" . consult-compile-error)
    112   ("M-g f" . consult-flymake)               ;; Alternative: consult-flycheck
    113   ("M-g g" . consult-goto-line)             ;; orig. goto-line
    114   ("M-g M-g" . consult-goto-line)           ;; orig. goto-line
    115   ("M-g o" . consult-outline)               ;; Alternative: consult-org-heading
    116   ("M-g m" . consult-mark)
    117   ("M-g k" . consult-global-mark)
    118   ("M-g i" . consult-imenu)
    119   ("M-g I" . consult-imenu-multi)
    120   ;; M-s bindings (search-map)
    121   ("M-s f" . consult-find)
    122   ("M-s L" . consult-locate)
    123   ("M-s g" . consult-grep)
    124   ("M-s G" . consult-git-grep)
    125   ("M-s l" . consult-line)
    126   ("M-s m" . consult-multi-occur)
    127   ("M-s k" . consult-keep-lines)
    128   ("M-s u" . consult-focus-lines)
    129   ("M-s s" . consult-eglot-symbols)
    130   ;; Isearch integration
    131   ("M-s e" . consult-isearch)
    132 
    133   ("C-+" . er/expand-region)
    134 
    135   ("M-o" . ace-window)
    136 
    137   ("C-c r l" . org-roam-buffer-toggle)
    138   ("C-c r f" . org-roam-node-find)
    139   ("C-c r i" . org-roam-node-insert)
    140 
    141   ("C-h f" . helpful-callable)
    142   ("C-h F" . helpful-function)
    143   ("C-h C" . helpful-command)
    144   ("C-h v" . helpful-variable)
    145   ("C-h k" . helpful-key)
    146   ("C-c C-d" . helpful-at-point)
    147 
    148   ("C-S-p" . lh/move-line-up)
    149   ("M-<up>" . lh/move-line-up)
    150   ("C-S-n" . lh/move-line-down)
    151   ("M-<down>" . lh/move-line-down)
    152 
    153   ("M-s r" . deadgrep)
    154 
    155   ("C-# a" . mc/mark-all-like-this-dwim)
    156   ("C-# w" . mc/mark-all-words-like-this)
    157   ("C-# n" . mc/mark-next-like-this)
    158   ("C-# p" . mc/mark-previous-like-this)
    159 
    160   ("C-c p" . lh/pop-out-buffer)
    161   ("C-c n" . lh/buffer-create-new)
    162   ("C-c a" . org-agenda)
    163   ("C-c c" . org-capture)
    164   ("C-c l" . org-store-link)
    165 
    166   ("C-c i j" . lh/insert-json-encoded)
    167   ("C-c i i s" . lh/insert-random-sha1)
    168   ("C-c i i u" . uuidgen)
    169   ("C-c i r f" . lh/insert-number-from-register-format)
    170 
    171   ("C-c e x" . lh/xml-escape-region)
    172 
    173   ("<mouse-8>" . xref-go-back)
    174   ("<mouse-9>" . xref-go-forward)))
    175 
    176 (lh/define-keys icomplete-fido-mode-map
    177                 (("TAB" . icomplete-force-complete)
    178                  ("<left>" . left-char)
    179                  ("<right>" . right-char)
    180                  ("^" . icomplete-fido-backward-updir)
    181                  ("DEL" . backward-delete-char))
    182                 icomplete)
    183 (lh/define-keys isearch-mode-map
    184                 (("M-e" . consult-isearch)
    185                  ("M-s e" . consult-isearch)
    186                  ("M-s l" . consult-line)))
    187 (lh/define-keys paredit-mode-map
    188                 (("M-s" . nil)
    189                  ("M-S" . paredit-splice-sexp))
    190                 paredit)
    191 (lh/define-keys elfeed-search-mode-map
    192                 (("G" . elfeed-update))
    193                 elfeed)
    194 (lh/define-keys json-mode-map
    195                 (("C-c C-j" . jq-interactively))
    196                 json-mode)
    197 (lh/define-keys sly-inspector-mode-map
    198                 (("<mouse-8>" . sly-inspector-pop)
    199                  ("<mouse-9>" . sly-inspector-next))
    200                 sly)
    201 
    202 (defun lh/elfeed-show-visit ()
    203   (interactive)
    204   (let ((link (elfeed-entry-link elfeed-show-entry)))
    205     (if (string-match-p (rx
    206                          line-start
    207                          "http" (opt "s") "://"
    208                          (opt "www.")
    209                          "youtube.com/")
    210                         link)
    211         (elfeed-tube-mpv (point))
    212       (elfeed-show-visit))))
    213 
    214 (lh/define-keys elfeed-show-mode-map
    215                 (("b" . lh/elfeed-show-visit)
    216                  ("F" . elfeed-tube-fetch)
    217                  ([remap save-buffer] . elfeed-tube-save)
    218                  ("C-c C-f" . elfeed-tube-mpv-follow-mode)
    219                  ("C-c C-w" . elfeed-tube-mpv-where))
    220                 elfeed)
    221 (lh/define-keys elfeed-search-mode-map
    222                 (("F" . elfeed-tube-fetch)
    223                  ([remap save-buffer] . elfeed-tube-save))
    224                 elfeed)
    225 
    226 (defun corfu-insert-with-return ()
    227   (interactive)
    228   (let ((idx corfu--index))
    229     (corfu-insert)
    230     (when (< idx 0)
    231       (funcall (key-binding (kbd "RET")))
    232       (indent-according-to-mode))))
    233 
    234 (lh/define-keys corfu-map
    235                 (("RET" . corfu-insert-with-return))
    236                 corfu)
    237 
    238 (add-hook 'lisp-mode-hook #'paredit-mode)
    239 (add-hook 'emacs-lisp-mode-hook #'paredit-mode)
    240 ;; Aggressive Intent mode causes 100% CPU for me whenever the sly repl prints warnings
    241 (add-hook 'sly-mrepl-mode-hook (lambda () (aggressive-indent-mode -1)))
    242 
    243 ;; notmuch's tag selection doesnt work with consult-completing-read-multiple
    244 ;; items need to be trimmed
    245 (defun lh/notmuch-read-tag-changes-trim (tags)
    246   (seq-map (lambda (x)
    247              (string-trim-right x))
    248            tags))
    249 
    250 (advice-add #'notmuch-read-tag-changes :filter-return #'lh/notmuch-read-tag-changes-trim)
    251 
    252 ;; Fixes bug in minibuffer.el that causes consult to not work without any text
    253 ;; https://github.com/minad/consult/issues/566
    254 ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=55205
    255 (defun lh/advice-fix-minibuffer-consult (func &rest args)
    256   (apply func (list (car args)
    257                     (cadr args)
    258                     (copy-sequence (caddr args)))))
    259 
    260 (advice-add #'completion--replace :around #'lh/advice-fix-minibuffer-consult)
    261 
    262 (setq completion-ignore-case t)
    263 
    264 (custom-set-variables
    265  ;; custom-set-variables was added by Custom.
    266  ;; If you edit it by hand, you could mess it up, so be careful.
    267  ;; Your init file should contain only one such instance.
    268  ;; If there is more than one, they won't work right.
    269  '(auth-sources '("~/.authinfo.gpg"))
    270  '(aw-dispatch-always t)
    271  '(aw-keys '(97 115 100 102 103 104 106 107 108))
    272  '(aw-scope 'frame)
    273  '(backup-by-copying t)
    274  '(before-save-hook '(whitespace-cleanup))
    275  '(bookmark-completion-ignore-case nil)
    276  '(calendar-christian-all-holidays-flag nil)
    277  '(calendar-mark-holidays-flag t)
    278  '(calendar-week-start-day 1)
    279  '(column-number-mode t)
    280  '(company-idle-delay 0)
    281  '(completion-ignore-case t t)
    282  '(completion-styles '(basic substring initials))
    283  '(context-menu-mode t)
    284  '(corfu-auto t)
    285  '(corfu-auto-delay 0.0)
    286  '(corfu-auto-prefix 1)
    287  '(corfu-preselect-first nil)
    288  '(corfu-quit-at-boundary t)
    289  '(create-lockfiles nil)
    290  '(cursor-type 'bar)
    291  '(delete-old-versions t)
    292  '(delete-selection-mode t)
    293  '(dired-dwim-target 'dired-dwim-target-next)
    294  '(dired-kill-when-opening-new-dired-buffer t)
    295  '(ediff-split-window-function 'split-window-horizontally)
    296  '(editorconfig-mode t)
    297  '(elfeed-tube-auto-save-p t)
    298  '(fido-mode t)
    299  '(fido-vertical-mode t)
    300  '(frame-resize-pixelwise t)
    301  '(global-aggressive-indent-mode t)
    302  '(global-auto-revert-mode t)
    303  '(global-company-mode t)
    304  '(global-corfu-mode t)
    305  '(help-window-select t)
    306  '(ignored-local-variable-values '((sly-load-failed-fasl . ask)))
    307  '(indent-tabs-mode nil)
    308  '(inferior-lisp-program "ros run")
    309  '(kept-new-versions 10)
    310  '(kept-old-versions 5)
    311  '(lh/global-resurrect-mode t)
    312  '(marginalia-mode t)
    313  '(mouse-wheel-progressive-speed nil)
    314  '(mouse-wheel-scroll-amount '(5 ((shift) . hscroll) ((meta)) ((control) . text-scale)))
    315  '(org-agenda-custom-commands
    316    '(("n" "Agenda and all TODOs"
    317       ((agenda "" nil)
    318        (alltodo "" nil))
    319       nil)
    320      ("g" "GTD View"
    321       ((agenda "" nil)
    322        (tags-todo "+aktion+TODO=\"NEXT\""
    323                   ((org-agenda-overriding-header "Nächste Aktionen:")))
    324        (tags "projekt"
    325              ((org-agenda-overriding-header "Projekte:")
    326               (org-agenda-skip-function 'lh/org-capture-skip-below-toplevel)))
    327        (tags-todo "WAITING"
    328                   ((org-agenda-overriding-header "Warten auf:"))))
    329       nil nil)))
    330  '(org-agenda-loop-over-headlines-in-active-region nil)
    331  '(org-babel-load-languages
    332    '((awk . t)
    333      (lisp . t)
    334      (shell . t)
    335      (emacs-lisp . t)
    336      (restclient . t)))
    337  '(org-html-validation-link "")
    338  '(org-log-done 'time)
    339  '(org-log-done-with-time t)
    340  '(org-refile-use-outline-path 'file)
    341  '(org-src-window-setup 'other-window)
    342  '(org-startup-folded t)
    343  '(org-startup-indented t)
    344  '(org-startup-truncated nil)
    345  '(package-archive-priorities
    346    '(("gnu" . 3)
    347      ("nongnu" . 2)
    348      ("melpa-stable" . 1)
    349      ("melpa" . 0)))
    350  '(package-archives
    351    '(("gnu" . "https://elpa.gnu.org/packages/")
    352      ("nongnu" . "https://elpa.nongnu.org/nongnu/")
    353      ("melpa-stable" . "https://stable.melpa.org/packages/")
    354      ("melpa" . "https://melpa.org/packages/")))
    355  '(package-selected-packages
    356    '(ox-epub ob-powershell powershell web-mode lexic editorconfig forge elfeed-tube-mpv elfeed-tube cider restclient-jq graphviz-dot-mode consult-eglot jq-mode multiple-cursors ob-restclient restclient vterm 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 geiser-guile geiser org-roam org-contrib org ace-window expand-region consult marginalia uuidgen request diminish which-key))
    357  '(pcomplete-ignore-case t t)
    358  '(pixel-scroll-precision-mode t)
    359  '(read-buffer-completion-ignore-case t)
    360  '(read-file-name-completion-ignore-case t)
    361  '(reb-re-syntax 'string)
    362  '(recentf-max-saved-items 200)
    363  '(recentf-mode t)
    364  '(repeat-mode t)
    365  '(ring-bell-function 'ignore)
    366  '(save-place-mode t)
    367  '(savehist-mode t)
    368  '(scroll-conservatively 100)
    369  '(tab-always-indent 'complete)
    370  '(use-short-answers t)
    371  '(warning-suppress-types '((comp)))
    372  '(which-key-mode t))
    373 (custom-set-faces
    374  ;; custom-set-faces was added by Custom.
    375  ;; If you edit it by hand, you could mess it up, so be careful.
    376  ;; Your init file should contain only one such instance.
    377  ;; If there is more than one, they won't work right.
    378  '(default ((t (:inherit nil :extend nil :stipple nil :background "#ffffff" :foreground "#000000" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 110 :width normal :foundry "    " :family "Go Mono"))))
    379  '(variable-pitch ((t (:family "IBM Plex Serif")))))
    380 
    381 ;; This is the place where I override all customize stuff
    382 
    383 (let ((feeds (expand-file-name "feeds.el" user-emacs-directory)))
    384   (when (file-exists-p feeds)
    385     (load feeds)))
    386 
    387 (customize-set-value
    388  'elfeed-db-directory
    389  (let ((data-dir (expand-file-name "elfeed" lh/dir-data-home)))
    390    (unless (file-exists-p data-dir)
    391      (make-directory data-dir))
    392    data-dir))
    393 
    394 (customize-set-value
    395  'backup-directory-alist
    396  (let ((backup-dir (concat user-emacs-directory "backup")))
    397    (unless (file-exists-p backup-dir)
    398      (make-directory backup-dir t))
    399    `(("." . ,backup-dir))))
    400 
    401 (let* ((dir (expand-file-name "org" lh/dir-documents))
    402        (roam-dir (expand-file-name "notes" dir)))
    403   (unless (file-exists-p dir)
    404     (make-directory dir t))
    405   (unless (file-exists-p roam-dir)
    406     (make-directory roam-dir t))
    407   (customize-set-value
    408    'org-directory
    409    dir)
    410   (customize-set-value
    411    'org-agenda-files
    412    (list dir))
    413   (customize-set-value
    414    'org-roam-directory
    415    roam-dir)
    416   (with-eval-after-load "org"
    417     (setq org-capture-templates
    418           `(("g" "GTD Inbox" entry
    419              (file ,(expand-file-name "inbox.org" dir))
    420              "* %?")))))
    421 
    422 (diminish 'which-key-mode)
    423 (diminish 'aggressive-indent-mode)
    424 (diminish 'editorconfig-mode)
    425 
    426 (let ((path (expand-file-name "private.el" user-emacs-directory)))
    427   (when (file-exists-p path)
    428     (load path)))
    429 
    430 (pdf-loader-install)
    431 
    432 (server-start)