.emacs.d/init.el
2024-09-09 15:24:04 -07:00

1020 lines
32 KiB
EmacsLisp

;;; EMACS init file -*- lexical-binding:t -*-
(eval-and-compile
(defconst my-is-nixos (file-exists-p "/nix")
"Whether or not Emacs is running on NixOS."))
(when my-is-nixos
(setq auth-sources '("/run/agenix/authinfo")))
(require 'cl-lib)
(with-eval-after-load 'package
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/"))
(package-initialize))
(setq use-package-always-ensure (not my-is-nixos)
use-package-always-defer t
use-package-expand-minimally t)
(require 'use-package)
(let ((emacs-tmp-dir (expand-file-name (format "emacs%d" (user-uid))
temporary-file-directory)))
(setq auto-save-file-name-transforms `((".*" ,emacs-tmp-dir t))
auto-save-list-file-prefix emacs-tmp-dir
backup-directory-alist (setq undo-tree-history-directory-alist
`((".*" . ,emacs-tmp-dir)))
org-preview-latex-image-directory (expand-file-name "ltximg" emacs-tmp-dir)))
(setq backup-by-copying t
inhibit-splash-screen t
custom-file (expand-file-name "custom.el" temporary-file-directory))
(defun my-inhibit-hl-line-mode ()
"Disable `gobal-hl-line-mode' for the current buffer."
(setq-local global-hl-line-mode nil))
(use-package f
:demand t)
(use-package dash
:demand t
:hook (emacs-lisp-mode . dash-fontify-mode)
:init
(with-eval-after-load 'info-look
(dash-register-info-lookup)))
(use-package undo-fu
:demand t
:config
(global-unset-key (kbd "C-/"))
(global-unset-key (kbd "C-?"))
(global-set-key (kbd "C-/") #'undo-fu-only-undo)
(global-set-key (kbd "C-?") #'undo-fu-only-redo))
(use-package god-mode
:demand t
:bind
("<escape>" . god-mode-all)
("ESC ESC ESC" . god-mode-all)
("C-S-h" . help-command)
("C-h" . my--god-del)
(:map god-local-mode-map
("i" . god-mode-all)
("<escape>" . my--god-c-g)
("ESC ESC ESC" . keyboard-escape-quit)
("z" . repeat)
("q" . my--god-c-q))
(:map minibuffer-local-map
("<escape>" . abort-minibuffers)
("ESC ESC ESC" . keyboard-escape-quit))
:custom
(god-exempt-major-modes nil)
(god-exempt-predicates (list #'god-exempt-mode-p))
(god-mode-enable-function-key-translations nil)
(god-mode-alist '((nil . "C-")
("g" . "M-")
("m" . "C-M-")))
:config
(defun my--god-c-q ()
(interactive)
(let ((god-local-mode nil))
(if-let* ((buffer-read-only)
(ret (key-binding (read-kbd-macro "q")))
((not (or (eq ret #'self-insert-command) (and (boundp lispy-mode) lispy-mode)))))
(call-interactively ret)
(switch-to-prev-buffer))))
(cl-macrolet ((define-kmacro-wrapper (name key)
`(defun ,name ()
(interactive)
(call-interactively (key-binding (read-kbd-macro ,key))))))
(define-kmacro-wrapper my--god-del "DEL")
(define-kmacro-wrapper my--god-c-g "C-g"))
(with-eval-after-load 'catppuccin-theme
(add-hook 'god-mode-enabled-hook
(lambda ()
(face-spec-set 'cursor `((t (:background ,(catppuccin-get-color 'rosewater)))))
(unless (display-graphic-p)
(send-string-to-terminal "\e[2 q"))))
(add-hook 'god-mode-disabled-hook
(lambda ()
(face-spec-set 'cursor `((t (:background ,(catppuccin-get-color 'mauve)))))
(unless (display-graphic-p)
;; Escape codes for hbar cursor in insert mode
(send-string-to-terminal "\e[4 q")))))
(god-mode))
(use-package multiple-cursors
:bind
("C-S-c" . mc/edit-lines)
("C->" . mc/mark-next-like-this)
("C-<" . mc/mark-previous-like-this)
("C-+" . mc/mark-all-like-this)
("C-|" . mc/mark-pop)
("C-c c" . mc/mark-all-in-region)
("C-c C" . mc/mark-all-in-region-regexp)
("C-c u" . mc/mark-all-like-this-dwim)
("C-c U" . mc/mark-all-dwim)
("C-S-<mouse-1>" . mc/add-cursor-on-click)
:custom
(mc/always-run-for-all t)
:init
;; NOTE: For SOME REASON lispy also defvars the mc cmds list to nil when
;; sourced so they need to be modified twice
(let ((add-cmds (lambda ()
(dolist (f '(god-local-mode
god-mode-all
god-global-mode))
(add-to-list 'mc/cmds-to-run-once f)))))
;; Because multiple-cursors-core is what actually gets autoloaded
(eval-after-load 'multiple-cursors-core add-cmds)
(eval-after-load 'lispy add-cmds)))
(use-package expand-region
:bind ("C-=" . er/expand-region))
(use-package avy
:bind
("C-'" . avy-goto-char)
("C-," . avy-goto-char-2)
("C-\"" . avy-goto-char-timer)
("M-g f" . avy-goto-line)
("M-g w" . avy-goto-word-1)
("M-g e" . avy-goto-word-0)
:custom
(avy-timeout-seconds 0.3))
(use-package lispy
:hook
emacs-lisp-mode
ielm-mode
lisp-mode
scheme-mode
clojure-mode
:config
(add-to-list 'lispy-compat 'god-mode)
(add-to-list 'lispy-compat 'magit-blame-mode)
(when (boundp 'god-local-mode-map)
(push (assoc 'god-local-mode minor-mode-map-alist) minor-mode-map-alist)))
(use-package ace-window
:bind ("C-c w" . ace-window)
:custom
(aw-dispatch-always t)
(aw-scope 'frame)
(aw-keys '(?a ?w ?d ?f ?g ?h ?k ?l))
:config
(with-eval-after-load 'catppuccin-theme
(face-spec-set 'aw-leading-char-face `((t (:foreground
,(catppuccin-get-color 'crust)
:background
,(catppuccin-get-color 'red)
:weight bold))))
(face-spec-set 'aw-background-face `((t (:foreground
,(catppuccin-get-color 'overlay1)))))))
(use-package goggles
:hook prog-mode
:config
(setq-default goggles-pulse t)
(with-eval-after-load 'catppuccin-theme
(let ((new-spec `((t (:background ,(catppuccin-get-color 'surface1))))))
(dolist (f '(goggles-added
goggles-removed
goggles-changed))
(face-spec-set f new-spec))))
(setcar (cdr (assq 'goggles-mode minor-mode-alist)) " O-O"))
(defun my--set-tab-width-2 ()
(setq tab-width 2))
(use-package treesit
:ensure nil
:mode
("\\.ts\\'" . typescript-ts-mode)
("\\.tsx\\'" . tsx-ts-mode)
("\\.rs\\'" . rust-ts-mode)
("\\.ya?ml\\'" . yaml-ts-mode)
("/Dockerfile\\'" . dockerfile-ts-mode)
("\\(/CMakeLists.txt\\|\\.cmake\\)\\'" . cmake-ts-mode)
:hook
(typescript-ts-mode . my--set-tab-width-2)
(tsx-ts-mode . my--set-tab-width-2)
:init
(add-to-list 'major-mode-remap-alist '(sh-mode . bash-ts-mode))
(add-to-list 'major-mode-remap-alist '(css-mode . css-ts-mode))
(add-to-list 'major-mode-remap-alist '(c-mode . c-ts-mode))
(add-to-list 'major-mode-remap-alist '(c++-mode . c++-ts-mode))
(add-to-list 'major-mode-remap-alist '(csharp-mode . csharp-ts-mode))
(add-to-list 'major-mode-remap-alist '(java-mode . java-ts-mode))
(add-to-list 'major-mode-remap-alist '(python-mode . python-ts-mode))
(add-to-list 'major-mode-remap-alist '(ruby-mode . ruby-ts-mode))
(add-to-list 'major-mode-remap-alist '(html-mode . html-ts-mode))
(add-to-list 'major-mode-remap-alist '(js-mode . js-ts-mode))
(add-to-list 'major-mode-remap-alist '(js-json-mode . json-ts-mode))
(add-to-list 'major-mode-remap-alist '(conf-toml-mode . toml-ts-mode))
:config
(unless my-is-nixos
(add-to-list 'treesit-extra-load-path (expand-file-name "tree-sitter-module/dist/"
user-emacs-directory))))
(use-package dtrt-indent
:demand t
:config
(setcar (cdr (assq 'dtrt-indent-mode minor-mode-alist)) " dtrt")
(dtrt-indent-global-mode))
(use-package aggressive-indent
:custom
(aggressive-indent-sit-for-time 0.1)
:hook
emacs-lisp-mode
ielm-mode
lisp-mode
scheme-mode
clojure-mode
nix-mode)
(use-package rainbow-delimiters
:hook prog-mode sly-mrepl-mode racket-repl-mode)
(use-package highlight-indent-guides
:hook prog-mode
:custom
(highlight-indent-guides-auto-enabled nil)
(highlight-indent-guides-method 'character)
(highlight-indent-guides-responsive 'stack))
(use-package which-key
:demand t
:custom
(which-key-idle-delay 0.2)
:config
(with-eval-after-load 'god-mode
(which-key-enable-god-mode-support))
(which-key-mode))
(use-package flymake
:ensure nil
:bind (:map flymake-mode-map
("M-n" . flymake-goto-next-error)
("M-p" . flymake-goto-prev-error)))
(use-package eglot
:ensure nil
:bind (:map eglot-mode-map
("C-c e c" . eglot-code-actions)
("C-c e r" . eglot-rename)
("C-c e f" . eglot-format)
("C-c e s" . eglot-shutdown)
("C-c e S" . eglot-shutdown-all)
("C-c e R" . eglot-reconnect))
:hook
(c-mode . eglot-ensure)
(c-ts-mode . eglot-ensure)
(c++-mode . eglot-ensure)
(c++-ts-mode . eglot-ensure)
(haskell-mode . eglot-ensure)
(java-mode . eglot-ensure)
(java-ts-mode . eglot-ensure)
(js-mode . eglot-ensure)
(js-ts-mode . eglot-ensure)
(lua-mode . eglot-ensure)
(nix-mode . eglot-ensure)
(python-mode . eglot-ensure)
(python-ts-mode . eglot-ensure)
(rust-ts-mode . eglot-ensure)
(typescript-ts-mode . eglot-ensure)
(tsx-ts-mode . eglot-ensure)
:custom
(eglot-events-buffer-size 0)
(eglot-autoshutdown t)
(eglot-confirm-server-initiated-edits nil)
:config
(setq-default eglot-workspace-configuration
'((haskell
(formattingProvider . "floskell")))))
(use-package eglot-booster
:ensure nil
:after eglot
:demand t
:custom
(eglot-booster-no-remote-boost t)
:config
(eglot-booster-mode))
(use-package eglot-java
:hook java-mode java-ts-mode)
(use-package yasnippet
:config
(advice-add #'yas-expand-snippet
:around
(lambda (oldfun &rest r)
(let ((org-src-tab-acts-natively nil))
(apply oldfun r)))
'((name . my--yas-expand-disable-org-tab-native)))
(yas-global-mode))
(use-package yasnippet-snippets)
(use-package consult
:bind
("M-s r" . consult-ripgrep)
("M-s d" . consult-find)
("C-x M-:" . consult-complex-command)
("C-x b" . consult-buffer)
("C-x r b" . consult-bookmark))
(use-package consult-yasnippet
:bind
("C-c s" . consult-yasnippet)
("C-c S" . consult-yasnippet-visit-snippet-file))
(use-package embark
:bind
("C-." . embark-act)
("C-;" . embark-dwim))
(use-package embark-consult)
(use-package orderless
:demand t
:custom
(completion-styles '(orderless basic))
(completion-category-defaults nil)
(completion-category-overrides '((file (styles basic partial-completion)))))
(use-package marginalia
:after vertico
:demand t
:bind (:map minibuffer-local-map ("M-a" . marginalia-cycle))
:config
(marginalia-mode))
(use-package vertico
:demand t
:config
(vertico-mode)
(vertico-mouse-mode))
(use-package corfu
:demand t
:custom
(corfu-auto t)
(corfu-cycle t)
(corfu-preselect-first nil)
(corfu-scroll-margin 3)
(tab-always-indent 'complete)
:config
(add-hook 'minibuffer-setup-hook
(lambda ()
(when (where-is-internal #'completion-at-point
(list (current-local-map)))
(setq-local corfu-echo-display nil
corfu-popupinfo-delay nil)
(corfu-mode))))
(global-corfu-mode))
(use-package cape)
(use-package all-the-icons
:demand t)
(use-package all-the-icons-completion
:after marginalia all-the-icons
:hook (marginalia-mode . all-the-icons-completion-marginalia-setup)
:init
(all-the-icons-completion-mode))
(use-package treemacs)
(use-package treemacs-all-the-icons
:after treemacs
:demand t
:config
(treemacs-load-theme 'all-the-icons))
(use-package doom-modeline
:demand t
:custom
(doom-modeline-continuous-word-count-modes '(markdown-mode gfm-mode org-mode))
(doom-modeline-enable-word-count t)
(doom-modeline-indent-info t)
(doom-modeline-minor-modes t)
(doom-modeline-battery nil)
:config
(doom-modeline-mode))
(use-package minions
:demand t
:config
(minions-mode))
(use-package dirvish
:after dired
:demand t
:custom
(dired-auto-revert-buffer t)
(dirvish-attributes '(all-the-icons))
:config
(dirvish-override-dired-mode))
(use-package persp-mode
:if nil
:bind ("C-c p" . persp-key-map)
:custom
(persp-keymap-prefix nil)
:init
(when (daemonp)
(require 'persp-mode))
:config
(with-eval-after-load 'consult
(consult-customize consult--source-buffer :hidden t :default nil)
(add-to-list 'consult-buffer-sources
(list :name "Perspective"
:narrow ?s
:category 'buffer
:state #'consult--buffer-state
:history 'buffer-name-history
:default t
:items (lambda ()
(consult--buffer-query :sort 'visibility
:predicate (lambda (buf)
(memq buf (persp-buffer-list)))
:as #'buffer-name)))))
(persp-mode))
(use-package alert
:ensure nil
:custom
(alert-default-style 'libnotify)
(alert-libnotify-command (expand-file-name "scripts/emacs-hyprland-notify"
user-emacs-directory)))
(use-package pdf-tools
:mode ("\\.pdf\\'" . pdf-view-mode)
:bind (:map pdf-view-mode-map ("/" . #'isearch-forward))
:config
(pdf-tools-install))
(defun my-double-space-sentence ()
(setq-local sentence-end-double-space t))
(use-package engrave-faces)
(use-package org
:hook
(org-mode . auto-fill-mode)
(org-mode . my-inhibit-hl-line-mode)
(org-mode . my-double-space-sentence)
:custom
(org-startup-with-inline-images t)
(org-special-ctrl-a/e t)
(org-insert-heading-respect-content t)
(org-list-allow-alphabetical t)
(org-hide-emphasis-markers t)
(org-pretty-entities t)
(org-babel-load-languages '((emacs-lisp . t)
(ruby . t)
(python . t)
(shell . t)
(C . t)))
(org-agenda-files '("~/Agenda"))
;; NixOS minimal LaTeX setup
(org-latex-compiler "lualatex")
(org-preview-latex-default-process 'dvisvgm)
(org-latex-src-block-backend 'engraved)
:config
(setq org-format-latex-options (plist-put org-format-latex-options :scale 1.1)
org-modules (append '(org-tempo org-habit) org-modules))
(with-eval-after-load 'catppuccin-theme
(face-spec-set 'org-block `((t (:foreground ,(catppuccin-get-color 'text)))))))
(use-package org-alert
:init
(when (daemonp)
(run-with-idle-timer 10 nil #'require 'org-alert))
:config
(setq org-alert-notification-title "org-alert"
org-alert-notify-cutoff 30)
(org-alert-enable))
(use-package org-modern
:hook
org-mode
(org-agenda-finalize . org-modern-agenda)
:config
(with-eval-after-load 'catppuccin-theme
(face-spec-set 'org-modern-done `((t (:foreground
,(catppuccin-get-color 'text)
:background
,(catppuccin-get-color 'surface0)))))
(face-spec-set 'org-modern-date-inactive `((t (:foreground
,(catppuccin-get-color 'subtext0)
:background
,(catppuccin-get-color 'surface0)))))
(face-spec-set 'org-modern-horizontal-rule `((t (:strike-through
,(catppuccin-get-color 'overlay1)))))
(face-spec-set 'org-modern-tag `((t (:foreground
,(catppuccin-get-color 'base)
:background
,(catppuccin-get-color 'sapphire)))))
(face-spec-set 'org-modern-time-active `((t (:foreground
,(catppuccin-get-color 'base)
:background
,(catppuccin-get-color 'overlay2)))))
(face-spec-set 'org-modern-time-inactive `((t (:foreground
,(catppuccin-get-color 'base)
:background
,(catppuccin-get-color 'surface0)))))))
(use-package org-modern-indent
:ensure nil
:hook org-modern-mode)
(use-package djvu)
(use-package nov
:mode ("\\.epub\\'" . nov-mode))
(use-package org-pdftools
:hook (org-mode . org-pdftools-setup-link))
(use-package editorconfig
:demand t
:config
(editorconfig-mode)
(setcar (cdr (assq 'editorconfig-mode minor-mode-alist)) " EdConf"))
(use-package envrc
:bind ("C-c v" . envrc-command-map)
:hook (after-init . envrc-global-mode))
(use-package sly
:custom
(sly-symbol-completion-mode nil)
:config
(setq inferior-lisp-program "sbcl")
(defun my--sly-add-project-root-to-asdf (old-init)
(let ((dir (if-let* ((proj (project-current))
(root (project-root proj)))
root
default-directory)))
(if (directory-files dir nil "\\.asd\\'" t 1)
(let ((old-init-list (read old-init)))
(setf (cddadr old-init-list)
(cons `(push (pathname ,(sly-to-lisp-filename dir))
(symbol-value
(read-from-string "asdf:*central-registry*")))
(cddadr old-init-list)))
(format "%S\n\n" old-init-list))
old-init)))
(advice-add #'sly-init-using-asdf :filter-return #'my--sly-add-project-root-to-asdf)
(sly-setup))
(use-package sly-asdf)
(use-package sly-named-readtables)
(use-package racket-mode
:hook (racket-mode . racket-xp-mode))
(use-package haskell-mode
:hook (haskell-mode . interactive-haskell-mode)
:custom
(haskell-process-show-debug-tips nil))
(use-package lua-mode
:custom
(lua-indent-level 4)
(lua-indent-nested-block-content-align nil)
(lua-indent-close-paren-align nil))
(use-package nix-mode)
(use-package markdown-mode
:mode ("README\\.md\\'" . gfm-mode)
:custom
(markdown-command '("pandoc" "--from=markdown" "--to=html5")))
(use-package csv-mode)
(use-package meson-mode)
(use-package jinx
:hook text-mode)
(use-package minimap
:custom-face
(minimap-active-region-background ((t (:background unspecified :inherit hl-line))))
:hook (minimap-sb-mode . turn-on-solaire-mode))
(use-package magit
:hook (git-commit-setup . git-commit-turn-on-auto-fill))
(use-package forge
:after magit
:demand t)
(use-package tramp
:custom
(remote-file-name-inhibit-cache nil)
(tramp-verbose 1)
:config
(setq vc-ignore-dir-regexp (format "%s\\|%s"
vc-ignore-dir-regexp
tramp-file-name-regexp)))
(use-package eat
:bind
("C-c t" . eat)
(:map eat-mode-map
("<escape>" . eat-self-input))
:hook (eat-mode . my-inhibit-hl-line-mode)
:config
(with-eval-after-load 'god-mode
(add-to-list 'god-exempt-major-modes 'eat-mode)))
(use-package circe
:hook (circe-channel-mode . enable-lui-autopaste)
:custom
(circe-default-nick "eriedaberrie")
(circe-default-user "eriedaberrie")
(circe-default-realname "eriedaberrie")
(circe-format-self-say ">>> {body}")
(lui-time-stamp-position 'right-margin)
(lui-fill-type nil)
(lui-time-stamp-format "%T")
:config
(--when-let (nth 0 (auth-source-search :max 1
:require '(:user :secret)
:host "irc.libera.chat"
:port 6697))
(let ((user (plist-get it :user))
(secret (plist-get it :secret)))
(setq circe-network-options
`(("Libera Chat"
:tls t
:nick ,user
:sasl-username ,user
:sasl-password ,(if (functionp secret)
(funcall secret)
secret)
:channels ("#emacs" "#nixos" "#lisp" "#commonlisp"))))))
(add-hook 'lui-mode-hook
(lambda ()
(visual-line-mode)
(setq-local fringes-outside-margins t
right-margin-width 8
wrap-prefix " ")
(setcdr (assoc 'continuation fringe-indicator-alist) nil))))
(use-package circe-notifications
:hook (circe-server-connected . enable-circe-notifications))
(use-package mpv)
(use-package lingva
:custom
(lingva-instance "lingva.garudalinux.org"))
(use-package mastodon
:custom
(mastodon-instance-url "https://fosstodon.org")
(mastodon-active-user "eriedaberrie")
(mastodon-toot-timestamp-format "%F %-I:%M %p"))
(use-package elfeed
:custom
(elfeed-feeds '(("https://archlinux.org/feeds/news/" arch-linux)
("https://nixos.org/blog/announcements-rss.xml" nixos))))
(use-package xkcd)
(use-package page-break-lines
:hook
emacs-lisp-mode
lisp-mode
scheme-mode
compilation-mode
outline-mode
help-mode)
(use-package hl-todo
:hook prog-mode)
(use-package gruvbox-theme)
(use-package catppuccin-theme
:demand t
:custom-face
(line-number-current-line ((t (:inherit hl-line))))
:custom
(catppuccin-flavor 'mocha)
(catppuccin-highlight-matches t)
(catppuccin-italic-comments t)
(catppuccin-italic-blockquotes t)
(catppuccin-italic-variables t))
(defun my-load-theme-with-solaire ()
(load-theme 'catppuccin t)
(catppuccin-reload)
(face-spec-set 'font-lock-variable-name-face `((t (:foreground
,(catppuccin-get-color 'flamingo)))))
(solaire-global-mode)
(when (daemonp)
(remove-hook 'server-after-make-frame-hook #'my-load-theme-with-solaire)))
(use-package solaire-mode
:demand t
:custom
(solaire-mode-real-buffer-fn (lambda ()
(and (solaire-mode-real-buffer-p)
(or (custom-theme-enabled-p 'gruvbox)
(not (memq 'minimap-sb-mode
local-minor-modes))))))
:config
(if (daemonp)
(add-hook 'server-after-make-frame-hook #'my-load-theme-with-solaire)
(my-load-theme-with-solaire)))
(use-package with-editor
:bind
([remap async-shell-command] . with-editor-async-shell-command)
([remap shell-command] . with-editor-shell-command)
:hook
(shell-mode . with-editor-export-editor)
(eshell-mode . with-editor-export-editor)
(term-exec . with-editor-export-editor))
(use-package nyan-mode
:custom
(nyan-animate-nyancat t)
(nyan-wavy-trail t))
(use-package smtpmail
:ensure nil
:custom
(smtpmail-smtp-service 587)
(smtpmail-stream-type 'starttls)
(smtpmail-default-smtp-server "smtp.gmail.com")
(message-send-mail-function #'smtpmail-send-it)
(message-citation-line-function #'message-insert-formatted-citation-line)
(message-kill-buffer-on-exit t))
(use-package mu4e
:if my-is-nixos
:ensure nil
:bind
("C-c m m" . mu4e)
("C-c m c" . mu4e-compose-new)
("C-c m u" . mu4e-update-mail-and-index)
:hook
(mu4e-view-mode . my-inhibit-hl-line-mode)
(message-mode . my-double-space-sentence)
:custom
(mail-user-agent 'mu4e-user-agent)
(mu4e-get-mail-command "mbsync -a")
(mu4e-sent-messages-behavior 'delete)
(mu4e-change-filenames-when-moving t)
(mu4e-view-show-images t)
(mu4e-use-fancy-chars t)
(mu4e-attachment-dir "~/Downloads")
(mu4e-context-policy 'ask)
(mu4e-compose-context-policy 'ask-if-none)
(mu4e-confirm-quit nil)
(mu4e-completing-read-function #'completing-read)
:init
(let ((age-file "/run/agenix/email.json"))
(when (file-exists-p age-file)
(defvar my--agenix-email-json-data
(with-temp-buffer
(insert-file-contents age-file)
(json-parse-buffer :object-type 'alist)))
(pcase-let ((`((address . ,address) (name . ,name) ,_)
(alist-get 'personal my--agenix-email-json-data)))
(setq user-mail-address address
user-full-name name))))
:config
(when (boundp 'my--agenix-email-json-data)
(setq mu4e-contexts
(--map (pcase-let ((`(,type (address . ,address) (name . ,name) ,_) it))
(make-mu4e-context
:name (symbol-name type)
:enter-func (lambda ()
(mu4e-message (format "Entering \"%s\" context"
type)))
:leave-func (lambda ()
(mu4e-message (format "Leaving \"%s\" context"
type)))
:match-func (lambda (msg)
(when msg
(mu4e-message-contact-field-matches
msg
:to address)))
:vars (cl-labels ((folder-name (folder-type)
(format "/%s/[Gmail]/%s" type folder-type)))
`((user-mail-address . ,address)
(user-full-name . ,name)
(mu4e-drafts-folder . ,(folder-name "Drafts"))
(mu4e-sent-folder . ,(folder-name "Sent Mail"))
(mu4e-trash-folder . ,(folder-name "Trash"))
(smtpmail-smtp-server . "smtp.gmail.com")
(smtpmail-smtp-user . ,address)))))
my--agenix-email-json-data)))
(when (fboundp 'imagemagick-register-types)
(imagemagick-register-types)))
(use-package org-msg
:after message
:demand t
:custom
(org-msg-convert-citation t)
(org-msg-greeting-fmt "\nHi%s,\n\n"))
(use-package emacs-everywhere
:custom
(emacs-everywhere-app-info-function
(lambda ()
(let* ((string-data (emacs-everywhere-call "hyprctl" "-j" "activewindow"))
(window-data (json-parse-string string-data
:object-type 'plist
:array-type 'list
:null-object nil
:false-object nil))
(window-id (plist-get window-data :address))
(app-id (plist-get window-data :class))
(window-title (plist-get window-data :title))
(window-geometry (append (plist-get window-data :at)
(plist-get window-data :size))))
(make-emacs-everywhere-app
:id window-id
:class app-id
:title window-title
:geometry window-geometry))))
(emacs-everywhere-window-focus-command '("hyprctl" "dispatch" "focuswindow" "address:%w"))
:config
(dolist (f '((alpha-background . 1.0) (width . 120) (height . 20)))
(add-to-list 'emacs-everywhere-frame-parameters f)))
(use-package prettify-symbols
:ensure nil
:hook prog-mode org-mode
:custom
(prettify-symbols-unprettify-at-point t))
(use-package electric-pair-mode
:ensure nil
:hook
(prog-mode . electric-pair-local-mode)
(eval-expression-minibuffer-setup . electric-pair-local-mode)
(sly-mrepl-mode . electric-pair-local-mode)
(racket-repl-mode . electric-pair-local-mode))
(use-package ffap
:ensure nil
:demand t
:config
(ffap-bindings))
(use-package eldoc
:ensure nil
:custom
(eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly))
(use-package ibuffer
:ensure nil
:bind ("C-x C-b" . ibuffer))
(use-package info
:ensure nil
:hook (Info-mode . my-inhibit-hl-line-mode))
(use-package tool-bar
:ensure nil
:config
(tool-bar-mode 0))
(use-package menu-bar
:ensure nil
:config
(menu-bar-mode 0))
(use-package scroll-bar
:ensure nil
:config
(scroll-bar-mode 0))
(setq pixel-scroll-precision-large-scroll-height 40
fast-but-imprecise-scrolling t)
(pixel-scroll-precision-mode)
(setcar mouse-wheel-scroll-amount 3)
(setq server-client-instructions nil
scroll-step 1
scroll-margin 8
scroll-conservatively 9999
python-indent-guess-indent-offset nil
read-file-name-completion-ignore-case t
read-buffer-completion-ignore-case t
completion-ignore-case t
sentence-end-double-space nil
custom-safe-themes t
x-stretch-cursor t)
(setq-default c-basic-offset 4
c-ts-mode-indent-offset 4
json-ts-mode-indent-offset 4
sgml-basic-offset 4
tab-width 4
fill-column 78)
;; Because python-mode sets tab-width to 8 for some reason
(add-hook 'python-mode-hook (lambda () (setq tab-width 4)))
(column-number-mode)
(size-indication-mode)
(global-hl-line-mode)
(defun my-relative-linenum (&optional toggle)
"Simply enables relative line numbers."
(interactive "p")
(setq display-line-numbers (if (and toggle display-line-numbers) nil 'relative)))
(dolist (hook '(prog-mode-hook
conf-mode-hook))
(add-hook hook #'my-relative-linenum))
(defun my-use-spaces-for-indent ()
"Simply turn off `indent-tabs-mode'."
(setq indent-tabs-mode nil))
(dolist (hook '(emacs-lisp-mode-hook
lisp-mode-hook
scheme-mode-hook
clojure-mode-hook))
(add-hook hook #'my-use-spaces-for-indent))
(add-hook 'text-mode-hook #'word-wrap-whitespace-mode)
(add-hook 'text-mode-hook #'visual-line-mode)
(defun scroll-down-3 ()
"Scroll down by 3."
(interactive)
(scroll-down 3))
(defun scroll-up-3 ()
"Scroll up by 3."
(interactive)
(scroll-up 3))
(defun my-frame-make-detect-term (&optional frame)
"Check when FRAME are made in order to make terminal-only configurations."
(unless (display-graphic-p frame)
(xterm-mouse-mode)
(global-set-key (kbd "<mouse-4>") #'scroll-down-3)
(global-set-key (kbd "<mouse-5>") #'scroll-up-3)
(remove-hook 'after-make-frame-functions #'my-frame-make-detect-term)))
(if (daemonp)
(add-to-list 'after-make-frame-functions #'my-frame-make-detect-term)
(my-frame-make-detect-term))
(defun my-sudo-edit ()
"Edit current file as root."
(interactive)
(unless (and buffer-file-name
(file-writable-p buffer-file-name))
(find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name))))
(setq auto-mode-alist
(append '(("\\.yuck\\'" . lisp-mode)
("/flake\\.lock\\'" . js-json-mode))
auto-mode-alist
'(("/qutebrowser-editor-" . text-mode))))
(when (daemonp)
(with-current-buffer "*scratch*"
(cd "~/")))
(defvar my-ac-previous-status t
"Whether connected to AC during last check.")
(require 'battery)
(defun my-bat-check ()
"Check if battery status has changed.
Used to toggle `goggles-pulse', `pixel-scroll-precision-mode', and `nyan-mode'."
(let ((ac-status (not (string=
(cdr (assq ?B (funcall battery-status-function)))
"discharging"))))
(unless (eq ac-status my-ac-previous-status)
(setq my-ac-previous-status ac-status)
(when (boundp 'goggles-pulse)
(setq goggles-pulse ac-status))
(when nyan-mode
(if ac-status
(nyan-start-animation)
(nyan-stop-animation)))
(setq nyan-animate-nyancat ac-status
nyan-wavy-trail ac-status)
(pixel-scroll-precision-mode (if ac-status 1 0)))))
(when battery-status-function
(run-with-timer 0 30 #'my-bat-check))