summaryrefslogtreecommitdiff
path: root/config
diff options
context:
space:
mode:
Diffstat (limited to 'config')
-rw-r--r--config/emacs/init.el982
-rw-r--r--config/emacs/site-lisp/my-builtins.el200
-rw-r--r--config/emacs/site-lisp/my-defines.el363
-rw-r--r--config/emacs/site-lisp/my-packages.el394
4 files changed, 961 insertions, 978 deletions
diff --git a/config/emacs/init.el b/config/emacs/init.el
index 932bd29..d01bf5b 100644
--- a/config/emacs/init.el
+++ b/config/emacs/init.el
@@ -1,20 +1,6 @@
;;; init.el --- tmu init file -*- lexical-binding: t; -*-
-
-;;; Commentary:
-;;; This file is organized with
-;;;
-;;; Stuff that needs to be at the start (package init, some fast
-;;; startup stuff, etc)
-;;; then my custom functions and variables
-;;; then builtin customization
-;;; then external packages
-;;; then other files that contain config I don't need all the time
-;;; then things Emacs sets programtically.
-
;;; Code:
-;;; Init header:
-
(progn ; performance stuff:
;; delay initial gc until after loading init if possible
(setq gc-cons-threshold most-positive-fixnum)
@@ -33,977 +19,17 @@
:config
(add-hook 'after-init-hook 'benchmark-init/deactivate))
-;;; Custom definitions, with prefix "my/"
-
-(defvar surround-keys '("(" "{" "[" "$" "\"" "'"))
-(defun my/wrap-pair ()
- "Ensure the region is active and then \"insert-pair\"."
- (interactive)
- (activate-mark)
- (insert-pair))
-(eval
- `(define-keymap
- :full nil
- :name "Surround"
- :prefix 'surround-prefix
- ,@(mapcan
- (lambda (key) (list key ''my/wrap-pair))
- surround-keys
- )))
-
-(defun my/toggle-frame-transparency ()
- "Toggle transparency."
- (interactive)
- (let ((alpha-transparency 90))
- (if (eq alpha-transparency (frame-parameter nil 'alpha-background))
- (set-frame-parameter nil 'alpha-background 100)
- (set-frame-parameter nil 'alpha-background alpha-transparency))))
-
-(defvar my/prog-cleanup-excluded-modes
- '(makefile-gmake-mode makefile-mode makefile-imake-mode
- makefile-makepp-mode makefile-bsdmake-mode
- makefile-automake-mode
- python-mode
- fundamental-mode)
- "Major modes for which \"my/clean-prog-file\" should not be run before save.")
-
-(defvar my/prog-cleanup-want-tabs-modes
- '(makefile-gmake-mode makefile-mode makefile-imake-mode
- makefile-makepp-mode makefile-bsdmake-mode makefile-automake-mode)
- "Major modes that need tabs instead of spaces.
-\"my/clean-prog-file\" should convert spaces to tabs instead of tabs to spaces.")
-
-(defvar my/prog-cleanup-indent-max-lines 500
- "Skip reindenting the buffer if it is longer than this many lines.
-Nil for no limit.")
-
-(define-minor-mode my/global-prog-clean-mode
- "Do auto formating on save in prog mode buffers."
- :global t
- (if my/global-prog-clean-mode
- (progn ;enable
- (add-hook 'before-save-hook 'my/clean-prog-file))
- (progn ;disable
- (remove-hook 'before-save-hook 'my/clean-prog-file))))
-(my/global-prog-clean-mode 1)
-
-(defun my/clean-prog-file (&optional buffer)
- "Perform whitespace cleanup and some normalization on `buffer'.
-Defaults to the current BUFFER. Converts tabs to spaces unless the
-major mode is in `my/prog-cleanup-want-tabs-modes', otherwise do the
-reverse. Delete trailing whitespace."
- (unless buffer (setq buffer (current-buffer)))
- (with-current-buffer buffer
- (when (and my/global-prog-clean-mode
- (not (member major-mode my/prog-cleanup-excluded-modes))
- (derived-mode-p '(prog-mode))
- (cond
- ((and (functionp 'clang-format-buffer)
- ; safety valve for undef'd
- (derived-mode-p '(c-mode c++-mode)))
- (clang-format-buffer))
- (t
- (when (and my/prog-cleanup-indent-max-lines
- (< (car (buffer-line-statistics buffer))
- my/prog-cleanup-indent-max-lines))
- (indent-region (point-min) (point-max)))))
- (if (member major-mode my/prog-cleanup-want-tabs-modes)
- (tabify (point-min) (point-max))
- (untabify (point-min) (point-max)))
- (delete-trailing-whitespace)))))
-
-(defun my/prog-buffer-setup ()
- "Do setup in for code buffers."
- ;; (superword-mode 1)
- ;; (modify-syntax-entry ?_ "w")
- ;; (hs-minor-mode 1)
- (display-fill-column-indicator-mode 1)
- (smerge-mode 1)
- (ignore-errors
- (when (and (derived-mode-p '(c-mode c++-mode))
- (> (car (buffer-line-statistics)) 0))
- (c-guess))))
-(add-hook 'prog-mode-hook 'my/prog-buffer-setup)
-
-(defun my/wrap-region-paren ()
- "Wraps the region in parens. Similar to pressing ( with the region active."
- (interactive)
- (let ((beg (region-beginning))
- (end (region-end)))
- (save-excursion
- (goto-char beg)
- (insert "(")
- (goto-char (+ end 1))
- (insert ")"))))
-
-(defun my/zap-whitespace ()
- "Zaps (deletes) the whitespace around the point in both directions."
- (interactive)
- (push-mark)
- (skip-chars-backward " \t\n")
- (push-mark)
- (skip-chars-forward " \t\n")
- (delete-region (mark) (point))
- (pop-mark)
- (goto-char (mark))
- (pop-mark))
-
-(defun my/wrap-sexp (&optional arg)
- "Wraps the following sexp in a pair of parens.
-Places point inside the new pair, pushing the mark before the new pair.
-With prefix ARG do ARG number sexps if given, including backwards."
- (interactive "p")
- (message "%s" arg)
- (if arg
- (progn
- (push-mark)
- (insert-pair arg ?\( ?\)))
- (insert-pair 1 ?\( ?\))))
-
-(defun my/toggle-window-other-reachability ()
- "Toggle whether this window can be selected by `other-window'."
- (interactive)
- (let* ((win (get-buffer-window (current-buffer)))
- (current (window-parameter win 'no-other-window)))
- (set-window-parameter win 'no-other-window (not current))
- (force-mode-line-update)))
-;; small hack to make other window reachability visible like window dedication
-(advice-add 'mode-line-window-control :around
- (lambda (f) (concat (funcall f)
- (if (window-parameter nil 'no-other-window) "o" "")))
- '(:name "other-window-indicator"))
-
-;; TODO find a bind for this
-(defun my/open-window-by-buffer (buffer)
- "Move focus to an extant window by the buffer it contains.
-If no such window exists, switch to BUFFER in the current window."
- (interactive "bBuffer: ")
- (let ((win (get-buffer-window buffer t)))
- (if win
- (select-window win)
- (switch-to-buffer buffer))))
-
-(defun my/shorten-path (path)
- "Shorten string PATH. Initialize all but the last path component."
- (let* ((components (split-string path "/"))
- (last-component (-last (lambda (s) (not (string-empty-p s))) components))
- (shortened-components
- (mapcar (lambda (comp)
- (if (or (string-equal comp last-component) (string-empty-p comp))
- comp
- (substring comp 0 1)))
- components)))
- (mapconcat 'identity shortened-components "/")))
-
-(defun my/swap-other-window-buffer ()
- "Exchange buffer contents with the next window.
-Tries to switch the buffer contents of the current window and the next
-in the cyclic ordering. Doesn't consider windows that are dedicated."
- (interactive)
- (let* ((cw (get-mru-window nil nil nil t))
- (cb (window-buffer cw))
- (ow (next-window))
- (ob (window-buffer ow)))
- (unless (window-dedicated-p cw)
- (while (window-dedicated-p ow)
- (setq ow (next-window ow)
- ob (window-buffer ow)))
- (unless (eq cw ow)
- (progn
- (with-selected-window ow
- (switch-to-buffer cb))
- (with-selected-window cw
- (switch-to-buffer ob)))))))
-
-(defun my/activate-mark ()
- "Activate the region a la `C-SPC C-SPC', but don't move the point.
-Useful in combination with `query-replace' for acting on the region."
- (interactive)
- (if (region-active-p)
- (deactivate-mark)
- (activate-mark)))
-
-(defun my/c-x-n-to-m-n (&optional keymap)
- "Copy bindings from C-x [n] to M-[n] in KEYMAP, defaulting to the global
-keymap."
- (unless keymap (setq keymap global-map))
- (mapc (lambda (n)
- (let* ((from (concat "C-x " (format "%d" n)))
- (to (concat "M-" (format "%d" n)))
- (bind (keymap-lookup keymap from)))
- (keymap-set keymap to bind)))
- '(0 1 2 3 4 5 6 7 8 9)))
-(my/c-x-n-to-m-n)
-
-(defun my/keymap-keys (map)
- "Return a list of all key sequences in a keymap MAP recursively."
- (mapcan (lambda (c)
- (let ((ks (car c))
- (km (cdr c))
- (acc nil))
- (map-keymap (lambda (key bind)
- (let ((kss (vconcat ks (vector key))))
- (when (commandp bind)
- (push kss acc))))
- km)
- acc))
- (accessible-keymaps map)))
-
-(defun my/eshell (&optional arg)
- "Create a new eshell or switch to an existing one.
-With ARG, make a new shell. If the current buffer is an eshell, switch
-back to the previous selected buffer."
- (interactive "P")
- (if (eq major-mode 'eshell-mode)
- (switch-to-prev-buffer)
- (eshell arg)))
-
-(defun my/eshell-clear-or-center (&optional clear)
- "Either clear the screen or recenter display depending on point location."
- (interactive "P")
- (cond
- (clear (eshell/clear clear))
- ((>= (point) eshell-last-output-end) ;; at the input line
- (eshell/clear clear))
- (t ;; in scroll back somewhere
- (recenter-top-bottom))))
-
-(defun my/vc-on-root (&optional arg)
- "Open a vc dir buffer at the project root.
-With ARG, open a Dired buffer instead."
- (interactive "P")
- (let ((dir (project-root (project-current t))))
- (if arg
- (dired dir)
- (vc-dir dir))))
-
-(defun my/shell-at-root ()
- "Execute an async shell commmand at the root of the current project."
- (interactive)
- (let ((prior-cwd default-directory)
- (want-quit inhibit-quit))
- (setq inhibit-quit t)
- (with-local-quit
- (setq default-directory (project-root (project-current)))
- (call-interactively 'async-shell-command))
- (setq default-directory prior-cwd
- inhibit-quit want-quit)))
-
-(defun my/kill-buffer (&optional arg)
- "Kill the current buffer. With ARG kill the window as well."
- (interactive "P")
- (if arg
- (kill-buffer-and-window)
- (kill-buffer)))
-
-(defvar my/layout-pair (cons nil nil)
- "Cons pair of window configurations.")
-(add-hook 'after-init-hook
- (lambda ()
- (setq my/layout-pair (cons (current-window-configuration)
- (current-window-configuration)))))
-(defun my/layout-swap (&optional arg)
- "Swap between the two saved window configurations.
-With ARG, don't save the current layout."
- (interactive "p")
- (let ((left (car my/layout-pair))
- (right (cdr my/layout-pair))
- (cwc (current-window-configuration)))
- (cond
- ((>= arg 16) (setq my/layout-pair (cons cwc cwc)))
- ((eq (selected-frame) (window-configuration-frame right))
- (unless (>= arg 4) (setq left cwc))
- (set-window-configuration right t t)
- (setq my/layout-pair (cons right left)))
- (t (message "Quick layout swap only works with same frame!")))))
-
-(defun my/display-lines-advice (func &rest r)
- "Around advice that temporarily shows line numbers."
- (let ((want-quit inhibit-quit))
- (setq inhibit-quit t)
- (display-line-numbers-mode 1)
- (force-window-update)
- (with-local-quit
- (call-interactively func))
- (display-line-numbers-mode -1)
- (force-window-update)
- (setq inhibit-quit want-quit)))
-
-(progn ; my global keybinds
- (define-minor-mode my/keys-mode
- "Minor mode collecting global keybinds"
- :global t
- :keymap (make-sparse-keymap)
-
- (if my/keys-mode
- (repeat-mode 1)
- (repeat-mode -1)))
- (require 'eshell)
- (require 'em-prompt)
- (put 'other-window 'repeat-map nil)
- (put 'other-window-backward 'repeat-map nil)
- (put 'eshell-previous-prompt 'repeat-map nil)
- (put 'eshell-next-prompt 'repeat-map nil)
-
- ;; The keymaps in `emulation-mode-map-alists' take precedence over
- ;; `minor-mode-map-alist'
- (add-to-list 'emulation-mode-map-alists
- '((my/keys-mode . my/keys-keymap)))
-
- (keymap-set my/keys-mode-map "C-x -" 'my/swap-other-window-buffer)
- (keymap-set my/keys-mode-map "C-x w o" 'my/toggle-window-other-reachability)
- (keymap-set my/keys-mode-map "C-x w r r" 'window-layout-rotate-clockwise)
- (keymap-set my/keys-mode-map "C-x w r R" 'window-layout-rotate-anticlockwise)
- (keymap-set window-layout-rotate-repeat-map "r" 'window-layout-rotate-clockwise)
- (keymap-set window-layout-rotate-repeat-map "R" 'window-layout-rotate-anticlockwise)
-
- (keymap-set my/keys-mode-map "C-M-z" 'my/wrap-sexp)
-
- (keymap-set my/keys-mode-map "C-c R" 'raise-sexp)
- (keymap-set my/keys-mode-map "C-c r" 'delete-pair)
-
- (keymap-set my/keys-mode-map "M-s g" 'grep)
- (keymap-set my/keys-mode-map "M-s r" 'query-replace-regexp)
- (keymap-set my/keys-mode-map "M-s a" 'align-regexp)
-
- (keymap-set my/keys-mode-map "M-w" 'copy-region-as-kill)
- (keymap-set my/keys-mode-map "M-(" 'my/wrap-region-paren)
- (keymap-set my/keys-mode-map "M-z" 'my/zap-whitespace)
- (keymap-set my/keys-mode-map "M-o" 'other-window)
- (keymap-set my/keys-mode-map "M-O" 'other-window-backward)
- (keymap-set my/keys-mode-map "M-RET" 'my/eshell)
- (keymap-set my/keys-mode-map "M-C" 'calc)
- (keymap-set my/keys-mode-map "M-K" 'my/kill-buffer)
- (keymap-set my/keys-mode-map "M-D" 'my/vc-on-root)
- (keymap-set my/keys-mode-map "M-Q" 'auto-fill-mode)
- (keymap-set my/keys-mode-map "M-A" 'beginning-of-line-text)
- (keymap-set my/keys-mode-map "M-R" 'my/layout-swap)
- (keymap-set my/keys-mode-map "M-W" 'switch-to-buffer)
- (keymap-set my/keys-mode-map "M-N" 'man)
- (keymap-set my/keys-mode-map "M-*" 'my/shell-at-root)
- (keymap-set my/keys-mode-map "M-S" 'surround-prefix)
- (keymap-set my/keys-mode-map "M-J" 'my/activate-mark)
-
- (my/keys-mode 1))
-
-(progn ; mode for log files
- (define-derived-mode
- generic-log-mode
- fundamental-mode
- "Log"
- "Major mode for following log files."
- (setq-local auto-revert-verbose nil)
- (auto-revert-tail-mode 1))
- (add-to-list 'auto-mode-alist
- '("\\.log\\'" . generic-log-mode)))
-
-;;; Builtin config:
-
-(use-package server ; allow emacsclient
- :demand t
- :config
- (unless (server-running-p) (server-start)))
-
-(use-package proced ; process editor
- :commands (proced)
- :config
- (setq-default proced-auto-update-flag t)
- (setq-default proced-auto-update-interval 1))
-
-(use-package dabbrev ; dynamic abbreviations
- :demand t
- :config
- (add-to-list 'dabbrev-ignored-buffer-modes 'exwm-mode)
- (add-to-list 'dabbrev-ignored-buffer-modes 'pdf-view-mode)
- (add-to-list 'dabbrev-ignored-buffer-modes 'tags-table-mode)
- (add-to-list 'dabbrev-ignored-buffer-modes 'doc-view-mode))
-
-(progn ; dired directory editor
- (require 'dired)
- (defun dired-do-find-marked-files ()
- (interactive)
- (seq-do 'find-file (dired-get-marked-files)))
- (define-key dired-mode-map (kbd "C-o") 'dired-display-file)
- (define-key dired-mode-map (kbd "F") 'dired-do-find-marked-files))
-
-(use-package ibuffer ; give a nice list of buffers with extra info
- :commands (ibuffer)
- :custom
- (ibuffer-formats
- '((mark modified read-only " "
- (name 50 50 :left :elide) ; was originally 18
- " "
- (size 9 -1 :right)
- " "
- (mode 16 16 :left :elide)
- " " filename-and-process)
- (mark " "
- (name 16 -1)
- " " filename)))
- :bind
- ("C-x C-b" . ibuffer))
-
-(progn ; isearch search in buffer
- ;; swap basic and regex binds
- (keymap-set global-map "C-s" 'isearch-forward-regexp)
- (keymap-set global-map "C-r" 'isearch-backward-regexp)
- (keymap-set global-map "C-M-s" 'isearch-forward)
- (keymap-set global-map "C-M-r" 'isearch-backward))
-
-(use-package eshell ; emacs shell
- :demand t
- :config
- (use-package esh-help)
- (require 'em-hist)
- (require 'em-term)
- (setup-esh-help-eldoc)
- :bind (:map eshell-mode-map
- ("C-l" . my/eshell-clear-or-center)) ; todo make smarter with centering
- :hook (eshell-mode . eldoc-mode))
-
-(use-package ediff ; emacs interactive diff
- :custom
- (ediff-window-setup-function 'ediff-setup-windows-plain))
-
-(progn ; comint, doesn't play with use-package
- (require 'comint)
- (setq-default comint-scroll-to-bottom-on-input t)
- (setq-default comint-scroll-to-bottom-on-output t)
- (setq-default comint-buffer-maximum-size 1048576)
- (add-to-list 'comint-output-filter-functions #'comint-truncate-buffer)
- (add-to-list 'comint-output-filter-functions #'ansi-color-process-output))
-
-(use-package tramp ; remote access for files
- :demand t
- :custom
- (tramp-allow-unsafe-temporary-files t))
-
-(use-package asm-mode ; asm comments and tags generation
- :demand t
- :custom
- (asm-comment-char ?#) ; prefer # over ; for asm comments
- :init
- (defun add-asm-label-tag-generation-hook ()
- (add-hook 'after-save-hook
- (lambda ()
- (shell-command
- "find . -iregex '.*\\.[sS]' -exec etags -l none -r '/\\([a-zA-Z0-9\\-_]+\\):/\1/' {} +"))
- 0 t))
- :hook
- (asm-mode . 'add-asm-label-tag-generation-hook))
-
-(use-package compile ; compliation buffers and easy bind
- :custom
- (compilation-always-kill t)
- (compilation-scroll-output t)
- :bind (:map my/keys-mode-map ("M-M" . 'recompile))
- :config
- ;; Allow compilation buffer to be dedicated across frames
- (add-to-list 'display-buffer-alist '("\\*compilation\\*" nil (reusable-frames . t)))
- (add-hook 'compilation-filter-hook #'ansi-color-compilation-filter))
-
-(use-package man ; view manuals in emacs
- :custom
- (Man-switches "-a"))
-
-(use-package imenu ; jump to items in the current buffer
- :bind
- ("M-i" . imenu)
- :custom
- (imenu-auto-rescan t)
- (imenu-flatten t))
-
-(use-package xref ; jump to syntactic elements in project
- ;; (add-hook 'xref-backend-functions 'gxref-xref-backend)
- :bind ("M-I" . xref-find-definitions))
-
-(use-package time ; time if I want it in the modeline etc
- :custom
- (display-time-day-and-date t)
- (display-time-24hr-format t))
-
-(use-package battery ; battery in modeline etc
- )
-
-(progn ; indent code when pasting
- (require 'dash)
- (defvar yank-indent-modes '(prog-mode LaTeX-mode TeX-mode)
- "Modes in which to indent regions that are yanked (or yank-popped).")
-
- (defun yank-indent-func (&optional arg)
- (let* ((parents (derived-mode-all-parents major-mode))
- (helper (lambda (acc v) (or acc (member v yank-indent-modes))))
- (included (-reduce helper parents)))
- (when (and (not arg) included)
- (indent-region (region-beginning) (region-end)))))
-
- (advice-add 'yank :after 'yank-indent-func)
- (advice-add 'yank-pop :after 'yank-indent-func))
-
-(progn ; better commenting binds
- (global-set-key (kbd "C-x C-;") 'comment-or-uncomment-region)
- (global-set-key (kbd "C-x ;") 'comment-line)
- (global-set-key (kbd "C-x :") 'comment-or-uncomment-region)
- ;; ^ duped for terminal w/o C-;
- )
-
-(progn ; default modeline config additions
- (let ((dir '("" (:eval (let ((str (concat (format " [%s] " (my/shorten-path default-directory)))))
- (add-face-text-property
- 0 (length str)
- '(:weight bold :foreground "green2")
- t str)
- str)))))
- (add-to-list 'mode-line-misc-info dir)))
-
-(progn ; comfy scratch buffer
- (require 'iimage)
- (setq inhibit-startup-screen t)
- (setq initial-scratch-message
- (concat (propertize ";; " 'invisible t)
- "</home/tmu/.emacs.d/splashLaputa.png>
-;; scratch for lisp evaluation and unsaved text
-
-"))
- (add-hook 'emacs-startup-hook
- (lambda ()
- (with-current-buffer "*scratch*"
- (emacs-lock-mode 'kill)
- (iimage-mode 1)))))
-
-(use-package which-func ; headline
- :custom
- (which-func-display 'header)
- (which-func-modes '(c-mode c++-mode))
- :config
- (set-face-foreground 'which-func "sky-blue")
- (which-function-mode))
-
-(progn ; vc and related binds
- (setq vc-follow-symlinks t)
- (vc-auto-revert-mode 1)
- (add-hook 'prog-mode-hook 'smerge-mode))
-
-(progn ; confirm fewer things
- (setq kill-buffer-query-functions
- (delq 'process-kill-buffer-query-function kill-buffer-query-functions))
- (setq confirm-kill-processes nil)
- (setq async-shell-command-buffer 'new-buffer))
-
-;; misc vars
-(setq delete-pair-blink-delay 0
- enable-recursive-minibuffers t
- frame-resize-pixelwise t
- c-guess-region-max 5000)
-(electric-pair-mode 1)
-(electric-indent-mode 1)
-
-;;; External packages:
-
-(use-package orderless ; ordering (minibuffer) completions
- :demand t
- :custom
- (orderless-skip-highlighting t)
- (completion-styles '(orderless basic partial-completion emacs22))
- (completion-category-defaults nil)
- (completion-category-overrides nil)
- (completion-ignore-case t)
- (read-file-name-completion-ignore-case t)
- (read-buffer-completion-ignore-case t)
- (orderless-smart-case nil)
- (orderless-matching-styles
- '(orderless-prefixes orderless-literal orderless-regexp)))
-
-(use-package vertico ; better minibuffer complete
- :demand t
- :custom
- (vertico-cycle t)
- :config
- (vertico-mode 1)
- (vertico-flat-mode)
- :bind (:map minibuffer-local-map
- ("M-v" . 'vertico-flat-mode)))
-
-(use-package marginalia ; more info in minibuffer menus
- :demand t
- :custom
- (marginalia-max-relative-age 0)
- (marginalia-align 'right)
- :bind (:map minibuffer-local-map
- ("M-A" . 'marginalia-cycle))
- :config
- (marginalia-mode))
-
-(use-package embark ; more actions from minibuffer
- :demand t
- :bind
- (("C-." . embark-act)
- ("C-," . embark-dwim)
- ("C-h B" . embark-bindings))
- :config
- ;; Hide the mode line of the Embark live/completions buffers
- (add-to-list 'display-buffer-alist
- '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
- nil
- (window-parameters (mode-line-format . none)))))
-
-(use-package corfu ; in buffer completion
- :demand t
- :custom
- (corfu-cycle t)
- (corfu-quit-no-match t)
- :bind (("M-/" . completion-at-point))
- :init
- (defun my/corfu-commit-single ()
- "Complete without asking if there is only one candidate."
- (when (and (corfu--popup-visible-p)
- (= (length corfu--candidates) 1))
- (corfu-accept)))
- :hook (corfu-post-command . my/corfu-commit-single)
- :config
- (global-corfu-mode 1))
-
-(use-package cape ; extend completion frameworks
- :demand t
- :after orderless corfu
- :bind ("C-c p" . cape-prefix-map)
- :config
- (advice-add 'pcomplete-completions-at-point :around 'cape-wrap-silent)
- (defvar my/completion-at-point-functions-always-include
- (list 'tags-completion-at-point-function 'cape-dabbrev 'tempel-complete))
- (setq completion-at-point-functions my/completion-at-point-functions-always-include))
-
-(use-package tempel ; templates
- :demand t
- :custom
- (tempel-path "~/.emacs.d/templates/*.eld")
- :bind (("M-+" . tempel-complete))
- :config
- (keymap-set tempel-map "<remap> <forward-word>" #'tempel-next)
- (keymap-set tempel-map "<remap> <backward-word>" #'tempel-previous))
-
-(use-package tempel-collection ; other people's templates
- :after tempel
- :demand t)
-
-(use-package ibuffer-vc ; group buffers by vcs directory
- :after ibuffer
- :demand t
- :hook
- (ibuffer .
- (lambda ()
- (ibuffer-vc-set-filter-groups-by-vc-root)
- (unless (eq ibuffer-sorting-mode 'alphabetic)
- (ibuffer-do-sort-by-alphabetic)))))
-
-(use-package eldoc-box
- :after eldoc
- :demand t
- :custom
- (eldoc-box-clear-with-C-g t)
- :hook
- (eldoc-mode . eldoc-box-hover-mode))
-
-(use-package free-keys ; display a list of unbound keys
- )
-
-(use-package which-key ; show list of next keys after prefix & delay
- :demand t
- :config
- (which-key-mode 1))
-
-(use-package winum ; binds for switching to windows by number
- :demand t
- :config
- (winum-mode 1))
-
-;; (use-package savehist ; preserve minibuffer history across sessions
-;; :demand t
-;; :init
-;; (savehist-mode))
-
-;; (use-package consult ; more encompassing buffer switch and searching
-;; :demand t
-;; :custom
-;; (consult-preview-excluded-buffers t)
-;; (consult-narrow-key ",")
-;; :bind
-;; ("C-x b" . consult-buffer)
-;; ("M-W" . consult-buffer)
-;; ("C-S-y" . consult-yank-from-kill-ring)
-;; ("M-g M-g" . consult-goto-line)
-;; ("C-S-s" . consult-line-multi)
-;; ("M-s g" . consult-grep)
-;; ("M-s G" . grep)
-;; ("M-s f" . consult-find)
-;; ;; move some standard binds
-;; ("M-s s" . consult-line))
-;; (use-package embark-consult
-;; :after embark consult)
-
-(use-package projectile
- :config
- (projectile-mode 1)
- (define-key projectile-mode-map (kbd "C-x P") 'projectile-command-map))
-
-(use-package hl-todo ; highlight certain keywords
- :hook
- (prog-mode . hl-todo-mode))
-
-(use-package diff-hl
- :config
- (global-diff-hl-mode 1))
-
-(use-package visible-mark ; make the mark visible
- :demand t
- :custom-face
- (visible-mark-active
- ((t . (:foreground "black"
- :background "deep pink"
- :box (:line-width (-1 . -1)
- :color "deep pink"
- :style nil)))))
- :custom
- (visible-mark-max 1)
- :config
- (global-visible-mark-mode 1))
-
-(use-package avy ; goto location by char pair and jump list
- :bind (("M-G" . avy-goto-char-2))
- :custom
- (avy-all-windows nil)
- (avy-all-windows-alt 'all-frames))
-
-(use-package balanced-windows ; auto rebalance windows
- :bind ("C-x w b" . balanced-windows-mode))
-
-(use-package eat ; terminal emu + make eshell behave better
- :demand t
- :custom
- (eat-enable-auto-line-mode t)
- :config
- (eat-eshell-mode)
- (eat-eshell-visual-command-mode)
- (let* ((desired-global-binds (my/keymap-keys my/keys-mode-map))
- (desired-prefixes (mapcar (lambda (ks)
- (let ((k1 (elt ks 0))
- (meta-mask ?\M-\0))
- (if (numberp k1)
- (if (equal ?\e k1)
- (vector k1 (elt ks 1))
- (let ((k-no-m (logand k1 (lognot meta-mask)))
- (k-has-m (not (zerop (logand k1 meta-mask)))))
- (if k-has-m
- (vector ?\e k-no-m)
- (vector k1))))
- (vector k1))))
- desired-global-binds)))
- (mapc (lambda (ks)
- (add-to-list 'eat-semi-char-non-bound-keys ks)
- (add-to-list 'eat-eshell-semi-char-non-bound-keys ks))
- desired-prefixes)
- (eat-update-semi-char-mode-map)
- (eat-eshell-update-semi-char-mode-map)))
-
-(use-package bash-completion ; allow bash completion in eshell mostly
- :demand t
- :config
- (add-hook 'shell-dynamic-complete-functions
- 'bash-completion-dynamic-complete)
- :hook
- (eshell-mode . (lambda ()
- (add-hook 'completion-at-point-functions
- 'bash-completion-capf-nonexclusive nil t))))
-
-(use-package pinentry ; allow some passwords to be entered with emacs
- )
-
-(use-package password-store ; gnu pass integration
- :demand t)
-(use-package auth-source-pass ; allow pass to act as auth within emacs
- :init (auth-source-pass-enable))
-(use-package pass ; nice interface for gnu pass
- :demand t
- :after password-store auth-source-pass
- :custom
- (pass-suppress-confirmations t)
- (epg-pinentry-mode 'loopback)
- :config
- (add-to-list 'display-buffer-alist
- '("\\*Password-Store\\*"
- display-buffer-in-side-window
- (side . right))))
-
-(use-package pyvenv ; respect python environments
- )
-
-;; (use-package sideline ; put warnings on the side of the same line
-;; :init
-;; (use-package sideline-flycheck)
-;; (use-package sideline-flymake)
-;; :custom
-;; (sideline-backends-right '(sideline-flycheck sideline-flymake)))
-
-(use-package flycheck
- :config
- ;; flymake stuff to be less annoying
- ;; (face-spec-set 'flycheck-note '((t :underline nil)))
- ;; (face-spec-set 'flycheck-info '((t :underline nil)))
- ;; (face-spec-set 'flycheck-warning '((t :underline nil)))
- ;; (face-spec-set 'flycheck-error '((t :underline nil)))
- :custom
- (flycheck-check-syntax-automatically '(save mode-enabled))
- ;; :hook
- ;; (prog-mode . flycheck-mode)
- )
-
-;; (progn ; collected folding binds, hs + fold this
-;; (define-prefix-command 'my/fold-map)
-;; (global-set-key (kbd "M-F") 'my/fold-map)
-;; (define-keymap :full nil
-;; :parent nil
-;; :suppress nil
-;; :keymap nil
-;; :name "my/fold-map"
-;; :prefix 'my/fold-map)
-;; (progn ; hideshow folding
-;; (keymap-set my/fold-map "t" 'hs-toggle-hiding)
-;; (keymap-set my/fold-map "l" 'hs-hide-level)
-;; (keymap-set my/fold-map "C-t" 'hs-hide-all)
-;; (keymap-set my/fold-map "C-a" 'hs-show-all))
-
-;; (use-package fold-this ; fold arbitrary region
-;; :init
-;; (defun my/fold-this-fold-forward (&optional arg)
-;; "Fold forward ARG number of sexps, defaulting to one."
-;; (interactive "p")
-;; (push-mark)
-;; (forward-sexp arg)
-;; (fold-this (mark) (point))
-;; (pop-mark))
-
-;; (defun my/fold-this-fold-backward (&optional arg)
-;; "Fold backward ARG number of sexps, defaulting to one."
-;; (interactive "p")
-;; (push-mark)
-;; (backward-sexp arg)
-;; (fold-this (point) (mark))
-;; (pop-mark))
-
-;; :bind (:map my/fold-map
-;; ("c" . fold-this)
-;; ("e" . fold-this-unfold-at-point)
-;; ("f" . my/fold-this-fold-forward)
-;; ("b" . my/fold-this-fold-backward))))
-
-(use-package clang-format ; let clang do c formatting
- )
-
-(use-package rust-mode ; rust lang syntax
- )
-
-(use-package haskell-mode ; haskell + cabal integrations
- :custom
- (haskell-tags-on-save t)
- (haskell-process-type 'cabal-repl)
- (haskell-process-auto-import-loaded-modules t)
- :hook (haskell-mode . interactive-haskell-mode)
- :config
- (add-to-list 'compilation-error-regexp-alist-alist (cons 'microhs (list "^mhs:.*error:\\s-*\"\\(.*\\)\":\\s-*line \\([0-9]*\\), col \\([0-9]*\\)" 1 2 3 2)))
- (add-to-list 'compilation-error-regexp-alist 'microhs))
-
-(use-package opam-switch-mode ; make emacs mode respect switch
- :config
- (when (and (file-exists-p "~/.opam") (executable-find "opam"))
- (opam-switch-set-switch "default")))
-(use-package tuareg ; ocaml mode
- :after opam-switch-mode)
-(use-package ocp-indent ; indentation for ocaml
- :after tuareg
- :hook (tuareg-mode . ocp-setup-indent))
-(use-package merlin ; ocaml completion
- :after tuareg
- :hook (tuareg-mode . merlin-mode)
- :custom (merlin-command 'opam))
-
-(use-package racket-mode ; basic racket integration
- )
-
-(use-package sdcv ; dictionary, requires sdcv install
- :demand t
- :config
- (define-prefix-command 'dict-map)
- (define-keymap :full nil
- :parent nil
- :suppress nil
- :keymap nil
- :name "dict-map"
- :prefix 'dict-map
- (kbd "w") 'sdcv-search-input
- (kbd "c") (lambda () (interactive)
- (activate-input-method 'pyim)
- (sdcv-search-input (read-from-minibuffer "Chinese Word: "
- nil nil nil
- nil nil t))
- (activate-input-method nil)))
- :bind (:map text-mode-map
- ("M-l" . 'dict-map)))
-
-(use-package olivetti ; center content per buffer
- )
-
-;; (use-package erc ; irc client
-;; :init
-;; (defun my/start-erc ()
-;; "Start erc and autojoin various channels"
-;; (interactive)
-;; (erc-tls :server "tccq.net" :port 4095 :nick "tccq"))
-;; :custom
-;; (erc-modules '(services autojoin button completion fill imenu irccontrols list match menu
-;; move-to-prompt netsplit networks readonly ring stamp track))
-;; (erc-nick "tccq")
-;; (erc-use-auth-source-for-nickserv-password t)
-;; (erc-autojoin-channels-alist '(("libera.chat"
-;; "#emacs" "#haskell" "#duskos" "#tcc")))
-
-;; (erc-hide-list '("JOIN" "PART" "QUIT"))
-;; (erc-current-nick-highlight-type 'nick)
-;; (erc-keywords nil)
-;; (erc-track-exclude-types '("JOIN" "PART" "QUIT" "NICK" "MODE"))
-;; (erc-track-use-faces t)
-;; (erc-track-faces-priority-list '(erc-current-nick-face erc-keyword-face))
-;; (erc-track-priority-faces-only 'all))
-
-(use-package minions ; show less on the modeline
- :demand t
- :config
- (minions-mode 1)
- :custom
- (minions-prominent-modes '(my/temp-nonmodal-mode persp-mode auto-fill-mode eldoc-mode eglot-mode lsp-mode)))
-
-(use-package ispell ; spellchecker
- :demand t
- :custom
- (ispell-personal-dictionary "/home/tmu/.aspell.en.pws")
- :config
- (defun ispell-mode (&optional arg)
- "Make some old packages work with modern ispell."
- (interactive)
- (ispell-minor-mode arg))
- (advice-add 'ispell-mode :before 'debug)
- (setq-default text-mode-hook (cons 'ispell-minor-mode (remove 'ispell-mode text-mode-hook))))
-
-;;; Optional files for occasional loading:
+(load-file "~/.emacs.d/site-lisp/my-defines.el")
+(load-file "~/.emacs.d/site-lisp/my-builtins.el")
+(load-file "~/.emacs.d/site-lisp/my-packages.el")
+(load-file "~/.emacs.d/site-lisp/my-eglot.el")
(autoload 'mm/global-modal-mode "/home/tmu/.emacs.d/site-lisp/my-modal.el" "" t)
(autoload 'single-header-mode "/home/tmu/.emacs.d/site-lisp/single-header.el" "" t)
-(load-file "/home/tmu/.emacs.d/site-lisp/my-eglot.el")
;; if you want exwm, include from ~/.emacs.d/site-lisp/my-exwm.el
;; if you want mail, include from ~/.emacs.d/site-lisp/my-mail.el
-;;; Theming:
-
(require 'tmu-custom-theme)
(push "~/.emacs.d/site-lisp/" custom-theme-load-path)
(load-theme 'tmu-custom t)
diff --git a/config/emacs/site-lisp/my-builtins.el b/config/emacs/site-lisp/my-builtins.el
new file mode 100644
index 0000000..94e82c1
--- /dev/null
+++ b/config/emacs/site-lisp/my-builtins.el
@@ -0,0 +1,200 @@
+;;; Builtin config: -*- lexical-binding: t; -*-
+
+(use-package server ; allow emacsclient
+ :demand t
+ :config
+ (unless (server-running-p) (server-start)))
+
+(use-package proced ; process editor
+ :commands (proced)
+ :config
+ (setq-default proced-auto-update-flag t)
+ (setq-default proced-auto-update-interval 1))
+
+(use-package dabbrev ; dynamic abbreviations
+ :demand t
+ :config
+ (add-to-list 'dabbrev-ignored-buffer-modes 'exwm-mode)
+ (add-to-list 'dabbrev-ignored-buffer-modes 'pdf-view-mode)
+ (add-to-list 'dabbrev-ignored-buffer-modes 'tags-table-mode)
+ (add-to-list 'dabbrev-ignored-buffer-modes 'doc-view-mode))
+
+(progn ; dired directory editor
+ (require 'dired)
+ (defun dired-do-find-marked-files ()
+ (interactive)
+ (seq-do 'find-file (dired-get-marked-files)))
+ (define-key dired-mode-map (kbd "C-o") 'dired-display-file)
+ (define-key dired-mode-map (kbd "F") 'dired-do-find-marked-files))
+
+(use-package ibuffer ; give a nice list of buffers with extra info
+ :commands (ibuffer)
+ :custom
+ (ibuffer-formats
+ '((mark modified read-only " "
+ (name 50 50 :left :elide) ; was originally 18
+ " "
+ (size 9 -1 :right)
+ " "
+ (mode 16 16 :left :elide)
+ " " filename-and-process)
+ (mark " "
+ (name 16 -1)
+ " " filename)))
+ :bind
+ ("C-x C-b" . ibuffer))
+
+(progn ; isearch search in buffer
+ ;; swap basic and regex binds
+ (keymap-set global-map "C-s" 'isearch-forward-regexp)
+ (keymap-set global-map "C-r" 'isearch-backward-regexp)
+ (keymap-set global-map "C-M-s" 'isearch-forward)
+ (keymap-set global-map "C-M-r" 'isearch-backward))
+
+(use-package eshell ; emacs shell
+ :demand t
+ :config
+ (use-package esh-help)
+ (require 'em-hist)
+ (require 'em-term)
+ (setup-esh-help-eldoc)
+ :bind (:map eshell-mode-map
+ ("C-l" . my/eshell-clear-or-center)) ; todo make smarter with centering
+ :hook (eshell-mode . eldoc-mode))
+
+(use-package ediff ; emacs interactive diff
+ :custom
+ (ediff-window-setup-function 'ediff-setup-windows-plain))
+
+(progn ; comint, doesn't play with use-package
+ (require 'comint)
+ (setq-default comint-scroll-to-bottom-on-input t)
+ (setq-default comint-scroll-to-bottom-on-output t)
+ (setq-default comint-buffer-maximum-size 1048576)
+ (add-to-list 'comint-output-filter-functions #'comint-truncate-buffer)
+ (add-to-list 'comint-output-filter-functions #'ansi-color-process-output))
+
+(use-package tramp ; remote access for files
+ :demand t
+ :custom
+ (tramp-allow-unsafe-temporary-files t))
+
+(use-package asm-mode ; asm comments and tags generation
+ :demand t
+ :custom
+ (asm-comment-char ?#) ; prefer # over ; for asm comments
+ :init
+ (defun add-asm-label-tag-generation-hook ()
+ (add-hook 'after-save-hook
+ (lambda ()
+ (shell-command
+ "find . -iregex '.*\\.[sS]' -exec etags -l none -r '/\\([a-zA-Z0-9\\-_]+\\):/\1/' {} +"))
+ 0 t))
+ :hook
+ (asm-mode . 'add-asm-label-tag-generation-hook))
+
+(use-package compile ; compliation buffers and easy bind
+ :custom
+ (compilation-always-kill t)
+ (compilation-scroll-output t)
+ :bind (:map my/keys-mode-map ("M-M" . 'recompile))
+ :config
+ ;; Allow compilation buffer to be dedicated across frames
+ (add-to-list 'display-buffer-alist '("\\*compilation\\*" nil (reusable-frames . t)))
+ (add-hook 'compilation-filter-hook #'ansi-color-compilation-filter))
+
+(use-package man ; view manuals in emacs
+ :custom
+ (Man-switches "-a"))
+
+(use-package imenu ; jump to items in the current buffer
+ :bind
+ ("M-i" . imenu)
+ :custom
+ (imenu-auto-rescan t)
+ (imenu-flatten t))
+
+(use-package xref ; jump to syntactic elements in project
+ ;; (add-hook 'xref-backend-functions 'gxref-xref-backend)
+ :bind ("M-I" . xref-find-definitions))
+
+(use-package time ; time if I want it in the modeline etc
+ :custom
+ (display-time-day-and-date t)
+ (display-time-24hr-format t))
+
+(use-package battery ; battery in modeline etc
+ )
+
+(progn ; indent code when pasting
+ (require 'dash)
+ (defvar yank-indent-modes '(prog-mode LaTeX-mode TeX-mode)
+ "Modes in which to indent regions that are yanked (or yank-popped).")
+
+ (defun yank-indent-func (&optional arg)
+ (let* ((parents (derived-mode-all-parents major-mode))
+ (helper (lambda (acc v) (or acc (member v yank-indent-modes))))
+ (included (-reduce helper parents)))
+ (when (and (not arg) included)
+ (indent-region (region-beginning) (region-end)))))
+
+ (advice-add 'yank :after 'yank-indent-func)
+ (advice-add 'yank-pop :after 'yank-indent-func))
+
+(progn ; better commenting binds
+ (global-set-key (kbd "C-x C-;") 'comment-or-uncomment-region)
+ (global-set-key (kbd "C-x ;") 'comment-line)
+ (global-set-key (kbd "C-x :") 'comment-or-uncomment-region)
+ ;; ^ duped for terminal w/o C-;
+ )
+
+(progn ; default modeline config additions
+ (let ((dir '("" (:eval (let ((str (concat (format " [%s] " (my/shorten-path default-directory)))))
+ (add-face-text-property
+ 0 (length str)
+ '(:weight bold :foreground "green2")
+ t str)
+ str)))))
+ (add-to-list 'mode-line-misc-info dir)))
+
+(progn ; comfy scratch buffer
+ (require 'iimage)
+ (setq inhibit-startup-screen t)
+ (setq initial-scratch-message
+ (concat (propertize ";; " 'invisible t)
+ "</home/tmu/.emacs.d/splashLaputa.png>
+;; scratch for lisp evaluation and unsaved text
+
+"))
+ (add-hook 'emacs-startup-hook
+ (lambda ()
+ (with-current-buffer "*scratch*"
+ (emacs-lock-mode 'kill)
+ (iimage-mode 1)))))
+
+(use-package which-func ; headline
+ :custom
+ (which-func-display 'header)
+ (which-func-modes '(c-mode c++-mode))
+ :config
+ (set-face-foreground 'which-func "sky-blue")
+ (which-function-mode))
+
+(progn ; vc and related binds
+ (setq vc-follow-symlinks t)
+ (vc-auto-revert-mode 1)
+ (add-hook 'prog-mode-hook 'smerge-mode))
+
+(progn ; confirm fewer things
+ (setq kill-buffer-query-functions
+ (delq 'process-kill-buffer-query-function kill-buffer-query-functions))
+ (setq confirm-kill-processes nil)
+ (setq async-shell-command-buffer 'new-buffer))
+
+;; misc vars
+(setq delete-pair-blink-delay 0
+ enable-recursive-minibuffers t
+ frame-resize-pixelwise t
+ c-guess-region-max 5000)
+(electric-pair-mode 1)
+(electric-indent-mode 1)
diff --git a/config/emacs/site-lisp/my-defines.el b/config/emacs/site-lisp/my-defines.el
new file mode 100644
index 0000000..425a23e
--- /dev/null
+++ b/config/emacs/site-lisp/my-defines.el
@@ -0,0 +1,363 @@
+;;; Custom definitions, with prefix "my/" -*- lexical-binding: t; -*-
+
+(defvar surround-keys '("(" "{" "[" "$" "\"" "'"))
+(defun my/wrap-pair ()
+ "Ensure the region is active and then \"insert-pair\"."
+ (interactive)
+ (activate-mark)
+ (insert-pair))
+(eval
+ `(define-keymap
+ :full nil
+ :name "Surround"
+ :prefix 'surround-prefix
+ ,@(mapcan
+ (lambda (key) (list key ''my/wrap-pair))
+ surround-keys
+ )))
+
+(defun my/toggle-frame-transparency ()
+ "Toggle transparency."
+ (interactive)
+ (let ((alpha-transparency 90))
+ (if (eq alpha-transparency (frame-parameter nil 'alpha-background))
+ (set-frame-parameter nil 'alpha-background 100)
+ (set-frame-parameter nil 'alpha-background alpha-transparency))))
+
+(defvar my/prog-cleanup-excluded-modes
+ '(makefile-gmake-mode makefile-mode makefile-imake-mode
+ makefile-makepp-mode makefile-bsdmake-mode
+ makefile-automake-mode
+ python-mode
+ fundamental-mode)
+ "Major modes for which \"my/clean-prog-file\" should not be run before save.")
+
+(defvar my/prog-cleanup-want-tabs-modes
+ '(makefile-gmake-mode makefile-mode makefile-imake-mode
+ makefile-makepp-mode makefile-bsdmake-mode makefile-automake-mode)
+ "Major modes that need tabs instead of spaces.
+\"my/clean-prog-file\" should convert spaces to tabs instead of tabs to spaces.")
+
+(defvar my/prog-cleanup-indent-max-lines 500
+ "Skip reindenting the buffer if it is longer than this many lines.
+Nil for no limit.")
+
+(define-minor-mode my/global-prog-clean-mode
+ "Do auto formating on save in prog mode buffers."
+ :global t
+ (if my/global-prog-clean-mode
+ (progn ;enable
+ (add-hook 'before-save-hook 'my/clean-prog-file))
+ (progn ;disable
+ (remove-hook 'before-save-hook 'my/clean-prog-file))))
+(my/global-prog-clean-mode 1)
+
+(defun my/clean-prog-file (&optional buffer)
+ "Perform whitespace cleanup and some normalization on `buffer'.
+Defaults to the current BUFFER. Converts tabs to spaces unless the
+major mode is in `my/prog-cleanup-want-tabs-modes', otherwise do the
+reverse. Delete trailing whitespace."
+ (unless buffer (setq buffer (current-buffer)))
+ (with-current-buffer buffer
+ (when (and my/global-prog-clean-mode
+ (not (member major-mode my/prog-cleanup-excluded-modes))
+ (derived-mode-p '(prog-mode))
+ (cond
+ ((and (functionp 'clang-format-buffer)
+ ; safety valve for undef'd
+ (derived-mode-p '(c-mode c++-mode)))
+ (clang-format-buffer))
+ (t
+ (when (and my/prog-cleanup-indent-max-lines
+ (< (car (buffer-line-statistics buffer))
+ my/prog-cleanup-indent-max-lines))
+ (indent-region (point-min) (point-max)))))
+ (if (member major-mode my/prog-cleanup-want-tabs-modes)
+ (tabify (point-min) (point-max))
+ (untabify (point-min) (point-max)))
+ (delete-trailing-whitespace)))))
+
+(defun my/prog-buffer-setup ()
+ "Do setup in for code buffers."
+ ;; (superword-mode 1)
+ ;; (modify-syntax-entry ?_ "w")
+ ;; (hs-minor-mode 1)
+ (display-fill-column-indicator-mode 1)
+ (smerge-mode 1)
+ (ignore-errors
+ (when (and (derived-mode-p '(c-mode c++-mode))
+ (> (car (buffer-line-statistics)) 0))
+ (c-guess))))
+(add-hook 'prog-mode-hook 'my/prog-buffer-setup)
+
+(defun my/wrap-region-paren ()
+ "Wraps the region in parens. Similar to pressing ( with the region active."
+ (interactive)
+ (let ((beg (region-beginning))
+ (end (region-end)))
+ (save-excursion
+ (goto-char beg)
+ (insert "(")
+ (goto-char (+ end 1))
+ (insert ")"))))
+
+(defun my/zap-whitespace ()
+ "Zaps (deletes) the whitespace around the point in both directions."
+ (interactive)
+ (push-mark)
+ (skip-chars-backward " \t\n")
+ (push-mark)
+ (skip-chars-forward " \t\n")
+ (delete-region (mark) (point))
+ (pop-mark)
+ (goto-char (mark))
+ (pop-mark))
+
+(defun my/wrap-sexp (&optional arg)
+ "Wraps the following sexp in a pair of parens.
+Places point inside the new pair, pushing the mark before the new pair.
+With prefix ARG do ARG number sexps if given, including backwards."
+ (interactive "p")
+ (message "%s" arg)
+ (if arg
+ (progn
+ (push-mark)
+ (insert-pair arg ?\( ?\)))
+ (insert-pair 1 ?\( ?\))))
+
+(defun my/toggle-window-other-reachability ()
+ "Toggle whether this window can be selected by `other-window'."
+ (interactive)
+ (let* ((win (get-buffer-window (current-buffer)))
+ (current (window-parameter win 'no-other-window)))
+ (set-window-parameter win 'no-other-window (not current))
+ (force-mode-line-update)))
+;; small hack to make other window reachability visible like window dedication
+(advice-add 'mode-line-window-control :around
+ (lambda (f) (concat (funcall f)
+ (if (window-parameter nil 'no-other-window) "o" "")))
+ '(:name "other-window-indicator"))
+
+;; TODO find a bind for this
+(defun my/open-window-by-buffer (buffer)
+ "Move focus to an extant window by the buffer it contains.
+If no such window exists, switch to BUFFER in the current window."
+ (interactive "bBuffer: ")
+ (let ((win (get-buffer-window buffer t)))
+ (if win
+ (select-window win)
+ (switch-to-buffer buffer))))
+
+(defun my/shorten-path (path)
+ "Shorten string PATH. Initialize all but the last path component."
+ (let* ((components (split-string path "/"))
+ (last-component (-last (lambda (s) (not (string-empty-p s))) components))
+ (shortened-components
+ (mapcar (lambda (comp)
+ (if (or (string-equal comp last-component) (string-empty-p comp))
+ comp
+ (substring comp 0 1)))
+ components)))
+ (mapconcat 'identity shortened-components "/")))
+
+(defun my/swap-other-window-buffer ()
+ "Exchange buffer contents with the next window.
+Tries to switch the buffer contents of the current window and the next
+in the cyclic ordering. Doesn't consider windows that are dedicated."
+ (interactive)
+ (let* ((cw (get-mru-window nil nil nil t))
+ (cb (window-buffer cw))
+ (ow (next-window))
+ (ob (window-buffer ow)))
+ (unless (window-dedicated-p cw)
+ (while (window-dedicated-p ow)
+ (setq ow (next-window ow)
+ ob (window-buffer ow)))
+ (unless (eq cw ow)
+ (progn
+ (with-selected-window ow
+ (switch-to-buffer cb))
+ (with-selected-window cw
+ (switch-to-buffer ob)))))))
+
+(defun my/activate-mark ()
+ "Activate the region a la `C-SPC C-SPC', but don't move the point.
+Useful in combination with `query-replace' for acting on the region."
+ (interactive)
+ (if (region-active-p)
+ (deactivate-mark)
+ (activate-mark)))
+
+(defun my/c-x-n-to-m-n (&optional keymap)
+ "Copy bindings from C-x [n] to M-[n] in KEYMAP, defaulting to the global
+keymap."
+ (unless keymap (setq keymap global-map))
+ (mapc (lambda (n)
+ (let* ((from (concat "C-x " (format "%d" n)))
+ (to (concat "M-" (format "%d" n)))
+ (bind (keymap-lookup keymap from)))
+ (keymap-set keymap to bind)))
+ '(0 1 2 3 4 5 6 7 8 9)))
+(my/c-x-n-to-m-n)
+
+(defun my/keymap-keys (map)
+ "Return a list of all key sequences in a keymap MAP recursively."
+ (mapcan (lambda (c)
+ (let ((ks (car c))
+ (km (cdr c))
+ (acc nil))
+ (map-keymap (lambda (key bind)
+ (let ((kss (vconcat ks (vector key))))
+ (when (commandp bind)
+ (push kss acc))))
+ km)
+ acc))
+ (accessible-keymaps map)))
+
+(defun my/eshell (&optional arg)
+ "Create a new eshell or switch to an existing one.
+With ARG, make a new shell. If the current buffer is an eshell, switch
+back to the previous selected buffer."
+ (interactive "P")
+ (if (eq major-mode 'eshell-mode)
+ (switch-to-prev-buffer)
+ (eshell arg)))
+
+(defun my/eshell-clear-or-center (&optional clear)
+ "Either clear the screen or recenter display depending on point location."
+ (interactive "P")
+ (cond
+ (clear (eshell/clear clear))
+ ((>= (point) eshell-last-output-end) ;; at the input line
+ (eshell/clear clear))
+ (t ;; in scroll back somewhere
+ (recenter-top-bottom))))
+
+(defun my/vc-on-root (&optional arg)
+ "Open a vc dir buffer at the project root.
+With ARG, open a Dired buffer instead."
+ (interactive "P")
+ (let ((dir (project-root (project-current t))))
+ (if arg
+ (dired dir)
+ (vc-dir dir))))
+
+(defun my/shell-at-root ()
+ "Execute an async shell commmand at the root of the current project."
+ (interactive)
+ (let ((prior-cwd default-directory)
+ (want-quit inhibit-quit))
+ (setq inhibit-quit t)
+ (with-local-quit
+ (setq default-directory (project-root (project-current)))
+ (call-interactively 'async-shell-command))
+ (setq default-directory prior-cwd
+ inhibit-quit want-quit)))
+
+(defun my/kill-buffer (&optional arg)
+ "Kill the current buffer. With ARG kill the window as well."
+ (interactive "P")
+ (if arg
+ (kill-buffer-and-window)
+ (kill-buffer)))
+
+(defvar my/layout-pair (cons nil nil)
+ "Cons pair of window configurations.")
+(add-hook 'after-init-hook
+ (lambda ()
+ (setq my/layout-pair (cons (current-window-configuration)
+ (current-window-configuration)))))
+(defun my/layout-swap (&optional arg)
+ "Swap between the two saved window configurations.
+With ARG, don't save the current layout."
+ (interactive "p")
+ (let ((left (car my/layout-pair))
+ (right (cdr my/layout-pair))
+ (cwc (current-window-configuration)))
+ (cond
+ ((>= arg 16) (setq my/layout-pair (cons cwc cwc)))
+ ((eq (selected-frame) (window-configuration-frame right))
+ (unless (>= arg 4) (setq left cwc))
+ (set-window-configuration right t t)
+ (setq my/layout-pair (cons right left)))
+ (t (message "Quick layout swap only works with same frame!")))))
+
+(defun my/display-lines-advice (func &rest r)
+ "Around advice that temporarily shows line numbers."
+ (let ((want-quit inhibit-quit))
+ (setq inhibit-quit t)
+ (display-line-numbers-mode 1)
+ (force-window-update)
+ (with-local-quit
+ (call-interactively func))
+ (display-line-numbers-mode -1)
+ (force-window-update)
+ (setq inhibit-quit want-quit)))
+
+(progn ; my global keybinds
+ (define-minor-mode my/keys-mode
+ "Minor mode collecting global keybinds"
+ :global t
+ :keymap (make-sparse-keymap)
+
+ (if my/keys-mode
+ (repeat-mode 1)
+ (repeat-mode -1)))
+ (require 'eshell)
+ (require 'em-prompt)
+ (put 'other-window 'repeat-map nil)
+ (put 'other-window-backward 'repeat-map nil)
+ (put 'eshell-previous-prompt 'repeat-map nil)
+ (put 'eshell-next-prompt 'repeat-map nil)
+
+ ;; The keymaps in `emulation-mode-map-alists' take precedence over
+ ;; `minor-mode-map-alist'
+ (add-to-list 'emulation-mode-map-alists
+ '((my/keys-mode . my/keys-keymap)))
+
+ (keymap-set my/keys-mode-map "C-x -" 'my/swap-other-window-buffer)
+ (keymap-set my/keys-mode-map "C-x w o" 'my/toggle-window-other-reachability)
+ (keymap-set my/keys-mode-map "C-x w r r" 'window-layout-rotate-clockwise)
+ (keymap-set my/keys-mode-map "C-x w r R" 'window-layout-rotate-anticlockwise)
+ (keymap-set window-layout-rotate-repeat-map "r" 'window-layout-rotate-clockwise)
+ (keymap-set window-layout-rotate-repeat-map "R" 'window-layout-rotate-anticlockwise)
+
+ (keymap-set my/keys-mode-map "C-M-z" 'my/wrap-sexp)
+
+ (keymap-set my/keys-mode-map "C-c R" 'raise-sexp)
+ (keymap-set my/keys-mode-map "C-c r" 'delete-pair)
+
+ (keymap-set my/keys-mode-map "M-s g" 'grep)
+ (keymap-set my/keys-mode-map "M-s r" 'query-replace-regexp)
+ (keymap-set my/keys-mode-map "M-s a" 'align-regexp)
+
+ (keymap-set my/keys-mode-map "M-w" 'copy-region-as-kill)
+ (keymap-set my/keys-mode-map "M-(" 'my/wrap-region-paren)
+ (keymap-set my/keys-mode-map "M-z" 'my/zap-whitespace)
+ (keymap-set my/keys-mode-map "M-o" 'other-window)
+ (keymap-set my/keys-mode-map "M-O" 'other-window-backward)
+ (keymap-set my/keys-mode-map "M-RET" 'my/eshell)
+ (keymap-set my/keys-mode-map "M-C" 'calc)
+ (keymap-set my/keys-mode-map "M-K" 'my/kill-buffer)
+ (keymap-set my/keys-mode-map "M-D" 'my/vc-on-root)
+ (keymap-set my/keys-mode-map "M-Q" 'auto-fill-mode)
+ (keymap-set my/keys-mode-map "M-A" 'beginning-of-line-text)
+ (keymap-set my/keys-mode-map "M-R" 'my/layout-swap)
+ (keymap-set my/keys-mode-map "M-W" 'switch-to-buffer)
+ (keymap-set my/keys-mode-map "M-N" 'man)
+ (keymap-set my/keys-mode-map "M-*" 'my/shell-at-root)
+ (keymap-set my/keys-mode-map "M-S" 'surround-prefix)
+ (keymap-set my/keys-mode-map "M-J" 'my/activate-mark)
+
+ (my/keys-mode 1))
+
+(progn ; mode for log files
+ (define-derived-mode
+ generic-log-mode
+ fundamental-mode
+ "Log"
+ "Major mode for following log files."
+ (setq-local auto-revert-verbose nil)
+ (auto-revert-tail-mode 1))
+ (add-to-list 'auto-mode-alist
+ '("\\.log\\'" . generic-log-mode)))
diff --git a/config/emacs/site-lisp/my-packages.el b/config/emacs/site-lisp/my-packages.el
new file mode 100644
index 0000000..c625252
--- /dev/null
+++ b/config/emacs/site-lisp/my-packages.el
@@ -0,0 +1,394 @@
+;;; External packages: -*- lexical-binding: t; -*-
+
+(use-package orderless ; ordering (minibuffer) completions
+ :demand t
+ :custom
+ (orderless-skip-highlighting t)
+ (completion-styles '(orderless basic partial-completion emacs22))
+ (completion-category-defaults nil)
+ (completion-category-overrides nil)
+ (completion-ignore-case t)
+ (read-file-name-completion-ignore-case t)
+ (read-buffer-completion-ignore-case t)
+ (orderless-smart-case nil)
+ (orderless-matching-styles
+ '(orderless-prefixes orderless-literal orderless-regexp)))
+
+(use-package vertico ; better minibuffer complete
+ :demand t
+ :custom
+ (vertico-cycle t)
+ :config
+ (vertico-mode 1)
+ (vertico-flat-mode)
+ :bind (:map minibuffer-local-map
+ ("M-v" . 'vertico-flat-mode)))
+
+(use-package marginalia ; more info in minibuffer menus
+ :demand t
+ :custom
+ (marginalia-max-relative-age 0)
+ (marginalia-align 'right)
+ :bind (:map minibuffer-local-map
+ ("M-A" . 'marginalia-cycle))
+ :config
+ (marginalia-mode))
+
+(use-package embark ; more actions from minibuffer
+ :demand t
+ :bind
+ (("C-." . embark-act)
+ ("C-," . embark-dwim)
+ ("C-h B" . embark-bindings))
+ :config
+ ;; Hide the mode line of the Embark live/completions buffers
+ (add-to-list 'display-buffer-alist
+ '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
+ nil
+ (window-parameters (mode-line-format . none)))))
+
+(use-package corfu ; in buffer completion
+ :demand t
+ :custom
+ (corfu-cycle t)
+ (corfu-quit-no-match t)
+ :bind (("M-/" . completion-at-point))
+ :init
+ (defun my/corfu-commit-single ()
+ "Complete without asking if there is only one candidate."
+ (when (and (corfu--popup-visible-p)
+ (= (length corfu--candidates) 1))
+ (corfu-accept)))
+ :hook (corfu-post-command . my/corfu-commit-single)
+ :config
+ (global-corfu-mode 1))
+
+(use-package cape ; extend completion frameworks
+ :demand t
+ :after orderless corfu
+ :bind ("C-c p" . cape-prefix-map)
+ :config
+ (advice-add 'pcomplete-completions-at-point :around 'cape-wrap-silent)
+ (defvar my/completion-at-point-functions-always-include
+ (list 'tags-completion-at-point-function 'cape-dabbrev 'tempel-complete))
+ (setq completion-at-point-functions my/completion-at-point-functions-always-include))
+
+(use-package tempel ; templates
+ :demand t
+ :custom
+ (tempel-path "~/.emacs.d/templates/*.eld")
+ :bind (("M-+" . tempel-complete))
+ :config
+ (keymap-set tempel-map "<remap> <forward-word>" #'tempel-next)
+ (keymap-set tempel-map "<remap> <backward-word>" #'tempel-previous))
+
+(use-package tempel-collection ; other people's templates
+ :after tempel
+ :demand t)
+
+(use-package ibuffer-vc ; group buffers by vcs directory
+ :after ibuffer
+ :demand t
+ :hook
+ (ibuffer .
+ (lambda ()
+ (ibuffer-vc-set-filter-groups-by-vc-root)
+ (unless (eq ibuffer-sorting-mode 'alphabetic)
+ (ibuffer-do-sort-by-alphabetic)))))
+
+(use-package eldoc-box
+ :after eldoc
+ :demand t
+ :custom
+ (eldoc-box-clear-with-C-g t)
+ :hook
+ (eldoc-mode . eldoc-box-hover-mode))
+
+(use-package free-keys ; display a list of unbound keys
+ )
+
+(use-package which-key ; show list of next keys after prefix & delay
+ :demand t
+ :config
+ (which-key-mode 1))
+
+(use-package winum ; binds for switching to windows by number
+ :demand t
+ :config
+ (winum-mode 1))
+
+;; (use-package savehist ; preserve minibuffer history across sessions
+;; :demand t
+;; :init
+;; (savehist-mode))
+
+;; (use-package consult ; more encompassing buffer switch and searching
+;; :demand t
+;; :custom
+;; (consult-preview-excluded-buffers t)
+;; (consult-narrow-key ",")
+;; :bind
+;; ("C-x b" . consult-buffer)
+;; ("M-W" . consult-buffer)
+;; ("C-S-y" . consult-yank-from-kill-ring)
+;; ("M-g M-g" . consult-goto-line)
+;; ("C-S-s" . consult-line-multi)
+;; ("M-s g" . consult-grep)
+;; ("M-s G" . grep)
+;; ("M-s f" . consult-find)
+;; ;; move some standard binds
+;; ("M-s s" . consult-line))
+;; (use-package embark-consult
+;; :after embark consult)
+
+(use-package projectile
+ :config
+ (projectile-mode 1)
+ (define-key projectile-mode-map (kbd "C-x P") 'projectile-command-map))
+
+(use-package hl-todo ; highlight certain keywords
+ :hook
+ (prog-mode . hl-todo-mode))
+
+(use-package diff-hl
+ :config
+ (global-diff-hl-mode 1))
+
+(use-package visible-mark ; make the mark visible
+ :demand t
+ :custom-face
+ (visible-mark-active
+ ((t . (:foreground "black"
+ :background "deep pink"
+ :box (:line-width (-1 . -1)
+ :color "deep pink"
+ :style nil)))))
+ :custom
+ (visible-mark-max 1)
+ :config
+ (global-visible-mark-mode 1))
+
+(use-package avy ; goto location by char pair and jump list
+ :bind (("M-G" . avy-goto-char-2))
+ :custom
+ (avy-all-windows nil)
+ (avy-all-windows-alt 'all-frames))
+
+(use-package balanced-windows ; auto rebalance windows
+ :bind ("C-x w b" . balanced-windows-mode))
+
+(use-package eat ; terminal emu + make eshell behave better
+ :demand t
+ :custom
+ (eat-enable-auto-line-mode t)
+ :config
+ (eat-eshell-mode)
+ (eat-eshell-visual-command-mode)
+ (let* ((desired-global-binds (my/keymap-keys my/keys-mode-map))
+ (desired-prefixes (mapcar (lambda (ks)
+ (let ((k1 (elt ks 0))
+ (meta-mask ?\M-\0))
+ (if (numberp k1)
+ (if (equal ?\e k1)
+ (vector k1 (elt ks 1))
+ (let ((k-no-m (logand k1 (lognot meta-mask)))
+ (k-has-m (not (zerop (logand k1 meta-mask)))))
+ (if k-has-m
+ (vector ?\e k-no-m)
+ (vector k1))))
+ (vector k1))))
+ desired-global-binds)))
+ (mapc (lambda (ks)
+ (add-to-list 'eat-semi-char-non-bound-keys ks)
+ (add-to-list 'eat-eshell-semi-char-non-bound-keys ks))
+ desired-prefixes)
+ (eat-update-semi-char-mode-map)
+ (eat-eshell-update-semi-char-mode-map)))
+
+(use-package bash-completion ; allow bash completion in eshell mostly
+ :demand t
+ :config
+ (add-hook 'shell-dynamic-complete-functions
+ 'bash-completion-dynamic-complete)
+ :hook
+ (eshell-mode . (lambda ()
+ (add-hook 'completion-at-point-functions
+ 'bash-completion-capf-nonexclusive nil t))))
+
+(use-package pinentry ; allow some passwords to be entered with emacs
+ )
+
+(use-package password-store ; gnu pass integration
+ :demand t)
+(use-package auth-source-pass ; allow pass to act as auth within emacs
+ :init (auth-source-pass-enable))
+(use-package pass ; nice interface for gnu pass
+ :demand t
+ :after password-store auth-source-pass
+ :custom
+ (pass-suppress-confirmations t)
+ (epg-pinentry-mode 'loopback)
+ :config
+ (add-to-list 'display-buffer-alist
+ '("\\*Password-Store\\*"
+ display-buffer-in-side-window
+ (side . right))))
+
+(use-package pyvenv ; respect python environments
+ )
+
+;; (use-package sideline ; put warnings on the side of the same line
+;; :init
+;; (use-package sideline-flycheck)
+;; (use-package sideline-flymake)
+;; :custom
+;; (sideline-backends-right '(sideline-flycheck sideline-flymake)))
+
+(use-package flycheck
+ :config
+ ;; flymake stuff to be less annoying
+ ;; (face-spec-set 'flycheck-note '((t :underline nil)))
+ ;; (face-spec-set 'flycheck-info '((t :underline nil)))
+ ;; (face-spec-set 'flycheck-warning '((t :underline nil)))
+ ;; (face-spec-set 'flycheck-error '((t :underline nil)))
+ :custom
+ (flycheck-check-syntax-automatically '(save mode-enabled))
+ ;; :hook
+ ;; (prog-mode . flycheck-mode)
+ )
+
+;; (progn ; collected folding binds, hs + fold this
+;; (define-prefix-command 'my/fold-map)
+;; (global-set-key (kbd "M-F") 'my/fold-map)
+;; (define-keymap :full nil
+;; :parent nil
+;; :suppress nil
+;; :keymap nil
+;; :name "my/fold-map"
+;; :prefix 'my/fold-map)
+;; (progn ; hideshow folding
+;; (keymap-set my/fold-map "t" 'hs-toggle-hiding)
+;; (keymap-set my/fold-map "l" 'hs-hide-level)
+;; (keymap-set my/fold-map "C-t" 'hs-hide-all)
+;; (keymap-set my/fold-map "C-a" 'hs-show-all))
+
+;; (use-package fold-this ; fold arbitrary region
+;; :init
+;; (defun my/fold-this-fold-forward (&optional arg)
+;; "Fold forward ARG number of sexps, defaulting to one."
+;; (interactive "p")
+;; (push-mark)
+;; (forward-sexp arg)
+;; (fold-this (mark) (point))
+;; (pop-mark))
+
+;; (defun my/fold-this-fold-backward (&optional arg)
+;; "Fold backward ARG number of sexps, defaulting to one."
+;; (interactive "p")
+;; (push-mark)
+;; (backward-sexp arg)
+;; (fold-this (point) (mark))
+;; (pop-mark))
+
+;; :bind (:map my/fold-map
+;; ("c" . fold-this)
+;; ("e" . fold-this-unfold-at-point)
+;; ("f" . my/fold-this-fold-forward)
+;; ("b" . my/fold-this-fold-backward))))
+
+(use-package clang-format ; let clang do c formatting
+ )
+
+(use-package rust-mode ; rust lang syntax
+ )
+
+(use-package haskell-mode ; haskell + cabal integrations
+ :custom
+ (haskell-tags-on-save t)
+ (haskell-process-type 'cabal-repl)
+ (haskell-process-auto-import-loaded-modules t)
+ :hook (haskell-mode . interactive-haskell-mode)
+ :config
+ (add-to-list 'compilation-error-regexp-alist-alist (cons 'microhs (list "^mhs:.*error:\\s-*\"\\(.*\\)\":\\s-*line \\([0-9]*\\), col \\([0-9]*\\)" 1 2 3 2)))
+ (add-to-list 'compilation-error-regexp-alist 'microhs))
+
+(use-package opam-switch-mode ; make emacs mode respect switch
+ :config
+ (when (and (file-exists-p "~/.opam") (executable-find "opam"))
+ (opam-switch-set-switch "default")))
+(use-package tuareg ; ocaml mode
+ :after opam-switch-mode)
+(use-package ocp-indent ; indentation for ocaml
+ :after tuareg
+ :hook (tuareg-mode . ocp-setup-indent))
+(use-package merlin ; ocaml completion
+ :after tuareg
+ :hook (tuareg-mode . merlin-mode)
+ :custom (merlin-command 'opam))
+
+(use-package racket-mode ; basic racket integration
+ )
+
+(use-package sdcv ; dictionary, requires sdcv install
+ :demand t
+ :config
+ (define-prefix-command 'dict-map)
+ (define-keymap :full nil
+ :parent nil
+ :suppress nil
+ :keymap nil
+ :name "dict-map"
+ :prefix 'dict-map
+ (kbd "w") 'sdcv-search-input
+ (kbd "c") (lambda () (interactive)
+ (activate-input-method 'pyim)
+ (sdcv-search-input (read-from-minibuffer "Chinese Word: "
+ nil nil nil
+ nil nil t))
+ (activate-input-method nil)))
+ :bind (:map text-mode-map
+ ("M-l" . 'dict-map)))
+
+(use-package olivetti ; center content per buffer
+ )
+
+;; (use-package erc ; irc client
+;; :init
+;; (defun my/start-erc ()
+;; "Start erc and autojoin various channels"
+;; (interactive)
+;; (erc-tls :server "tccq.net" :port 4095 :nick "tccq"))
+;; :custom
+;; (erc-modules '(services autojoin button completion fill imenu irccontrols list match menu
+;; move-to-prompt netsplit networks readonly ring stamp track))
+;; (erc-nick "tccq")
+;; (erc-use-auth-source-for-nickserv-password t)
+;; (erc-autojoin-channels-alist '(("libera.chat"
+;; "#emacs" "#haskell" "#duskos" "#tcc")))
+
+;; (erc-hide-list '("JOIN" "PART" "QUIT"))
+;; (erc-current-nick-highlight-type 'nick)
+;; (erc-keywords nil)
+;; (erc-track-exclude-types '("JOIN" "PART" "QUIT" "NICK" "MODE"))
+;; (erc-track-use-faces t)
+;; (erc-track-faces-priority-list '(erc-current-nick-face erc-keyword-face))
+;; (erc-track-priority-faces-only 'all))
+
+(use-package minions ; show less on the modeline
+ :demand t
+ :config
+ (minions-mode 1)
+ :custom
+ (minions-prominent-modes '(my/temp-nonmodal-mode persp-mode auto-fill-mode eldoc-mode eglot-mode lsp-mode)))
+
+(use-package ispell ; spellchecker
+ :demand t
+ :custom
+ (ispell-personal-dictionary "/home/tmu/.aspell.en.pws")
+ :config
+ (defun ispell-mode (&optional arg)
+ "Make some old packages work with modern ispell."
+ (interactive)
+ (ispell-minor-mode arg))
+ (advice-add 'ispell-mode :before 'debug)
+ (setq-default text-mode-hook (cons 'ispell-minor-mode (remove 'ispell-mode text-mode-hook))))