From daeeecee613987bd821b4e15d03b2cb925cd88b0 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 3 Apr 2026 02:09:58 +0200 Subject: emacs: Mark the config as legacy --- .config/emacs-old/modules/mm-abbrev.el | 110 +++++++ .config/emacs-old/modules/mm-buffer-menu.el | 15 + .config/emacs-old/modules/mm-calc.el | 13 + .config/emacs-old/modules/mm-completion.el | 256 +++++++++++++++ .config/emacs-old/modules/mm-darwin.el | 30 ++ .config/emacs-old/modules/mm-dired.el | 24 ++ .config/emacs-old/modules/mm-documentation.el | 44 +++ .config/emacs-old/modules/mm-editing.el | 449 ++++++++++++++++++++++++++ .config/emacs-old/modules/mm-humanwave.el | 254 +++++++++++++++ .config/emacs-old/modules/mm-keybindings.el | 188 +++++++++++ .config/emacs-old/modules/mm-lsp.el | 45 +++ .config/emacs-old/modules/mm-modeline.el | 147 +++++++++ .config/emacs-old/modules/mm-org.el | 6 + .config/emacs-old/modules/mm-projects.el | 114 +++++++ .config/emacs-old/modules/mm-search.el | 57 ++++ .config/emacs-old/modules/mm-spellcheck.el | 24 ++ .config/emacs-old/modules/mm-tetris.el | 20 ++ .config/emacs-old/modules/mm-theme.el | 246 ++++++++++++++ .config/emacs-old/modules/mm-treesit.el | 240 ++++++++++++++ .config/emacs-old/modules/mm-window.el | 72 +++++ 20 files changed, 2354 insertions(+) create mode 100644 .config/emacs-old/modules/mm-abbrev.el create mode 100644 .config/emacs-old/modules/mm-buffer-menu.el create mode 100644 .config/emacs-old/modules/mm-calc.el create mode 100644 .config/emacs-old/modules/mm-completion.el create mode 100644 .config/emacs-old/modules/mm-darwin.el create mode 100644 .config/emacs-old/modules/mm-dired.el create mode 100644 .config/emacs-old/modules/mm-documentation.el create mode 100644 .config/emacs-old/modules/mm-editing.el create mode 100644 .config/emacs-old/modules/mm-humanwave.el create mode 100644 .config/emacs-old/modules/mm-keybindings.el create mode 100644 .config/emacs-old/modules/mm-lsp.el create mode 100644 .config/emacs-old/modules/mm-modeline.el create mode 100644 .config/emacs-old/modules/mm-org.el create mode 100644 .config/emacs-old/modules/mm-projects.el create mode 100644 .config/emacs-old/modules/mm-search.el create mode 100644 .config/emacs-old/modules/mm-spellcheck.el create mode 100644 .config/emacs-old/modules/mm-tetris.el create mode 100644 .config/emacs-old/modules/mm-theme.el create mode 100644 .config/emacs-old/modules/mm-treesit.el create mode 100644 .config/emacs-old/modules/mm-window.el (limited to '.config/emacs-old/modules') 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-" . 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 "" :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 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 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))) + (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 " <" (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 "" #'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 + ;; "" #'e/scroll-up + ;; "" #'e/scroll-down + "C-" #'forward-page + "C-" #'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 (("" . 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 ("" . 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 '("" "")) + (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 -- cgit v1.2.3