From 3a5cdbdb8f1fdd777f0fd8aa69aeaa55379fea64 Mon Sep 17 00:00:00 2001 From: Thomas Ulmer Date: Sun, 22 Mar 2026 20:00:38 -0700 Subject: emacs move to separate files --- config/emacs/site-lisp/my-builtins.el | 200 +++++++++++++++++ config/emacs/site-lisp/my-defines.el | 363 +++++++++++++++++++++++++++++++ config/emacs/site-lisp/my-packages.el | 394 ++++++++++++++++++++++++++++++++++ 3 files changed, 957 insertions(+) create mode 100644 config/emacs/site-lisp/my-builtins.el create mode 100644 config/emacs/site-lisp/my-defines.el create mode 100644 config/emacs/site-lisp/my-packages.el (limited to 'config/emacs/site-lisp') 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) + " +;; 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 " " #'tempel-next) + (keymap-set tempel-map " " #'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)))) -- cgit v1.2.3