summaryrefslogtreecommitdiff
path: root/.config/emacs-old/modules
diff options
context:
space:
mode:
Diffstat (limited to '.config/emacs-old/modules')
-rw-r--r--.config/emacs-old/modules/mm-abbrev.el110
-rw-r--r--.config/emacs-old/modules/mm-buffer-menu.el15
-rw-r--r--.config/emacs-old/modules/mm-calc.el13
-rw-r--r--.config/emacs-old/modules/mm-completion.el256
-rw-r--r--.config/emacs-old/modules/mm-darwin.el30
-rw-r--r--.config/emacs-old/modules/mm-dired.el24
-rw-r--r--.config/emacs-old/modules/mm-documentation.el44
-rw-r--r--.config/emacs-old/modules/mm-editing.el449
-rw-r--r--.config/emacs-old/modules/mm-humanwave.el254
-rw-r--r--.config/emacs-old/modules/mm-keybindings.el188
-rw-r--r--.config/emacs-old/modules/mm-lsp.el45
-rw-r--r--.config/emacs-old/modules/mm-modeline.el147
-rw-r--r--.config/emacs-old/modules/mm-org.el6
-rw-r--r--.config/emacs-old/modules/mm-projects.el114
-rw-r--r--.config/emacs-old/modules/mm-search.el57
-rw-r--r--.config/emacs-old/modules/mm-spellcheck.el24
-rw-r--r--.config/emacs-old/modules/mm-tetris.el20
-rw-r--r--.config/emacs-old/modules/mm-theme.el246
-rw-r--r--.config/emacs-old/modules/mm-treesit.el240
-rw-r--r--.config/emacs-old/modules/mm-window.el72
20 files changed, 2354 insertions, 0 deletions
diff --git a/.config/emacs-old/modules/mm-abbrev.el b/.config/emacs-old/modules/mm-abbrev.el
new file mode 100644
index 0000000..d32ec0d
--- /dev/null
+++ b/.config/emacs-old/modules/mm-abbrev.el
@@ -0,0 +1,110 @@
+;;; mm-abbrev.el --- Emacs abbreviations and templates -*- lexical-binding: t; -*-
+
+;;; Helpers
+
+(defmacro mm-define-abbreviations (table &rest definitions)
+ "Define abbrevations for an abbreviation TABLE.
+Expand abbrev DEFINITIONS for the given TABLE. DEFINITIONS are a
+sequence of either string pairs mapping an abbreviation to its
+expansion, or a string and symbol pair mapping an abbreviation to a
+function.
+
+After adding all abbreviations to TABLE, this macro marks TABLE as
+case-sensitive to avoid unexpected abbreviation expansions."
+ (declare (indent 1))
+ (unless (cl-evenp (length definitions))
+ (user-error "expected an even number of elements in DEFINITIONS"))
+ `(progn
+ ,@(cl-loop for (abbrev expansion) in (seq-partition definitions 2)
+ if (stringp expansion)
+ collect (list #'define-abbrev table abbrev expansion)
+ else
+ collect (list #'define-abbrev table abbrev "" expansion))
+ (abbrev-table-put ,table :case-fixed t)))
+
+
+;;; Abbreviation Configuration
+
+(use-package abbrev
+ :hook prog-mode
+ :custom
+ (abbrev-file-name (expand-file-name "abbev-defs" mm-data-directory))
+ (save-abbrevs 'silently))
+
+
+;;; Abbreviation Definitions
+
+(defvar mm-c-mode-abbrev-table (make-abbrev-table)
+ "Abbreviations shared between `c-mode', `c++-mode', `c-ts-mode', and
+`c++-ts-mode'.")
+
+(mm-define-abbreviations mm-c-mode-abbrev-table
+ "flf" "flockfile"
+ "fpf" "fprintf"
+ "fuf" "funlockfile"
+ "pf" "printf"
+ "sde" "stderr"
+ "sdi" "stdin"
+ "sdo" "stdout")
+
+(with-eval-after-load 'cc-mode
+ (setq c-mode-abbrev-table (copy-abbrev-table mm-c-mode-abbrev-table)
+ c++-mode-abbrev-table (copy-abbrev-table mm-c-mode-abbrev-table)))
+(with-eval-after-load 'c-ts-mode
+ (setq c-ts-mode-abbrev-table (copy-abbrev-table mm-c-mode-abbrev-table)
+ c++-ts-mode-abbrev-table (copy-abbrev-table mm-c-mode-abbrev-table)))
+
+(mm-define-abbreviations emacs-lisp-mode-abbrev-table
+ "ald" ";;;###autoload"
+ "gc" "goto-char"
+ "ins" "insert"
+ "itv" "interactive"
+ "mtb" "match-beginning"
+ "mte" "match-end"
+ "ntr" "narrow-to-region"
+ "pbl" "pos-bol"
+ "pel" "pos-eol"
+ "pmn" "point-min"
+ "pmx" "point-max"
+ "pnt" "point"
+ "rap" "region-active-p"
+ "rb" "region-beginning"
+ "re" "region-end"
+ "rsb" "re-search-backward"
+ "rsf" "re-search-forward"
+ "sb" "search-backward"
+ "se" "save-excursion"
+ "sf" "search-forward"
+ "sme" "save-mark-and-excursion"
+ "sr" "save-restriction")
+
+(when mm-humanwave-p
+ (with-eval-after-load 'python
+ (mm-define-abbreviations python-ts-mode-abbrev-table
+ "empb" "with emphasize.Block():"
+ "empf" "@emphasize.func"
+ "empi" "from shared.system import emphasize"
+ "empt" "emphasize.this")))
+
+
+;;; Template Configuration
+
+(use-package tempel
+ :ensure t
+ :demand t
+ :pin gnu
+ :bind ( :map tempel-map
+ ("TAB" . tempel-next)
+ ("S-TAB" . tempel-previous))
+ :custom
+ (tempel-trigger-prefix "<")
+ :init
+ (setopt tempel-path (expand-file-name "templates" mm-config-directory))
+ (dolist (mode '(conf-mode prog-mode text-mode))
+ (add-hook (mm-mode-to-hook mode)
+ (defun mm-setup-tempel-capf ()
+ (add-hook 'completion-at-point-functions
+ #'tempel-complete -10 :local))))
+ (add-to-list 'auto-mode-alist (cons tempel-path #'lisp-data-mode)))
+
+(provide 'mm-abbrev)
diff --git a/.config/emacs-old/modules/mm-buffer-menu.el b/.config/emacs-old/modules/mm-buffer-menu.el
new file mode 100644
index 0000000..7b725c6
--- /dev/null
+++ b/.config/emacs-old/modules/mm-buffer-menu.el
@@ -0,0 +1,15 @@
+;;; mm-buffer-menu.el --- Buffer Menu configuration -*- lexical-binding: t; -*-
+
+(defun mm-Buffer-menu-delete-all ()
+ "Mark all buffers for deletion."
+ (interactive nil Buffer-menu-mode)
+ (save-excursion
+ (goto-char (point-min))
+ (while (not (eobp))
+ (Buffer-menu-delete))))
+
+(use-package buff-menu
+ :bind ( :map Buffer-menu-mode-map
+ ("D" . mm-Buffer-menu-delete-all)))
+
+(provide 'mm-buffer-menu) \ No newline at end of file
diff --git a/.config/emacs-old/modules/mm-calc.el b/.config/emacs-old/modules/mm-calc.el
new file mode 100644
index 0000000..af45b15
--- /dev/null
+++ b/.config/emacs-old/modules/mm-calc.el
@@ -0,0 +1,13 @@
+;;; mm-calc.el --- Emacs configurations for ‘calc-mode’ -*- lexical-binding: t; -*-
+
+(use-package calc
+ ;; TODO: Can this be done in :custom?
+ :init
+ (setopt
+ calc-display-trail nil
+ calc-group-digits t
+ ;; Optimize for Europeans
+ calc-point-char ","
+ calc-group-char "."))
+
+(provide 'mm-calc) \ No newline at end of file
diff --git a/.config/emacs-old/modules/mm-completion.el b/.config/emacs-old/modules/mm-completion.el
new file mode 100644
index 0000000..3367aa1
--- /dev/null
+++ b/.config/emacs-old/modules/mm-completion.el
@@ -0,0 +1,256 @@
+;;; mm-completion.el --- Configuration for Emacs completion -*- lexical-binding: t; -*-
+
+
+;;; Vertical Completions
+
+(use-package vertico
+ :ensure t
+ :hook after-init
+ :custom
+ (vertico-cycle t)
+ :config
+ (require 'hl-line)
+ ;; When working with ‘file-name-shadow-mode’ enabled, if I shadow old
+ ;; input (i.e.) by typing ‘~/’ after ‘foo/bar’ Vertico will clear the
+ ;; old path to keep only the current input (the old path is hidden by
+ ;; ‘rfn-shadow’ anyways).
+ (with-eval-after-load 'rfn-shadow
+ (add-hook 'rfn-shadow-update-overlay-hook #'vertico-directory-tidy)))
+
+
+;;; Annotate Completions
+
+(use-package marginalia
+ :ensure t
+ :hook after-init
+ :config
+ (with-eval-after-load 'magit
+ (defvar mm-marginalia--magit-cache nil)
+ (add-hook 'minibuffer-setup-hook
+ (lambda () (setq mm-marginalia--magit-cache nil)))
+
+ (defvar-local mm-marginalia-magit-base-branch "master")
+
+ (defface mm-diffstat-counter-added
+ '((t :inherit magit-diffstat-added))
+ "TODO")
+ (defface mm-diffstat-counter-removed
+ '((t :inherit magit-diffstat-removed))
+ "TODO")
+
+ (defun mm-marginalia-populate-magit-cache ()
+ "Batch-fetch all Git branch descriptions and stats into the cache."
+ (setq mm-marginalia--magit-cache (make-hash-table :test #'equal))
+ (when-let ((default-directory (magit-toplevel)))
+ (dolist (line (magit-git-lines "config" "list"))
+ (when (string-match "^branch\\.\\(.*?\\)\\.description=\\(.*\\)$" line)
+ (puthash (match-string 1 line)
+ (list :desc (match-string 2 line) :stats "")
+ mm-marginalia--magit-cache)))
+ (dolist (line (magit-git-lines
+ "for-each-ref"
+ (format
+ "--format=%%(refname:short)\x1F%%(ahead-behind:%s)"
+ mm-marginalia-magit-base-branch)
+ "refs/heads/"))
+ (when (string-match (rx bol (group (1+ (not #x1F)))
+ #x1F (group (1+ digit))
+ " " (group (1+ digit)) eol)
+ line)
+ (let* ((branch (match-string 1 line))
+ (ahead (+ (string-to-number (match-string 2 line))))
+ (behind (- (string-to-number (match-string 3 line))))
+ (ahead-str (if (zerop ahead)
+ ""
+ (propertize (format "%+d" ahead)
+ 'face 'mm-diffstat-counter-added)))
+ (behind-str (if (zerop behind)
+ ""
+ (propertize (format "%+d" behind)
+ 'face 'mm-diffstat-counter-removed)))
+ (stats-str (format "%5s %5s" ahead-str behind-str))
+ (existing (gethash branch mm-marginalia--magit-cache
+ (list :desc "" :stats ""))))
+ (puthash branch (plist-put existing :stats stats-str)
+ mm-marginalia--magit-cache))))))
+
+ (defun mm-marginalia-annotate-magit-branch (cand)
+ "Annotate Git branch CAND with ahead/behind stats and description."
+ (unless mm-marginalia--magit-cache
+ (mm-marginalia-populate-magit-cache))
+ (let* ((data (gethash cand mm-marginalia--magit-cache '(:desc "" :stats "")))
+ (desc (or (plist-get data :desc) ""))
+ (stats (or (plist-get data :stats) "")))
+ (marginalia--fields
+ (stats :width 10)
+ (desc :truncate 1.0 :face 'marginalia-documentation))))
+
+ (add-to-list 'marginalia-annotators
+ '(magit-branch mm-marginalia-annotate-magit-branch builtin none))
+ (dolist (cmd '(magit-branch-and-checkout
+ magit-branch-checkout
+ magit-branch-delete
+ magit-checkout
+ magit-merge
+ magit-rebase-branch))
+ (add-to-list 'marginalia-command-categories (cons cmd 'magit-branch))))
+ :custom
+ (marginalia-field-width 50)
+ (marginalia-max-relative-age 0))
+
+
+;;; Minibuffer Completion Styles
+
+(use-package minibuffer
+ :bind ( :map minibuffer-local-completion-map
+ ("SPC" . nil)
+ ("?" . nil))
+ :custom
+ (completion-styles '(basic substring orderless))
+ (completion-category-defaults nil) ; Avoid needing to override things
+ (completion-category-overrides
+ '((file (styles . (basic partial-completion orderless)))
+ (bookmark (styles . (basic substring)))
+ (library (styles . (basic substring)))
+ (imenu (styles . (basic substring orderless)))
+ (consult-location (styles . (basic substring orderless)))
+ (kill-ring (styles . (basic substring orderless)))))
+ (completion-ignore-case t)
+ (read-buffer-completion-ignore-case t)
+ (read-file-name-completion-ignore-case t))
+
+(use-package orderless
+ :ensure t
+ :after minibuffer
+ :custom
+ (orderless-matching-styles '(orderless-prefixes orderless-regexp)))
+
+
+;;; Disable Minibuffer Recursion Level
+
+(use-package mb-depth
+ :hook (after-init . minibuffer-depth-indicate-mode)
+ :custom
+ (enable-recursive-minibuffers t))
+
+
+;;; Don’t Show Defaults After Typing
+
+;; Usually if a minibuffer prompt has a default value you can access by
+;; hitting RET, the prompt will remain even if you begin typing (meaning
+;; the default will no longer take effect on RET). Enabling this mode
+;; disables that behaviour.
+
+(use-package minibuf-eldef
+ :hook (after-init . minibuffer-electric-default-mode)
+ :custom
+ (minibuffer-default-prompt-format " [%s]"))
+
+
+;;; Hide Shadowed Filepaths
+
+(use-package rfn-eshadow
+ :hook (after-init . file-name-shadow-mode)
+ :custom
+ (file-name-shadow-properties '(invisible t intangilble t)))
+
+
+;;; Completion Popups
+
+(mm-comment
+ (use-package corfu
+ :ensure t
+ :hook prog-mode
+ :bind ( :map corfu-map
+ ("C-<return>" . newline))
+ :custom
+ (corfu-auto t)
+ (corfu-cycle t)
+ (corfu-auto-prefix 1)
+ (corfu-auto-delay .1)
+ (corfu-min-width 20)
+ :config
+ ;; I complete with RET and this interferes with ‘tempel-next’
+ (keymap-unset corfu-map "TAB" :remove)
+ (with-eval-after-load 'savehist
+ (corfu-history-mode)
+ (add-to-list 'savehist-additional-variables 'corfu-history))
+ (with-eval-after-load 'multiple-cursors
+ (add-to-list 'mc/unsupported-minor-modes #'corfu-mode))))
+
+
+;;; Save Minibuffer History
+
+(use-package savehist-mode
+ :hook (after-init . savehist-mode)
+ :custom
+ (history-length 200)
+ (history-delete-duplicates t)
+ :config
+ (add-to-list 'savehist-additional-variables 'kill-ring))
+
+
+;;; Enhanced Replacements for Builtins
+
+;; TODO: Investigate other commands
+(use-package consult
+ :ensure t
+ :hook (completion-list-mode . consult-preview-at-point-mode)
+ :bind ( ([remap switch-to-buffer] . consult-buffer)
+ ([remap imenu] . consult-imenu)
+ ([remap goto-line] . consult-goto-line)
+ ("M-F" . consult-focus-lines)
+ :map project-prefix-map
+ ("b" . consult-project-buffer)
+ :map consult-narrow-map
+ ("?" . consult-narrow-help))
+ :custom
+ (consult-find-args
+ (string-join
+ '("find . -not ("
+ " -path '*/.git*' -prune"
+ " -or -path '*/vendor/*' -prune"
+ ")")
+ " ")))
+
+
+;;; Dynamic Abbreviations
+
+(use-package dabbrev
+ :commands (dabbrev-completion dabbrev-expand)
+ :custom
+ (dabbrev-upcase-means-case-search t))
+
+
+;;; Finding Things
+
+(use-package find-func
+ :custom
+ (find-library-include-other-files nil))
+
+
+;;; Completion at Point Functions
+
+(defun mm-cape-file--not-dot-path-p (cand)
+ (declare (ftype (function (string) boolean))
+ (pure t) (side-effect-free t))
+ (not (or (string= cand "./")
+ (string= cand "../"))))
+
+(use-package cape
+ :ensure t
+ :init
+ (add-hook 'completion-at-point-functions
+ (cape-capf-predicate #'cape-file #'mm-cape-file--not-dot-path-p))
+ (add-hook 'completion-at-point-functions
+ (cape-capf-prefix-length #'cape-dabbrev 3)))
+
+
+;;; Completion at Point Live Completions
+
+(use-package completion-preview
+ :hook (after-init . global-completion-preview-mode)
+ :custom
+ (completion-preview-minimum-symbol-length 1))
+
+(provide 'mm-completion)
diff --git a/.config/emacs-old/modules/mm-darwin.el b/.config/emacs-old/modules/mm-darwin.el
new file mode 100644
index 0000000..90dbedd
--- /dev/null
+++ b/.config/emacs-old/modules/mm-darwin.el
@@ -0,0 +1,30 @@
+;;; mm-darwin.el --- MacOS Configuration -*- lexical-binding: t; -*-
+
+(unless (featurep 'ns)
+ (error "'NS not available. Something has gone horribly wrong."))
+
+
+;;; Launch Emacs Properly
+
+(defun mm-ns-raise-emacs ()
+ (ns-do-applescript "tell application \"Emacs\" to activate"))
+
+(add-hook
+ 'after-make-frame-functions
+ (defun mm-ns-raise-emacs-with-frame (frame)
+ (when (display-graphic-p)
+ (with-selected-frame frame
+ (mm-ns-raise-emacs)))))
+
+(when (display-graphic-p)
+ (mm-ns-raise-emacs))
+
+
+;;; Set Modifier Keys
+
+(setopt mac-option-key-is-meta nil
+ mac-command-key-is-meta t)
+(setopt mac-option-modifier 'none
+ mac-command-modifier 'meta)
+
+(provide 'mm-darwin)
diff --git a/.config/emacs-old/modules/mm-dired.el b/.config/emacs-old/modules/mm-dired.el
new file mode 100644
index 0000000..9e78466
--- /dev/null
+++ b/.config/emacs-old/modules/mm-dired.el
@@ -0,0 +1,24 @@
+;;; mm-dired.el --- Configure the directory editor -*- lexical-binding: t; -*-
+
+(use-package dired
+ :hook ((dired-mode . dired-omit-mode)
+ (dired-mode . dired-hide-details-mode))
+ :bind ( :map dired-mode-map
+ ("f" . find-file))
+ :custom
+ (dired-auto-revert-buffer #'dired-directory-changed-p)
+ (dired-dwim-target t)
+ (dired-free-space nil)
+ (dired-recursive-copies 'always)
+ (dired-recursive-deletes 'always)
+ (dired-listing-switches
+ (combine-and-quote-strings
+ '("-AFGhlv" "--group-directories-first" "--time-style=+%d %b %Y %T"))))
+
+(use-package dired-aux
+ :custom
+ (dired-create-destination-dirs 'ask)
+ (dired-create-destination-dirs-on-trailing-dirsep t)
+ (dired-isearch-filenames 'dwim))
+
+(provide 'mm-dired) \ No newline at end of file
diff --git a/.config/emacs-old/modules/mm-documentation.el b/.config/emacs-old/modules/mm-documentation.el
new file mode 100644
index 0000000..1bd94da
--- /dev/null
+++ b/.config/emacs-old/modules/mm-documentation.el
@@ -0,0 +1,44 @@
+;;; mm-documentation.el --- Configuration related to documentation -*- lexical-binding: t; -*-
+
+;;; Enhance Describe Commands
+
+(use-package helpful
+ :ensure t
+ :bind (([remap describe-command] . helpful-command)
+ ([remap describe-function] . helpful-callable)
+ ([remap describe-key] . helpful-key)
+ ([remap describe-symbol] . helpful-symbol)
+ ([remap describe-variable] . helpful-variable)
+ (("C-h C-p" . helpful-at-point))))
+
+
+;;; Open Manpage for Symbol
+
+(defun mm-documentation-man-at-point ()
+ "Open a UNIX manual page for the symbol at point."
+ (declare (modes (c-mode c++-mode c-ts-mode c++-ts-mode)))
+ (interactive)
+ (if-let ((symbol
+ (pcase major-mode
+ ((or 'c-mode 'c++-mode)
+ (thing-at-point 'symbol :no-properties))
+ ((or 'c-ts-mode 'c++-ts-mode)
+ (when-let ((node (treesit-thing-at-point "identifier" 'nested)))
+ (treesit-node-text node :no-properties))))))
+ (man symbol)
+ (message "No symbol at point.")))
+
+
+;;; Browse RFC Pages
+
+(use-package rfc-mode
+ :ensure t
+ :custom
+ (rfc-mode-directory (expand-file-name "rfc" (xdg-user-dir "DOCUMENTS")))
+ :config
+ (unless (featurep 'consult)
+ (keymap-set rfc-mode-map "g" #'imenu))
+ (with-eval-after-load 'consult
+ (keymap-set rfc-mode-map "g" #'consult-imenu)))
+
+(provide 'mm-documentation) \ No newline at end of file
diff --git a/.config/emacs-old/modules/mm-editing.el b/.config/emacs-old/modules/mm-editing.el
new file mode 100644
index 0000000..24aa7ea
--- /dev/null
+++ b/.config/emacs-old/modules/mm-editing.el
@@ -0,0 +1,449 @@
+;;; mm-editing.el --- Text editing configuation -*- lexical-binding: t; -*-
+
+;;; Delete Region When Typing
+
+(use-package delsel
+ :hook (after-init . delete-selection-mode))
+
+
+;;; Capitalize ‘ß’ into ‘ẞ’
+
+;; https://lists.gnu.org/archive/html/bug-gnu-emacs/2024-11/msg00030.html
+(set-case-syntax-pair ?ẞ ?ß (standard-case-table))
+(put-char-code-property ?ß 'special-uppercase nil)
+
+
+;;; Force Spaces For Alignment
+
+(defun mm-editing-force-space-indentation (function &rest arguments)
+ "Call FUNCTION with ARGUMENTS in an environment in which
+`indent-tabs-mode' is nil."
+ (let (indent-tabs-mode)
+ (apply function arguments)))
+
+(dolist (command #'(align-region
+ c-backslash-region
+ comment-dwim
+ makefile-backslash-region
+ sh-backslash-region))
+ (advice-add command :around #'mm-editing-force-space-indentation))
+
+
+;;; Recenter The Screen When Jumping
+
+(mm-comment
+ (dolist (command #'(backward-page
+ backward-paragraph
+ forward-page
+ forward-paragraph
+ pop-global-mark))
+ (advice-add command :around #'mm-do-and-center)))
+
+
+;;; Indentation Settings
+
+(setq-default
+ tab-width 4
+ indent-tabs-mode (not mm-humanwave-p))
+
+(defvar mm-editing-indentation-settings-alist
+ '((awk-ts-mode . (:extras awk-ts-mode-indent-level))
+ (c-mode . (:extras c-basic-offset))
+ (c-ts-mode . (:extras c-ts-mode-indent-offset))
+ (css-mode . (:extras css-indent-offset))
+ (elixir-ts-mode . (:width 2 :extras elixir-ts-indent-offset))
+ (emacs-lisp-mode . (:width 8 :spaces t)) ; GNU code uses 8-column tabs
+ (go-mod-ts-mode . (:extras go-ts-mode-indent-offset))
+ (go-ts-mode . (:extras go-ts-mode-indent-offset))
+ (gsp-ts-mode . (:width 2 :extras gsp-ts-mode-indent-rules))
+ (helpful-mode . (:width 8)) ; GNU code uses 8-column tabs
+ (json-ts-mode . (:extras json-ts-mode-indent-offset))
+ (latex-mode . (:width 2))
+ (lisp-data-mode . (:spaces t))
+ (lisp-interaction-mode . (:spaces t))
+ (lisp-mode . (:spaces t))
+ (mhtml-mode . (:extras sgml-basic-offset))
+ (org-mode . (:width 8 :spaces t))
+ (python-mode . (:extras python-indent-offset))
+ (python-ts-mode . (:extras python-indent-offset))
+ (sgml-mode . (:extras sgml-basic-offset))
+ (sh-mode . (:extras sh-basic-offset))
+ (sql-mode . (:extras sqlind-basic-offset))
+ (tex-mode . (:width 2))
+ (typescript-ts-mode . (:extras typescript-ts-mode-indent-offset))
+ (vimscript-ts-mode . (:extras vimscript-ts-mode-indent-level))
+ (vue-ts-mode . (:extras (typescript-ts-mode-indent-offset
+ vue-ts-mode-indent-offset))))
+ "Alist of indentation settings.
+Each pair in this alist is of the form (MODE . SETTINGS) where MODE
+specifies the mode for which the given SETTINGS should apply.
+
+SETTINGS is a plist of one-or-more of the following keys:
+
+ `:spaces' -- If nil force tabs for indentation, if non-nil for spaces
+ for indentation. If this key is not provided then the
+ value of `indent-tabs-mode' is used.
+ `:width' -- Specifies a non-negative number to be used as the tab
+ width and indentation offset. If this key is not
+ provided then the default value of `tab-width' is used.
+ `:extras' -- A list of mode-specific variables which control
+ indentation settings that need to be set for
+ configurations to properly be applied.")
+
+(defun mm-editing-set-indentation-settings ()
+ "Set indentation settings for the current major mode.
+The indentation settings are set based on the configured values in
+`mm-editing-indentation-settings-alist'."
+ (let* ((plist (alist-get major-mode mm-editing-indentation-settings-alist))
+ (spaces (plist-member plist :spaces))
+ (width (plist-member plist :width))
+ (extras (plist-member plist :extras)))
+ ;; Some modes like ‘python-mode’ explicitly set ‘tab-width’ and
+ ;; ‘indent-tabs-mode’ so we must override them explicitly.
+ (setq-local indent-tabs-mode (if spaces (not (cadr spaces))
+ (default-value 'indent-tabs-mode))
+ tab-width (or (cadr width) (default-value 'tab-width)))
+ (when extras
+ (setq extras (cadr extras))
+ (when (symbolp extras)
+ (setq extras (list extras)))
+ (dolist (extra extras)
+ (set extra tab-width)))))
+
+(add-hook 'after-change-major-mode-hook #'mm-editing-set-indentation-settings)
+
+(defun mm-editing-set-tabsize ()
+ "Set the tabsize for the current buffer.
+If the current buffer’s major mode requires setting additional variables,
+those should be listed in `mm-editing-indentation-settings'."
+ (interactive)
+ (let* ((prompt-default (default-value 'tab-width))
+ (prompt (format-prompt "Tabsize" prompt-default))
+ (tabsize (mm-as-number (read-string prompt nil nil prompt-default))))
+ (setq-local tab-width tabsize)
+ (when-let* ((plist (alist-get major-mode mm-editing-indentation-settings))
+ (extras (plist-get plist :extras)))
+ (dolist (extra (if (symbolp extras)
+ (list extras)
+ extras))
+ (set (make-local-variable extra) tabsize)))))
+
+(use-package sh-mode
+ :custom
+ (sh-indent-for-case-label 0)
+ (sh-indent-for-case-alt #'+))
+
+
+;;; Code Commenting
+
+(defun mm-newcomment-c-config ()
+ (setq-local comment-continue " "))
+
+(defun mm-newcomment-html-config ()
+ (setq-local comment-continue " "))
+
+(defun mm-newcomment-rust-config ()
+ (setq-local comment-start "/* "
+ comment-end " */"
+ comment-continue " * " ; rustfmt doesn’t play nice
+ comment-quote-nested nil))
+
+(use-package newcomment
+ :custom
+ (comment-style 'multi-line)
+ :config
+ (dolist (mode '(c-mode c++-mode))
+ (add-hook (mm-mode-to-hook mode) #'mm-newcomment-c-config)
+ (when-let ((ts-mode (mm-mode-to-ts-mode mode))
+ ((fboundp ts-mode)))
+ (add-hook (mm-mode-to-hook ts-mode) #'mm-newcomment-c-config)))
+ (add-hook 'mhtml-mode-hook #'mm-newcomment-html-config)
+ (add-hook 'rust-ts-mode-hook #'mm-newcomment-rust-config))
+
+
+;;; Multiple Cursors
+
+(defmacro mm--define-mc-marking-command (name search-function noun)
+ (let ((noun-symbol (intern noun)))
+ `(defun ,name (beg end ,noun-symbol)
+ ,(format "Mark all occurances of %s between BEG and END.
+If called interactively with an active region then all matches in the
+region are marked, otherwise all matches in the buffer are marked."
+ (upcase noun))
+ (interactive
+ (list (or (use-region-beginning) (point-min))
+ (or (use-region-end) (point-max))
+ (read-string
+ (format-prompt ,(concat "Match " noun) nil))))
+ (if (string-empty-p ,noun-symbol)
+ (message "Command aborted")
+ (catch 'mm--no-match
+ (mc/remove-fake-cursors)
+ (goto-char beg)
+ (let (did-match-p)
+ (while (,search-function ,noun-symbol end :noerror)
+ (setq did-match-p t)
+ (push-mark (match-beginning 0))
+ (exchange-point-and-mark)
+ (mc/create-fake-cursor-at-point)
+ (goto-char (mark)))
+ (unless did-match-p
+ (message "No match for `%s'" ,noun-symbol)
+ (throw 'mm--no-match nil)))
+ (when-let ((first (mc/furthest-cursor-before-point)))
+ (mc/pop-state-from-overlay first))
+ (if (> (mc/num-cursors) 1)
+ (multiple-cursors-mode 1)
+ (multiple-cursors-mode 0)))))))
+
+(mm--define-mc-marking-command
+ mm-mark-all-in-region search-forward "string")
+(mm--define-mc-marking-command
+ mm-mark-all-in-region-regexp re-search-forward "regexp")
+
+(mm-comment
+ (defun mm-silent-mc-load (args)
+ "Advice to `load' to force it to be silent.
+The `multiple-cursors' package loads an `.mc-lists.el' file without
+passing `:nomessage' which causes messages to be sent in the minibuffer
+and *Messages* buffer. This forces that to not happen."
+ (when (and (boundp 'mc/list-file)
+ (string= (file-truename (car args))
+ (file-truename mc/list-file)))
+ (pcase (length args)
+ (1 (setq args (list (car args) nil :nomessage)))
+ (2 (add-to-list 'args :nomessage :append))
+ (_ (setf (caddr args) :nomessage)))
+ (advice-remove #'load #'mm-silent-mc-load))
+ args))
+
+(use-package multiple-cursors
+ :ensure t
+ :demand t
+ :bind (("C->" . #'mc/mark-next-like-this)
+ ("C-<" . #'mc/mark-previous-like-this)
+ ("C-M-<" . #'mc/mark-all-like-this-dwim)
+ ("C-M->" . #'mc/edit-lines)
+ :map search-map
+ ("$" . #'mm-mark-all-in-region)
+ ("M-$" . #'mm-mark-all-in-region-regexp))
+ :commands ( mm-mark-all-in-region mm-mark-all-in-region-regexp
+ mm-add-cursor-to-next-thing mm-transpose-cursor-regions)
+ :init
+ (mm-comment
+ (advice-add #'load :filter-args #'mm-silent-mc-load)
+ (with-eval-after-load 'multiple-cursors-core
+ (dolist (command #'(backward-delete-char
+ capitalize-dwim
+ delete-backward-char
+ delete-forward-char
+ downcase-dwim
+ upcase-dwim))
+ (add-to-list 'mc/cmds-to-run-for-all command))
+ (dolist (command #'(helpful-callable
+ helpful-key
+ helpful-symbol
+ helpful-variable))
+ (add-to-list 'mc/cmds-to-run-once command))))
+ (with-eval-after-load 'multiple-cursors-core
+ (keymap-unset mc/keymap "<return>" :remove)))
+
+
+;;; Increment Numbers
+
+(use-package increment
+ :bind (("C-c i i" . #'increment-number-at-point)
+ ("C-c i d" . #'decrement-number-at-point))
+ :commands (increment-number-at-point decrement-number-at-point))
+
+
+;;; Move Line or Region
+
+(defun mm-move-text-indent (&rest _)
+ (let ((deactivate deactivate-mark))
+ (if (region-active-p)
+ (indent-region (region-beginning) (region-end))
+ (indent-region (line-beginning-position) (line-end-position)))
+ (setq deactivate-mark deactivate)))
+
+(use-package move-text
+ :ensure t
+ :bind (("M-n" . move-text-down)
+ ("M-p" . move-text-up))
+ :config
+ (dolist (command #'(move-text-up move-text-down))
+ (advice-add command :after #'mm-move-text-indent)))
+
+
+;;; Surround With Delimeters
+
+(defun mm-editing-surround-with-spaces (char)
+ "Surrounds region or current symbol with a pair defined by CHAR.
+This is the same as `surround-insert' except it pads the contents of the
+surround with spaces."
+ (interactive
+ (list (char-to-string (read-char "Character: "))))
+ (let* ((pair (surround--make-pair char))
+ (left (car pair))
+ (right (cdr pair))
+ (bounds (surround--infer-bounds t)))
+ (save-excursion
+ (goto-char (cdr bounds))
+ (insert " " right)
+ (goto-char (car bounds))
+ (insert left " "))
+ (when (eq (car bounds) (point))
+ (forward-char))))
+
+;; TODO: Implement this manually
+(use-package surround
+ :ensure t
+ :bind-keymap ("M-'" . surround-keymap)
+ :bind (:map surround-keymap
+ ("S" . #'mm-editing-surround-with-spaces))
+ :config
+ (dolist (pair '(("‘" . "’")
+ ("“" . "”")
+ ("»" . "«")
+ ("⟮" . "⟯")))
+ (push pair surround-pairs))
+ (make-variable-buffer-local 'surround-pairs)
+ (add-hook 'emacs-lisp-mode-hook
+ (defun mm-editing-add-elisp-quotes-pair ()
+ (push '("`" . "'") surround-pairs))))
+
+
+;;; Insert Webpage Contents
+
+(defun mm-insert-from-url (url)
+ "Insert the contents of URL at point."
+ (interactive
+ (let ((url-at-point (thing-at-point 'url)))
+ (list (read-string
+ (format-prompt "URL" url-at-point)
+ nil nil url-at-point))))
+ (call-process "curl" nil '(t nil) nil url))
+
+
+;;; Emmet Mode
+
+(defun mm-editing-emmet-dwim (arg)
+ "Do-What-I-Mean Emmet expansion.
+If the region is active then the region will be surrounded by an emmet
+expansion read from the minibuffer. Otherwise the emmet expression
+before point is expanded. When provided a prefix argument the behaviour
+is as described by `emmet-expand-line'."
+ (interactive "P")
+ (if (region-active-p)
+ (call-interactively #'emmet-wrap-with-markup)
+ (emmet-expand-line arg)))
+
+(use-package emmet-mode
+ :ensure t
+ :bind ("C-," . mm-editing-emmet-dwim)
+ :custom
+ (emmet-self-closing-tag-style ""))
+
+
+;;; JQ Manipulation in JSON Mode
+
+(defun mm-jq-filter (query &optional beg end)
+ "TODO"
+ (interactive
+ (list
+ (read-string (format-prompt "Query" nil))
+ (when (use-region-p) (region-beginning))
+ (when (use-region-p) (region-end))))
+ (let* ((beg (or beg (point-min)))
+ (end (or end (point-max)))
+ (temp-buffer (generate-new-buffer "* jq temp*"))
+ (exit-code (call-process-region beg end "jq" nil temp-buffer nil
+ "--tab" query))
+ (output (with-current-buffer temp-buffer (buffer-string))))
+ (if (zerop exit-code)
+ (atomic-change-group
+ (delete-region beg end)
+ (insert output)
+ (indent-region beg (point)))
+ (message "%s" output))
+ (kill-buffer temp-buffer)))
+
+(use-package json-ts-mode
+ :bind ( :map json-ts-mode-map
+ ("C-|" . #'mm-jq-filter))
+ :config
+ (require 'live-jq))
+
+
+;;; Number Formatting
+
+(use-package number-format-mode
+ :commands ( number-format-buffer number-format-region
+ number-unformat-buffer number-unformat-region
+ number-format-mode))
+
+
+;;; Additional Major Modes
+
+(use-package awk-ts-mode :ensure t)
+(use-package cmake-mode :ensure t)
+(use-package git-modes :ensure t)
+(use-package kdl-mode :ensure t)
+(use-package po-mode :ensure t)
+(use-package sed-mode :ensure t)
+
+(use-package csv-mode
+ :ensure t
+ :custom
+ (csv-align-style 'auto)
+ (csv-align-padding 2))
+
+(use-package xcompose-mode
+ :vc ( :url "https://git.thomasvoss.com/xcompose-mode"
+ :branch "master"
+ :rev :newest
+ :vc-backend Git)
+ :ensure t)
+
+(use-package yaml-pro
+ :hook ((yaml-mode . yaml-pro-mode)
+ (yaml-ts-mode . yaml-pro-ts-mode)))
+
+
+;;; Mode-Specific Configurations
+
+(use-package make-mode
+ :custom
+ (makefile-backslash-column 80))
+
+(use-package python-mode
+ :custom
+ (python-indent-def-block-scale 1)
+ (python-indent-guess-indent-offset-verbose nil))
+
+
+;;; Add Missing Extensions
+
+(dolist (pattern '("\\.tmac\\'" "\\.mom\\'"))
+ (add-to-list 'auto-mode-alist (cons pattern #'nroff-mode)))
+
+
+;;; Subword Navigation
+
+(use-package subword
+ :hook prog-mode)
+
+
+;;; Edit Files via Doas/Sudo
+
+(defvar mm-root-editing-program
+ (if (string= (system-name) "mangobox") "doas" "sudo"))
+
+(defun mm-edit-root-protected-file-buffer ()
+ (interactive)
+ (when (and buffer-file-name (not (file-writable-p buffer-file-name)))
+ (find-alternate-file (format "/%s:root@localhost:%s"
+ mm-root-editing-program
+ buffer-file-name))))
+
+(provide 'mm-editing)
diff --git a/.config/emacs-old/modules/mm-humanwave.el b/.config/emacs-old/modules/mm-humanwave.el
new file mode 100644
index 0000000..d52546e
--- /dev/null
+++ b/.config/emacs-old/modules/mm-humanwave.el
@@ -0,0 +1,254 @@
+;;; mm-humanwave.el --- Humanwave extras -*- lexical-binding: t; -*-
+
+
+;;; Query the Backend
+
+(defvar mm--humanwave-query-history nil
+ "History for endpoints given to `mm-humanwave-query'.")
+
+(defun mm-humanwave-query (endpoint &optional method)
+ "Query and display the result of an HTTP reqiest on ENDPOINT.
+If METHOD is nil, a GET request is performed."
+ (interactive
+ (let* ((query (read-string (format-prompt "Query" nil)
+ (car-safe mm--humanwave-query-history)
+ 'mm--humanwave-query-history))
+ (parts (string-split (string-trim query) " " :omit-nulls)))
+ (when (length> parts 2)
+ (user-error "Queries must be of the form `METHOD ENDPOINT' or `ENDPOINT'."))
+ (nreverse parts)))
+ (let* ((project-root (project-root (project-current :maybe-prompt)))
+ (qry-path (expand-file-name "qry" project-root))
+ extras)
+ (unless (file-executable-p qry-path)
+ (user-error "No `qry' executable found in the project root"))
+ (let ((output-buffer (get-buffer-create "*Query Response*")))
+ (with-current-buffer output-buffer
+ (delete-region (point-min) (point-max))
+ (call-process qry-path nil t nil
+ (string-trim endpoint) "-X" (or method "GET"))
+ (unless (eq major-mode 'json-ts-mode)
+ (json-ts-mode))
+ (goto-char (point-min)))
+ (display-buffer output-buffer))))
+
+
+;;; IMenu Support for Handlers
+
+(require 'imenu)
+(require 'which-func)
+
+(defvar mm-humanwave-handler--regexp
+ (rx bol
+ (* blank)
+ (or "if" "elif")
+ (* blank)
+ (or "dialog" "topic" "schedule")
+ (* blank)
+ "=="
+ (* blank)
+ (or ?\' ?\")
+ (group (+ (not (or ?\' ?\"))))
+ (or ?\' ?\")
+ (* blank)
+ ?:
+ (* blank)
+ eol))
+
+(defun mm-humanwave-handler--insert-entry (topic-index function-parts route pos)
+ (if (null function-parts)
+ (cons (cons (format "%s (route)" route) pos) topic-index)
+ (let* ((current-group (car function-parts))
+ (rest-parts (cdr function-parts))
+ (existing-sublist (assoc current-group topic-index)))
+ (if existing-sublist
+ (progn
+ (setcdr existing-sublist
+ (mm-humanwave-handler--insert-entry
+ (cdr existing-sublist) rest-parts route pos))
+ topic-index)
+ (cons (cons current-group
+ (mm-humanwave-handler--insert-entry
+ nil rest-parts route pos))
+ topic-index)))))
+
+(defun mm-humanwave-handler-topic-imenu-index ()
+ (let ((case-fold-search nil)
+ (tree-index (python-imenu-treesit-create-index))
+ (topic-index '()))
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward mm-humanwave-handler--regexp nil :noerror)
+ (let ((route (match-string-no-properties 1))
+ (pos (match-beginning 0))
+ (function-parts (split-string (which-function) "\\.")))
+ (setq topic-index (mm-humanwave-handler--insert-entry
+ topic-index function-parts route pos)))))
+ (append (nreverse topic-index) tree-index)))
+
+(defun mm-humanwave-handler-topic-imenu-setup ()
+ "Setup custom imenu index for `python-ts-mode'."
+ (when (and (string-match-p "/handlers?/" (or (buffer-file-name) ""))
+ (derived-mode-p #'python-ts-mode))
+ (setq-local imenu-create-index-function
+ #'mm-humanwave-handler-topic-imenu-index)))
+
+(add-hook 'after-change-major-mode-hook
+ #'mm-humanwave-handler-topic-imenu-setup)
+
+
+;;; Insert Imports in Vue
+
+(defun mm-humanwave-insert-vue-import-path (base-directory target-file)
+ "Insert an import directive at POINT.
+The import directive imports TARGET-FILE relative from BASE-DIRECTORY.
+When called interactively BASE-DIRECTORY is the directory of the current
+open Vue file and TARGET-FILE is a file in the current project that is
+queried interactively.
+
+When called interactively the prefix argument can be used to emulate the
+behaviour of the INCLUDE-ALL-P argument to `mm-project-read-file-name'."
+ (interactive
+ (list
+ default-directory
+ (mm-humanwave-project-read-file-name current-prefix-arg)))
+ (let ((path (file-name-sans-extension
+ (file-relative-name target-file base-directory))))
+ (unless (string-match-p "/" path)
+ (setq path (concat "./" path)))
+ (insert "import ")
+ (save-excursion
+ (insert (thread-last
+ (file-name-base path)
+ (mm-string-split "-")
+ (mapconcat #'capitalize)))
+ (push-mark (point))
+ (insert (format " from '%s';" path)))))
+
+(defun mm-humanwave-project-read-file-name (&optional include-all-p)
+ "Prompt for a project file.
+This function is similar to `project-find-file', but it returns the path
+to the selected file instead of opening it.
+
+When called interactively the selected file is printed to the minibuffer,
+otherwise it is returned.
+
+The prefix argument INCLUDE-ALL-P is the same as the INCLUDE-ALL argument
+to the `project-find-file' command."
+ (interactive "P")
+ (let* ((project (project-current :maybe-prompt))
+ (root (project-root project))
+ (files (if include-all-p
+ (let ((vc-ignores (mapcar
+ (lambda (dir) (concat dir "/"))
+ vc-directory-exclusion-list)))
+ (project--files-in-directory root vc-ignores))
+ (project-files project)))
+ (canditates (mapcar (lambda (f) (file-relative-name f root))
+ files))
+ (table (lambda (string predicate action)
+ (if (eq action 'metadata)
+ '(metadata (category . file))
+ (complete-with-action action canditates string predicate))))
+ (default-directory root)
+ (choice (completing-read (format-prompt "Find project file" nil)
+ table nil :require-match)))
+ (let ((path (expand-file-name choice root)))
+ (if (called-interactively-p 'any)
+ (message "%s" path)
+ path))))
+
+(defun mm-humanwave-insert-last-commit-message ()
+ "TODO"
+ (interactive)
+ (insert
+ (with-temp-buffer
+ (call-process "git" nil t nil "log" "-1" "--pretty=%s")
+ (goto-char (point-min))
+ (replace-regexp "\\`HW-[0-9]+ " "")
+ (string-trim (buffer-string)))))
+
+
+;;; Jira Integration
+
+(use-package jira
+ :ensure t
+ :custom
+ (jira-api-version 3)
+ (jira-base-url "https://humanwave.atlassian.net")
+ (jira-detail-show-announcements nil)
+ (jira-issues-max-results 100)
+ (jira-issues-table-fields '(:key :status-name :assignee-name :summary))
+ (jira-token-is-personal-access-token nil))
+
+
+;;; Icon Autocompletion
+
+(defvar mm-humanwave-icon-component-file "web/src/components/icon.vue"
+ "Path to the <icon /> component definition.")
+
+(defun mm-humanwave--find-icon-map ()
+ (let* ((project (project-current :maybe-prompt))
+ (path (expand-file-name mm-humanwave-icon-component-file
+ (project-root project))))
+ (unless (file-exists-p path)
+ (user-error "File `%s' does not exist." path))
+ (with-current-buffer (find-file-noselect path)
+ (let* ((parser (treesit-parser-create 'typescript))
+ (root-node (treesit-parser-root-node parser))
+ (query `((((lexical_declaration
+ (variable_declarator
+ name: (identifier) @name)) @the_catch)
+ (:equal @name "ICON_MAP"))
+ (((variable_declaration
+ (variable_declarator
+ name: (identifier) @name)) @the_catch)
+ (:equal @name "ICON_MAP"))))
+ (captures (treesit-query-capture root-node query))
+ (found-node (alist-get 'the_catch captures)))
+ found-node))))
+
+(defun mm-humanwave--icon-list (found-node)
+ (let ((captures (treesit-query-capture found-node '((pair) @the_pair)))
+ (pairs nil))
+ (when captures
+ (dolist (capture captures)
+ (let* ((pair-node (cdr capture))
+ (key-node (treesit-node-child-by-field-name pair-node "key"))
+ (val-node (treesit-node-child-by-field-name pair-node "value")))
+ (when (and key-node val-node)
+ (push (cons (mm-camel-to-lisp
+ (treesit-node-text key-node :no-property))
+ (treesit-node-text val-node :no-property))
+ pairs))))
+ (sort pairs :key #'car :lessp #'string<))))
+
+(defun mm-humanwave-insert-icon-component ()
+ "Insert an icon at point with completion.
+
+This command provides completion for the available props that can be
+given to the <icon /> component. The parser searches for the `ICON_MAP'
+definition in the file specified by `mm-humanwave-icon-component-file'."
+ (interactive "" vue-ts-mode)
+ (if-let* ((node (mm-humanwave--find-icon-map))
+ (alist (mm-humanwave--icon-list node)))
+ (let* ((max-key-width
+ (thread-last
+ alist
+ (mapcar (lambda (pair) (length (car pair))))
+ (apply #'max)
+ (+ 4)))
+ (completion-extra-properties
+ `(:annotation-function
+ ,(lambda (key)
+ (concat
+ (propertize " "
+ 'display `(space :align-to ,max-key-width))
+ (propertize (cdr (assoc key alist))
+ 'face 'font-lock-string-face)))))
+ (prompt (format-prompt "Icon" nil))
+ (icon (completing-read prompt alist nil :require-match)))
+ (insert (format "<icon %s />" icon)))
+ (error "Unable to find ICON_MAP definitions")))
+
+(provide 'mm-humanwave)
diff --git a/.config/emacs-old/modules/mm-keybindings.el b/.config/emacs-old/modules/mm-keybindings.el
new file mode 100644
index 0000000..1480451
--- /dev/null
+++ b/.config/emacs-old/modules/mm-keybindings.el
@@ -0,0 +1,188 @@
+;;; mm-keybindings.el --- Emacs keybindings -*- lexical-binding: t; -*-
+
+(require 'editing)
+
+;; The following keys are either unbound and are free to populate, or are
+;; bound to functions I don’t care for:
+;; ‘C-i’, ‘C-j’, ‘C-o’, ‘C-{’, ‘C-}’, ‘C-|’, ‘C-/’, ‘C-\;’, ‘C-:’
+
+
+;;; Helper Macros
+
+(defmacro mm-keymap-set (keymap &rest definitions)
+ (declare (indent 1))
+ (unless (cl-evenp (length definitions))
+ (user-error "Expected an even-number of elements in DEFINITIONS."))
+ `(cl-loop for (from to) on (list ,@definitions) by #'cddr
+ do (keymap-set ,keymap from to)))
+
+(defmacro mm-keymap-set-repeating (keymap &rest definitions)
+ (declare (indent 1))
+ (unless (cl-evenp (length definitions))
+ (user-error "Expected an even-number of elements in DEFINITIONS."))
+ (let ((keymap-gen (gensym "mm-keybindings--repeat-map-")))
+ `(progn
+ (defvar-keymap ,keymap-gen)
+ (cl-loop for (from to) on (list ,@definitions) by #'cddr
+ do (progn
+ (keymap-set ,keymap-gen from to)
+ (put to 'repeat-map ',keymap-gen))))))
+
+(defmacro mm-keymap-remap (keymap &rest commands)
+ "Define command remappings for a given KEYMAP.
+COMMANDS is a sequence of unquoted commands. For each pair of COMMANDS
+the first command is remapped to the second command."
+ (declare (indent 1))
+ (unless (cl-evenp (length commands))
+ (user-error "Expected an even-number of elements in COMMANDS."))
+ (macroexp-progn
+ (cl-loop for (from to) in (seq-partition commands 2)
+ collect `(keymap-set
+ ,keymap
+ ,(concat "<remap> <" (symbol-name from) ">")
+ #',to))))
+
+
+;;; Support the Kitty Keyboard Protocol
+
+(use-package kkp
+ :ensure t
+ :unless (or (display-graphic-p) mm-humanwave-p)
+ :hook (tty-setup . global-kkp-mode))
+
+
+;;; Support QMK Hyper
+
+(defun mm-qmk-hyper-as-hyper (args)
+ (let ((chord (cadr args)))
+ (when (string-prefix-p "H-" chord)
+ (setf (cadr args) (concat "C-M-S-s" (substring chord 1)))))
+ args)
+
+;; Both ‘keymap-global-set’ and ‘keymap-local-set’ call ‘keymap-set’
+;; internally, so this advice covers all cases
+(advice-add #'keymap-set :filter-args #'mm-qmk-hyper-as-hyper)
+
+
+;;; Disable ESC as Meta
+
+(keymap-global-set "<escape>" #'ignore)
+
+
+;;; Enable Repeat Bindings
+
+(defun mm-enable-repeat-mode ()
+ "Enable `repeat-mode' without polluting the echo area."
+ (mm-with-suppressed-output
+ (repeat-mode)))
+
+(use-package repeat
+ :hook (after-init . mm-enable-repeat-mode)
+ :custom
+ (repeat-exit-timeout 5))
+
+
+;;; Remap Existing Bindings
+
+(mm-keymap-remap global-map
+ backward-delete-char-untabify backward-delete-char
+
+ capitalize-word capitalize-dwim
+ downcase-word downcase-dwim
+ upcase-word upcase-dwim
+
+ delete-indentation e/join-current-and-next-line
+ kill-ring-save e/kill-ring-save-dwim
+ mark-sexp e/mark-entire-sexp
+ mark-word e/mark-entire-word
+ open-line e/open-line
+ yank e/yank)
+
+(with-eval-after-load 'cc-vars
+ (setopt c-backspace-function #'backward-delete-char))
+
+
+;;; Remove Unwanted Bindings
+
+(keymap-global-unset "C-x C-c" :remove) ; ‘capitalize-region’
+(keymap-global-unset "C-x C-l" :remove) ; ‘downcase-region’
+(keymap-global-unset "C-x C-u" :remove) ; ‘upcase-region’
+
+;; The following conflict with ‘ace-window’
+(with-eval-after-load 'mhtml-mode
+ (keymap-unset html-mode-map "M-o" :remove))
+
+
+;;; Bind Commands Globally
+
+(mm-keymap-set global-map
+ ;; "<next>" #'e/scroll-up
+ ;; "<prior>" #'e/scroll-down
+ "C-<next>" #'forward-page
+ "C-<prior>" #'backward-page
+
+ "C-." #'repeat
+ "C-^" #'e/split-line
+ "C-/" #'e/mark-line-dwim
+
+ "C-]" #'mm-search-forward-char
+ "M-]" #'mm-search-backward-char
+
+ "M-\\" #'cycle-spacing
+
+ "C-M-@" #'mm-add-cursor-to-next-word
+
+ "C-c c a" #'mc/vertical-align-with-space
+ "C-c c i" #'mc/insert-numbers
+ "C-c c t" #'mm-transpose-cursor-regions
+ "C-c d" #'duplicate-dwim
+ "C-c t a" #'e/align-regexp
+ "C-c t f" #'fill-paragraph
+ "C-c t s" #'e/sort-dwim)
+
+(mm-keymap-set-repeating global-map
+ "j" #'e/join-current-and-next-line
+ "J" #'join-line)
+
+(mm-keymap-set-repeating global-map
+ "n" #'next-error
+ "p" #'previous-error)
+
+(with-eval-after-load 'increment
+ (mm-keymap-set-repeating global-map
+ "d" #'decrement-number-at-point
+ "i" #'increment-number-at-point))
+
+
+;;; Other Bindings
+
+(with-eval-after-load 'project
+ (mm-keymap-set project-prefix-map
+ "g" #'mm-project-find-regexp
+ "G" #'project-git-grab)
+
+ (when mm-humanwave-p
+ (mm-keymap-set project-prefix-map
+ "q" #'mm-humanwave-query)))
+
+(with-eval-after-load 'eat
+ (with-eval-after-load 'ace-window
+ (mm-keymap-set eat-semi-char-mode-map
+ "M-o" #'ace-window)))
+
+(with-eval-after-load 'minibuffer
+ (when mm-humanwave-p
+ (mm-keymap-set minibuffer-mode-map
+ "C-c m" #'mm-humanwave-insert-last-commit-message)))
+
+
+;;; Display Available Keybindings
+
+(use-package which-key
+ :hook after-init
+ :custom
+ (which-key-dont-use-unicode nil)
+ (which-key-ellipsis "…")
+ (wihch-key-idle-delay .5))
+
+(provide 'mm-keybindings)
diff --git a/.config/emacs-old/modules/mm-lsp.el b/.config/emacs-old/modules/mm-lsp.el
new file mode 100644
index 0000000..3a64f49
--- /dev/null
+++ b/.config/emacs-old/modules/mm-lsp.el
@@ -0,0 +1,45 @@
+;;; mm-lsp.el --- Language Server Protocol configuration -*- lexical-binding: t; -*-
+
+;;; Configure LSP
+
+(defun mm-lsp-eglot-no-inlay-hints ()
+ "Disable inlay hints when `eglot' is enabled."
+ (eglot-inlay-hints-mode -1))
+
+(use-package eglot
+ :hook (((c-mode c-ts-mode
+ c++-mode c++-ts-mode
+ go-ts-mode
+ js-mode js-ts-mode)
+ . eglot-ensure)
+ (eglot-managed-mode . mm-lsp-eglot-no-inlay-hints))
+ :init
+ (fset #'jsonrpc--log-event #'ignore)
+ :custom
+ (eglot-events-buffer 0)
+ (eglot-extend-to-xref t)
+ :config
+ (add-to-list 'eglot-stay-out-of 'flymake)
+ (add-to-list 'eglot-server-programs
+ '((c-mode c-ts-mode c++-mode c++-ts-mode)
+ . ("clangd" "--header-insertion=never"))))
+
+(use-package eglot-booster
+ :after eglot
+ :config
+ (eglot-booster-mode))
+
+
+;;; Use Tempel for Snippets
+
+(defun mm-lsp-eglot-tempel-enable ()
+ "Enable `eglot-tempel-mode'.
+If `eglot-tempel-mode' is already enabled this function does nothing."
+ (unless (default-value eglot-tempel-mode)
+ (eglot-tempel-mode)))
+
+(use-package eglot-tempel
+ :after eglot
+ :hook (eglot-managed-mode . mm-lsp-eglot-tempel-enable))
+
+(provide 'mm-lsp) \ No newline at end of file
diff --git a/.config/emacs-old/modules/mm-modeline.el b/.config/emacs-old/modules/mm-modeline.el
new file mode 100644
index 0000000..9a35d04
--- /dev/null
+++ b/.config/emacs-old/modules/mm-modeline.el
@@ -0,0 +1,147 @@
+;;; mm-modeline.el --- Pluggable modeline components -*- lexical-binding: t; -*-
+
+(defmacro mm-modeline--define-component (name &rest forms)
+ (declare (indent 1))
+ `(progn
+ (defface ,(intern (format "%s-face" name))
+ '((t))
+ ,(format "Face for the `%s' component." name))
+ (defvar-local ,name '(:eval (or ,(macroexp-progn forms) "")))
+ (put ',name 'risky-local-variable t)))
+
+
+;;; Support Icons
+
+(use-package all-the-icons
+ :ensure t
+ :init
+ (defvar mm-all-the-icons-cookie
+ (expand-file-name ".all-the-icons-installed-p" mm-cache-directory))
+ (unless (file-exists-p mm-all-the-icons-cookie)
+ (all-the-icons-install-fonts)
+ (make-empty-file mm-all-the-icons-cookie :parents))
+ (set-char-table-range char-width-table #xE907 2))
+
+
+;;; Modeline Components
+
+(mm-modeline--define-component mm-modeline-overwrite
+ (when overwrite-mode
+ (propertize " OVERWRITE" 'face 'mm-modeline-overwrite-face)))
+
+(mm-modeline--define-component mm-modeline-readonly
+ (when buffer-read-only
+ (propertize " READONLY" 'face 'mm-modeline-readonly-face)))
+
+(mm-modeline--define-component mm-modeline-buffer-name
+ (propertize "%b" 'face 'mm-modeline-buffer-name-face))
+
+(mm-modeline--define-component mm-modeline-buffer-modified
+ (when (and (buffer-modified-p)
+ (buffer-file-name))
+ (propertize " (modified)" 'face 'mm-modeline-buffer-modified-face)))
+
+(defconst mm-modeline-mode-acronyms
+ '("css" "csv" "gsp" "html" "json" "mhtml" "rfc" "scss" "sql" "toml" "tsv"
+ "url" "yaml")
+ "List of acronyms in major mode names that should be capitalized.")
+
+(defconst mm-modeline-remap-alist
+ '(("Bmenu" . "BMenu")
+ ("Bsdmake" . "BSD Make")
+ ("Gitattributes" . "Git Attributes")
+ ("Gitconfig" . "Git Config")
+ ("Gitignore" . "Git Ignore")
+ ("Gmake" . "GMake")
+ ("Imake" . "IMake")
+ ("Js" . "JavaScript")
+ ("Ts Mode" . "Tree-Sitter Mode")
+ ("Wdired" . "WDired")
+ ("Xcompose" . "XCompose"))
+ "Alist of substrings in major mode names that should be remapped.
+Some major modes have substrings that would be better displayed in
+another manner. For example expanding an abbreviation such as ‘Js’ to
+its expanded form ‘JavaScript’, or fixing the casing of words with a
+prefix such as ‘Gmake’ to ‘GMake’. This alist maps the original text to
+the text it should be mapped to.")
+
+(mm-modeline--define-component mm-modeline-major-mode-name
+ (propertize
+ (let ((string (thread-last
+ major-mode
+ (symbol-name)
+ (capitalize)
+ (string-replace "-" " ")))
+ (case-fold-search nil))
+ (save-match-data
+ (dolist (pair mm-modeline-remap-alist)
+ (setq string
+ (replace-regexp-in-string
+ (format "\\<%s\\>" (regexp-quote (car pair)))
+ (cdr pair) string)))
+ (setq case-fold-search t)
+ (if (string-match (regexp-opt mm-modeline-mode-acronyms 'words) string)
+ (concat
+ (substring string 0 (match-beginning 0))
+ (upcase (substring string (match-beginning 0) (match-end 0)))
+ (substring string (match-end 0) (length string)))
+ string)))
+ 'face 'mm-modeline-major-mode-name-face))
+
+(mm-modeline--define-component mm-modeline-major-mode-symbol
+ (propertize
+ (cond
+ ((derived-mode-p 'comint-mode) "$ ")
+ ((derived-mode-p 'conf-mode) "# ")
+ ((derived-mode-p 'prog-mode) "λ ")
+ ((derived-mode-p 'special-mode) "★ ")
+ ((derived-mode-p 'text-mode) "§ ")
+ (:default ""))
+ 'face 'mm-modeline-major-mode-symbol-face))
+
+(mm-modeline--define-component mm-modeline-narrow
+ (when (buffer-narrowed-p)
+ (propertize
+ " NARROW "
+ 'face 'mm-modeline-narrow-face)))
+
+(mm-modeline--define-component mm-modeline-git-branch
+ (when-let ((branch (car (and (featurep 'vc-git)
+ (vc-git-branches)))))
+ (concat
+ (propertize "\uE907" 'display '(raise 0))
+ " "
+ (propertize branch 'face 'mm-modeline-git-branch-face)
+ " │ ")))
+
+
+;;; Padding Between Left and Right
+
+(mm-modeline--define-component mm-modeline-left-right-padding
+ (let ((length (string-width (format-mode-line mm-modeline-right))))
+ (propertize " " 'display `(space :align-to (- right ,length)))))
+
+
+;;; Configure Modeline
+
+(setopt mode-line-format-right-align 'right-margin)
+
+(setq
+ mm-modeline-left (list mm-modeline-narrow
+ mm-modeline-overwrite
+ mm-modeline-readonly
+ " "
+ mm-modeline-buffer-name
+ mm-modeline-buffer-modified
+ " │ "
+ mm-modeline-major-mode-symbol
+ mm-modeline-major-mode-name
+ mm-modeline-left-right-padding
+ mode-line-end-spaces)
+ mm-modeline-right (list mm-modeline-git-branch
+ "%l:%c "))
+
+(setq-default
+ mode-line-format
+ (list mm-modeline-left mm-modeline-left-right-padding mm-modeline-right))
+(provide 'mm-modeline)
diff --git a/.config/emacs-old/modules/mm-org.el b/.config/emacs-old/modules/mm-org.el
new file mode 100644
index 0000000..b4d0f31
--- /dev/null
+++ b/.config/emacs-old/modules/mm-org.el
@@ -0,0 +1,6 @@
+;;; mm-org.el --- Org-Mode configuration -*- lexical-binding: t; -*-
+
+(use-package org
+ :hook (org-mode . org-indent-mode))
+
+(provide 'mm-org) \ No newline at end of file
diff --git a/.config/emacs-old/modules/mm-projects.el b/.config/emacs-old/modules/mm-projects.el
new file mode 100644
index 0000000..02d7af4
--- /dev/null
+++ b/.config/emacs-old/modules/mm-projects.el
@@ -0,0 +1,114 @@
+;;; mm-projects.el --- Configuration for project management -*- lexical-binding: t; -*-
+
+;;; Project Configuration
+
+(defun mm-projects-project-magit-status ()
+ "Open a Git status buffer for the current project.
+This is intended to be called interactively via
+ `project-switch-commands'."
+ (interactive)
+ (thread-last
+ (project-current t)
+ (project-root)
+ (magit-status-setup-buffer)))
+
+(use-package project
+ :custom
+ (project-switch-commands
+ '((project-dired "Dired" ?d)
+ (project-find-file "Find File" ?f)
+ (mm-projects-project-magit-status "Git Status" ?s)))
+ :config
+ (unless mm-humanwave-p
+ (if-let ((repo-directory (getenv "REPODIR")))
+ (let* ((list-dir
+ (lambda (path)
+ (directory-files path :full "\\`[^.]")))
+ (directories
+ (cl-loop for author in (funcall list-dir (getenv "REPODIR"))
+ append (cl-loop for path in (funcall list-dir author)
+ collect (list (concat path "/"))))))
+ (with-temp-buffer
+ (prin1 directories (current-buffer))
+ (write-file project-list-file))
+ (project--read-project-list))
+ (warn "The REPODIR environment variable is not set."))))
+
+
+;;; Emacs VC
+
+(use-package vc-hooks
+ :custom
+ (vc-follow-symlinks t)
+ (vc-handled-backends '(Git)))
+
+
+;;; Git Client
+
+(use-package magit
+ :ensure t
+ :bind (("C-c b" . magit-blame-addition)
+ :map magit-status-mode-map
+ ("[" . magit-section-backward-sibling)
+ ("]" . magit-section-forward-sibling))
+ :custom
+ (git-commit-style-convention-checks
+ '(non-empty-second-line overlong-summary-line))
+ (git-commit-summary-max-length 50)
+ (magit-diff-refine-hunk t)
+ (magit-display-buffer-function
+ #'magit-display-buffer-same-window-except-diff-v1)
+ (transient-default-level 7)
+ :config
+ (transient-define-suffix mm-projects-magit-push-current-to-all-remotes (args)
+ "Push the current branch to all remotes."
+ :if #'magit-get-current-branch
+ (interactive (list (magit-push-arguments)))
+ (run-hooks 'magit-credential-hook)
+ (let ((branch (magit-get-current-branch)))
+ (dolist (remote (magit-list-remotes))
+ (magit-run-git-async
+ "push" "-v" args remote
+ (format "refs/heads/%s:refs/heads/%s" branch branch)))))
+ (transient-append-suffix #'magit-push '(1 -1)
+ '("a" "all remotes" mm-projects-magit-push-current-to-all-remotes))
+ (add-to-list 'magit-blame-styles
+ '(margin
+ (show-lines . t)
+ (margin-format . (" %C %a" " %s%f" " "))
+ (margin-width . 73)
+ (margin-face . magit-blame-margin)
+ (margin-body-face . (magit-blame-dimmed)))))
+
+(use-package magit-repos
+ :ensure nil ; Part of ‘magit’
+ :if (not mm-humanwave-p)
+ :commands (magit-list-repositories)
+ :init
+ (if-let ((directory (getenv "REPODIR")))
+ (setopt magit-repository-directories `((,directory . 2)))
+ (warn "The REPODIR environment variable is not set.")))
+
+(use-package magit-todos
+ :ensure t
+ :after magit
+ :hook magit-mode
+ :custom
+ (magit-todos-exclude-globs '("vendor/")))
+
+
+;; Project Compilation
+
+(use-package compile
+ :config
+ (require 'ansi-color)
+ (add-hook 'compilation-filter-hook #'ansi-color-compilation-filter))
+
+
+;;; GitHub Pull Requests
+
+(require 'gh)
+(keymap-global-set "C-c p c" #'gh-create-pr)
+(keymap-global-set "C-c p o" #'gh-open-previous-pr)
+
+(provide 'mm-projects)
diff --git a/.config/emacs-old/modules/mm-search.el b/.config/emacs-old/modules/mm-search.el
new file mode 100644
index 0000000..c89b9d0
--- /dev/null
+++ b/.config/emacs-old/modules/mm-search.el
@@ -0,0 +1,57 @@
+;;; mm-search.el --- Emacs text searching -*- lexical-binding: t; -*-
+
+;;; Classic Emacs text search
+
+(use-package isearch
+ :demand t
+ :bind ( :map isearch-mode-map
+ ("M-/" . isearch-complete)
+ :map minibuffer-local-isearch-map
+ ("M-/" . isearch-complete-edit))
+ :custom
+ (search-whitespace-regexp ".*?")
+ (isearch-lax-whitespace t)
+ (isearch-regexp-lax-whitespace nil)
+ (isearch-lazy-count t)
+ (lazy-highlight-initial-delay 0)
+ (lazy-count-prefix-format "(%s/%s) ")
+ (isearch-repeat-on-direction-change t))
+
+(defun mm--project-find-wrapper (command regexp)
+ (let (csf)
+ (cond ((string-suffix-p "/i" regexp)
+ (setq regexp (string-remove-suffix "/i" regexp)
+ csf t))
+ ((string-suffix-p "/I" regexp)
+ (setq regexp (string-remove-suffix "/I" regexp)
+ csf nil))
+ (:else
+ (setq csf case-fold-search)))
+ (let ((case-fold-search csf))
+ (funcall-interactively command regexp))))
+
+(defun mm-project-find-regexp (regexp)
+ "Find all matches for REGEXP in the current project’s roots.
+This is a thin wrapper around `project-find-regexp' that supports the
+`/i' and `/I' suffixes to enable and disable case-sensitive matching
+respectively."
+ (interactive (list (project--read-regexp)))
+ (mm--project-find-wrapper #'project-find-regexp regexp))
+
+(defun mm-project-or-external-find-regexp (regexp)
+ "Find all matches for REGEXP in the project roots or external roots.
+This is a thin wrapper around `project-or-external-find-regexp' that
+supports the `/i' and `/I' suffixes to enable and disable case-sensitive
+matching respectively."
+ (interactive (list (project--read-regexp)))
+ (mm--project-find-wrapper #'project-or-external-find-regexp regexp))
+
+
+;;; Grab Integration
+
+(use-package grab
+ :commands (grab git-grab project-grab project-git-grab)
+ :custom
+ (grab-default-pattern '("x/^.*?$/ g// h//" . 12)))
+
+(provide 'mm-search)
diff --git a/.config/emacs-old/modules/mm-spellcheck.el b/.config/emacs-old/modules/mm-spellcheck.el
new file mode 100644
index 0000000..95db7ac
--- /dev/null
+++ b/.config/emacs-old/modules/mm-spellcheck.el
@@ -0,0 +1,24 @@
+;;; mm-spellcheck.el --- Spell checking configuration -*- lexical-binding: t; -*-
+
+;;; ISpell Spell Checking
+
+(use-package ispell
+ :hook (flyspell-mode . ispell-minor-mode)
+ :custom
+ (ispell-program-name "hunspell")
+ (ispell-local-dictionary "en_US")
+ (ispell-local-dictionary-alist
+ '(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[’']"
+ nil ("-d" "en_US") nil utf-8)))
+ (ispell-hunspell-dictionary-alist ispell-local-dictionary-alist))
+
+
+;;; On-The-Fly Spell Checking
+
+(use-package flyspell
+ :defer t
+ :config
+ ;; I use ‘C-,’ for ‘emmet-expand-line’
+ (keymap-unset flyspell-mode-map "C-," :remove))
+
+(provide 'mm-spellcheck)
diff --git a/.config/emacs-old/modules/mm-tetris.el b/.config/emacs-old/modules/mm-tetris.el
new file mode 100644
index 0000000..06fae58
--- /dev/null
+++ b/.config/emacs-old/modules/mm-tetris.el
@@ -0,0 +1,20 @@
+;;; mm-tetris.el --- Emacs configurations for ‘tetris’ -*- lexical-binding: t; -*-
+
+(defun mm-tetris-rotate-mirror ()
+ "Rotate the current piece by 180°."
+ (declare (modes tetris-mode))
+ (interactive)
+ (tetris-rotate-next)
+ (tetris-rotate-next))
+
+(use-package tetris
+ :bind (:map tetris-mode-map
+ ("a" . tetris-move-left)
+ ("d" . tetris-move-right)
+ ("k" . tetris-rotate-next)
+ (";" . tetris-rotate-prev)
+ ("l" . tetris-move-down)
+ ("o" . mm-tetris-rotate-mirror)
+ ("SPC" . tetris-move-bottom)))
+
+(provide 'mm-tetris)
diff --git a/.config/emacs-old/modules/mm-theme.el b/.config/emacs-old/modules/mm-theme.el
new file mode 100644
index 0000000..89cdffd
--- /dev/null
+++ b/.config/emacs-old/modules/mm-theme.el
@@ -0,0 +1,246 @@
+;;; mm-theme.el --- Emacs theme settings -*- lexical-binding: t; -*-
+
+
+;;; Custom Theme
+
+(load-theme 'mango :no-confirm)
+
+
+;;; Fonts
+
+(defvar mm-theme-monospace-font `(,(if mm-humanwave-p
+ "Iosevka Custom"
+ "Iosevka Smooth")
+ :weight regular
+ :height 162)
+ "The default monospace font.
+This is a plist containing a font name, -weight, and -height.")
+
+(defvar mm-theme-proportional-font
+ `(,(if mm-darwin-p "Microsoft Sans Serif" "Source Sans 3 Medium")
+ :weight regular :height 162)
+ "The default proportional font.
+This is a plist containing a font name, -weight, and -height.")
+
+(defun mm-theme-set-fonts (&optional _frame)
+ "Set frame font settings.
+Sets the frame font settings according to the fonts specified by
+`mm-theme-monospace-font' and `mm-theme-proportional-font'.
+
+This function can be used as a hook in `after-make-frame-functions' and
+_FRAME is ignored."
+ (interactive)
+ (let* ((mono-family (car mm-theme-monospace-font))
+ (mono-props (cdr mm-theme-monospace-font))
+ (prop-family (car mm-theme-proportional-font))
+ (prop-props (cdr mm-theme-proportional-font))
+ (mono-weight (plist-get mono-props :weight))
+ (mono-height (plist-get mono-props :height))
+ (prop-weight (plist-get prop-props :weight))
+ (prop-height (plist-get prop-props :height)))
+ ;; Some characters in this font are larger than usual
+ (when (string= mono-family "Iosevka Smooth")
+ (dolist (rune '(?․ ?‥ ?… ?— ?← ?→ ?⇐ ?⇒ ?⇔))
+ (set-char-table-range char-width-table rune 2)))
+ (set-face-attribute 'default nil
+ :font mono-family
+ :weight mono-weight
+ :height mono-height)
+ (set-face-attribute 'fixed-pitch nil
+ :font mono-family
+ :weight mono-weight
+ :height mono-height)
+ (set-face-attribute 'variable-pitch nil
+ :font prop-family
+ :weight prop-weight
+ :height prop-height)))
+
+(if (daemonp)
+ (add-hook 'after-make-frame-functions #'mm-theme-set-fonts)
+ (mm-theme-set-fonts))
+
+;; Ligature Settings
+
+(defvar mm-theme-ligatures-alist
+ `(((c-mode c-ts-mode c++-mode c++-ts-mode)
+ . ("->"))
+ ((c++-mode c++-ts-mode)
+ . ("::"))
+ ((js-mode js-ts-mode typescript-ts-mode vue-ts-mode)
+ . (("=" ,(rx (or ?> (** 1 2 ?=))))
+ ("!" ,(rx (** 1 2 ?=)))))
+ (go-ts-mode
+ . (":=" "<-"))
+ ((python-mode python-ts-mode)
+ . (":=" "->"))
+ ((mhtml-mode html-mode html-ts-mode vue-ts-mode)
+ . ("<!--" "-->" "/>"))
+ (prog-mode
+ . ("<<=" "<=" ">=" "==" "!=" "*=" "__")))
+ "Ligatures to enable in specific modes.
+Elements of this alist are of the form:
+
+ (SPEC . LIGATURES)
+
+Where LIGATURES is a list of ligatures to enable for the set of modes
+described by SPEC.
+
+SPEC can be either a symbol, or a list of symbols. These symbols should
+correspond to modes for which the associated LIGATURES should be enabled.
+
+A mode may also be specified in multiple entries. To configure
+`go-ts-mode' to have its set of ligatures be a super-set of the
+ligatures for `c-ts-mode', the following two entries could be added:
+
+ \\='((c-ts-mode go-ts-mode) . (\">=\" \"<=\" \"!=\" \"==\"))
+ \\='(go-ts-mode . (\":=\"))")
+
+(defun mm-theme-update-ligatures ()
+ "Update the ligature composition tables.
+After running this function you may need to restart `ligature-mode'.
+
+Also see `mm-theme-ligatures-alist'."
+ (interactive)
+ (setopt ligature-composition-table nil)
+ (cl-loop for (spec . ligatures) in mm-theme-ligatures-alist
+ do (ligature-set-ligatures spec ligatures)))
+
+(use-package ligature
+ :ensure t
+ :if (or mm-darwin-p
+ (seq-contains-p (split-string system-configuration-features)
+ "HARFBUZZ"))
+ :hook prog-mode
+ :config
+ (mm-theme-update-ligatures))
+
+
+;;; Background Opacity
+
+(defvar mm-theme-background-opacity 100
+ "Opacity of the graphical Emacs frame.
+A value of 0 is fully transparent while 100 is fully opaque.")
+
+(defun mm-theme-background-opacity (opacity)
+ "Set the current frames' background opacity.
+See also the `mm-theme-background-opacity' variable."
+ (interactive
+ (list (mm-as-number
+ (read-string
+ (format-prompt "Background opacity"
+ (default-value 'mm-theme-background-opacity))
+ nil nil mm-theme-background-opacity))))
+ (set-frame-parameter nil 'alpha-background opacity))
+
+(add-to-list
+ 'default-frame-alist (cons 'alpha-background mm-theme-background-opacity))
+
+
+;;; Divider Between Windows
+
+(use-package frame
+ :hook (after-init . window-divider-mode))
+
+
+;;; Pulse Line on Jump
+
+(use-package pulsar
+ :ensure t
+ :hook (after-init . pulsar-global-mode)
+ :custom
+ (pulsar-pulse t)
+ (pulsar-delay .05)
+ (pulsar-iterations 10)
+ (pulsar-face 'hl-line)
+ :config
+ (dolist (command #'(backward-paragraph
+ e/scroll-down
+ e/scroll-up
+ forward-paragraph
+ jump-to-register
+ pop-global-mark))
+ (add-to-list 'pulsar-pulse-functions command))
+ ;; Integrate with ‘compilation-mode’
+ (add-hook 'next-error-hook #'pulsar-pulse-line)
+ :bind
+ (("C-c h l" . pulsar-highlight-dwim)))
+
+
+;;; In-buffer highlighting
+
+(require 'hi-lock) ; For extra face definitions
+(use-package highlighter
+ :bind (("C-c h m" . #'highlighter-mark)
+ ("C-c h u" . #'highlighter-unmark)
+ ("C-c h U" . #'highlighter-unmark-buffer))
+ :commands (highlighter-mark highlighter-unmark highlighter-unmark-buffer))
+
+
+;;; Add Padding
+
+(use-package spacious-padding
+ :ensure t
+ :hook after-init)
+
+
+;;; Pretty Page Boundaries
+
+(use-package page-break-lines
+ :ensure t
+ :hook (after-init . global-page-break-lines-mode)
+ :config
+ (dolist (mode '(c-mode c++-mode gsp-ts-mode))
+ (add-to-list 'page-break-lines-modes mode)
+ (let ((ts-mode (mm-mode-to-ts-mode mode)))
+ (when (fboundp ts-mode)
+ (add-to-list 'page-break-lines-modes ts-mode))))
+ (add-hook
+ 'change-major-mode-hook
+ (defun mm-theme--set-page-break-max-width ()
+ (setopt page-break-lines-max-width fill-column)))
+ ;; Since the ‘^L’ character is replaced by a horizontal rule, the
+ ;; cursor should appear below the horizontal rule. When moving
+ ;; backwards we need to account for the fact that the cursor is
+ ;; actually one character ahead of hte page break and adjust
+ ;; accordingly.
+ (advice-add
+ #'forward-page :after
+ (defun mm-theme--forward-char (&rest _)
+ (forward-char)))
+ (advice-add
+ #'backward-page :before
+ (defun mm-theme--backward-char (&rest _)
+ (backward-char))))
+
+
+;;; More Intuiative UI for Certain Modes
+
+(defun mm-disable-line-selection-mode ()
+ (line-selection-mode -1))
+
+(use-package line-selection-mode
+ :hook ((bookmark-bmenu-mode dired-mode ibuffer-mode magit-repolist-mode)
+ . line-selection-mode)
+ :config
+ (add-hook 'wdired-mode-hook #'mm-disable-line-selection-mode))
+
+
+;;; Line Highlighting
+
+(use-package hl-line
+ :custom
+ (hl-line-sticky-flag nil))
+
+
+;;; Indent Guides
+
+(when mm-humanwave-p
+ (use-package highlight-indent-guides
+ :ensure t
+ :hook ((jinja2-mode vue-ts-mode mhtml-mode) . highlight-indent-guides-mode)
+ :custom
+ (highlight-indent-guides-method 'fill)
+ (highlight-indent-guides-auto-even-face-perc 30)
+ (highlight-indent-guides-auto-odd-face-perc 0)))
+
+(provide 'mm-theme)
diff --git a/.config/emacs-old/modules/mm-treesit.el b/.config/emacs-old/modules/mm-treesit.el
new file mode 100644
index 0000000..81d0801
--- /dev/null
+++ b/.config/emacs-old/modules/mm-treesit.el
@@ -0,0 +1,240 @@
+;;; mm-treesit.el --- Tree-Sitter configuration -*- lexical-binding: t; -*-
+
+(unless (treesit-available-p)
+ (error "Tree-Sitter is not available."))
+
+
+;;; Tree-Sitter Variables
+
+(defvar mm-treesit-language-remap-alist
+ '((cpp . c++)
+ (gomod . go-mod)
+ (javascript . js)
+ (vim . vimscript))
+ "TODO")
+
+(setopt treesit-font-lock-level 4)
+(setopt treesit-language-source-alist
+ '((awk
+ "https://github.com/Beaglefoot/tree-sitter-awk")
+ (c
+ "https://github.com/tree-sitter/tree-sitter-c")
+ (cpp
+ "https://github.com/tree-sitter/tree-sitter-cpp")
+ (css
+ "https://github.com/tree-sitter/tree-sitter-css")
+ (dockerfile
+ "https://github.com/camdencheek/tree-sitter-dockerfile")
+ (elixir
+ "https://github.com/elixir-lang/tree-sitter-elixir")
+ (go
+ "https://github.com/tree-sitter/tree-sitter-go")
+ (gomod
+ "https://github.com/camdencheek/tree-sitter-go-mod")
+ (gsp
+ "git://git.thomasvoss.com/tree-sitter-gsp.git")
+ (heex
+ "https://github.com/phoenixframework/tree-sitter-heex")
+ (html
+ "https://github.com/tree-sitter/tree-sitter-html")
+ (java
+ "https://github.com/tree-sitter/tree-sitter-java")
+ (javascript
+ "https://github.com/tree-sitter/tree-sitter-javascript")
+ (json
+ "https://github.com/tree-sitter/tree-sitter-json")
+ (markdown
+ "https://github.com/tree-sitter-grammars/tree-sitter-markdown"
+ "split_parser" "tree-sitter-markdown/src")
+ (markdown-inline
+ "https://github.com/tree-sitter-grammars/tree-sitter-markdown"
+ "split_parser" "tree-sitter-markdown-inline/src")
+ (python
+ "https://github.com/tree-sitter/tree-sitter-python")
+ (rust
+ "https://github.com/tree-sitter/tree-sitter-rust")
+ (tsx
+ "https://github.com/tree-sitter/tree-sitter-typescript"
+ "master" "tsx/src")
+ (typescript
+ "https://github.com/tree-sitter/tree-sitter-typescript"
+ "master" "typescript/src")
+ (vim
+ "https://github.com/tree-sitter-grammars/tree-sitter-vim")
+ (vue
+ "https://github.com/ikatyang/tree-sitter-vue")
+ (yaml
+ "https://github.com/tree-sitter-grammars/tree-sitter-yaml")))
+
+
+;;; Install Missing Parsers
+
+(defun mm-treesit-install-all ()
+ "Install all Tree-Sitter parsers.
+This is like `mm-treesit-install-missing' but also reinstalls parsers
+that are already installed."
+ (interactive)
+ (cl-loop for (lang) in treesit-language-source-alist
+ do (treesit-install-language-grammar lang)))
+
+(defun mm-treesit-install-missing ()
+ "Install missing Tree-Sitter parsers.
+The parsers are taken from `treesit-language-source-alist'."
+ (interactive)
+ (cl-loop for (lang) in treesit-language-source-alist
+ unless (treesit-language-available-p lang)
+ do (treesit-install-language-grammar lang)))
+
+(mm-treesit-install-missing)
+
+
+;;; Install Additional TS Modes
+
+(use-package gsp-ts-mode
+ :vc (:url "https://git.thomasvoss.com/gsp-ts-mode"
+ :branch "master"
+ :rev :newest
+ :vc-backend Git)
+ :ensure t)
+
+;; NOTE: This package doesn’t autoload its ‘auto-mode-alist’ entries
+(use-package vimscript-ts-mode
+ :ensure t
+ :mode (rx (or (seq (? (or ?. ?_)) (? ?g) "vimrc")
+ ".vim"
+ ".exrc")
+ eos))
+
+;; NOTE: This package doesn’t autoload its ‘auto-mode-alist’ entries
+(use-package vue-ts-mode
+ :vc ( :url "https://github.com/8uff3r/vue-ts-mode.git"
+ :branch "main"
+ :rev :newest
+ :vc-backend Git)
+ :ensure t
+ :mode "\\.vue\\'")
+
+;; NOTE: This package doesn’t autoload its ‘auto-mode-alist’ entries
+(use-package markdown-ts-mode
+ :ensure t
+ :mode "\\.md\\'")
+
+
+;;; Prefer Tree-Sitter Modes
+
+;; NOTE: ‘go-ts-mode’ already adds itself to ‘auto-mode-alist’ but it
+;; isn’t autoloaded as of 2024-09-29 so we need to do it ourselves
+;; anyway. Same goes for ‘typescript-ts-mode’.
+(defvar mm-treesit-language-file-name-alist
+ '((dockerfile . "/[Dd]ockerfile\\'")
+ (elixir . "\\.exs?\\'")
+ (go . "\\.go\\'")
+ (gomod . "/go\\.mod\\'")
+ (heex . "\\.heex\\'")
+ (json . "\\.json\\'")
+ (rust . "\\.rs\\'")
+ (tsx . "\\.tsx\\'")
+ (typescript . "\\.ts\\'")
+ (yaml . "\\.ya?ml\\'"))
+ "Alist mapping languages to their associated file-names.
+This alist is a set of pairs of the form (LANG . REGEXP) where LANG is
+the symbol corresponding to a major mode with the `-ts-mode' suffix
+removed. REGEXP is a regular expression matching filenames for which
+the associated language’s major-mode should be enabled.
+
+This alist is used to configure `auto-mode-alist'.")
+
+(defvar mm-treesit-dont-have-modes
+ '(markdown-inline)
+ "List of languages that don't have modes.
+Some languages may come with multiple parsers, (e.g. `markdown' and
+`markdown-inline') and as a result one-or-more of the parsers won't be
+associated with a mode. To avoid breaking the configuration, these
+languages should be listed here.")
+
+(dolist (spec treesit-language-source-alist)
+ (let* ((lang (car spec))
+ (lang-remap (alist-get lang mm-treesit-language-remap-alist lang))
+ (name-mode (intern (format "%s-mode" lang-remap)))
+ (name-ts-mode (intern (format "%s-ts-mode" lang-remap))))
+ ;; If ‘name-ts-mode’ is already in ‘auto-mode-alist’ then we don’t
+ ;; need to do anything, however if that’s not the case then if
+ ;; ‘name-ts-mode’ and ‘name-mode’ are both bound we do a simple
+ ;; remap. If the above is not true then we lookup the extensions in
+ ;; ‘mm-treesit-language-file-name-alist’.
+ (cond
+ ((memq lang mm-treesit-dont-have-modes)
+ nil)
+ ((not (fboundp name-ts-mode))
+ (warn "`%s' is missing." name-ts-mode))
+ ((rassq name-ts-mode auto-mode-alist)
+ nil)
+ ((fboundp name-mode)
+ (add-to-list 'major-mode-remap-alist (cons name-mode name-ts-mode)))
+ (t ; (and (fboundp name-ts-mode) (not (fboundp name-mode)))
+ (if-let ((file-regexp
+ (alist-get lang mm-treesit-language-file-name-alist)))
+ (add-to-list 'auto-mode-alist (cons file-regexp name-ts-mode))
+ (warn "Unable to determine the extension for `%s'." name-ts-mode))))))
+
+;; JavaScript being difficult as usual
+(add-to-list 'major-mode-remap-alist '(javascript-mode . js-ts-mode))
+
+
+;;; Hack For C23
+
+(advice-add #'c-ts-mode--keywords :filter-return
+ (defun mm-c-ts-mode-add-constexpr (keywords)
+ ;; NOTE: We can’t add ‘typeof’ until it’s added to the TS grammar
+ ;; https://github.com/tree-sitter/tree-sitter-c/issues/236
+ (append keywords '("constexpr"))))
+
+
+;;; Highlight Predefined Variables
+
+(with-eval-after-load 'treesit
+ (defvar mm-c-font-lock-rules
+ (treesit-font-lock-rules
+ :language 'c
+ :feature 'constant
+ :override t
+ `(((identifier) @font-lock-constant-face
+ (:match ,(rx bos (or "__func__" "__FUNCTION__") eos)
+ @font-lock-constant-face))))))
+
+(add-hook 'c-ts-mode-hook
+ (defun mm-c-apply-font-lock-extras ()
+ (setq treesit-font-lock-settings
+ (append treesit-font-lock-settings mm-c-font-lock-rules))))
+
+
+;;; Region Expansion
+
+(defun mm-expreg-expand (n)
+ "Expand to N syntactic units."
+ (interactive "p")
+ (dotimes (_ n)
+ (expreg-expand)))
+
+(defun mm-expreg-expand-dwim ()
+ "Do-What-I-Mean `expreg-expand' to start with symbol or word.
+If over a real symbol, mark that directly, else start with a word. Fall
+back to regular `expreg-expand'."
+ (interactive)
+ (if (region-active-p)
+ (expreg-expand)
+ (let ((symbol (bounds-of-thing-at-point 'symbol)))
+ (cond
+ ((equal (bounds-of-thing-at-point 'word) symbol)
+ (mm-expreg-expand 1))
+ (symbol
+ (mm-expreg-expand 2))
+ (:else
+ (expreg-expand))))))
+
+(use-package expreg
+ :ensure t
+ :commands (mm-expreg-expand mm-expreg-expand-dwim)
+ :bind ("M-SPC" . mm-expreg-expand-dwim))
+
+(provide 'mm-treesit)
diff --git a/.config/emacs-old/modules/mm-window.el b/.config/emacs-old/modules/mm-window.el
new file mode 100644
index 0000000..0ce77c7
--- /dev/null
+++ b/.config/emacs-old/modules/mm-window.el
@@ -0,0 +1,72 @@
+;;; mm-window.el --- Window configurations -*- lexical-binding: t; -*-
+
+
+;;; Unique Buffer Names
+
+(use-package uniquify
+ :custom
+ (uniquify-buffer-name-style 'forward))
+
+
+;;; Highlight Whitespace
+
+(use-package whitespace
+ :bind (("<f1>" . whitespace-mode)
+ ("C-c z" . delete-trailing-whitespace))
+ :custom
+ (whitespace-style
+ '( face trailing spaces tabs space-mark tab-mark empty indentation
+ space-after-tab space-before-tab))
+ (whitespace-display-mappings
+ '((space-mark 32 [?·] [?.]) ; Space
+ (space-mark 160 [?␣] [?_]) ; Non-Breaking Space
+ (tab-mark 9 [?» ?\t] [?> ?\t]))))
+
+
+;;; Line Numbers
+
+(use-package display-line-numbers
+ :bind ("<f2>" . display-line-numbers-mode)
+ :custom
+ (display-line-numbers-grow-only t)
+ (display-line-numbers-type 'relative)
+ (display-line-numbers-width-start 99))
+
+
+;;; Select Help Windows
+
+(use-package help
+ :custom
+ (help-window-select t))
+
+
+;;; Window Scrolling
+
+(use-package window
+ :custom
+ (scroll-conservatively 101) ; (info "(Emacs)Auto Scrolling")
+ (scroll-error-top-bottom t)
+ (scroll-margin 10)
+ :config
+ (setq-default truncate-partial-width-windows nil))
+
+
+;;; Smoother Scrolling
+
+(mm-comment
+ (use-package pixel-scroll
+ :init
+ (pixel-scroll-precision-mode)
+ :config
+ ;; Make it easier to use custom scroll functions
+ (dolist (binding '("<next>" "<prior>"))
+ (keymap-unset pixel-scroll-precision-mode-map binding :remove))))
+
+
+;;; Ace Window
+
+(use-package ace-window
+ :ensure t
+ :bind ("M-o" . ace-window))
+
+(provide 'mm-window) \ No newline at end of file