From 46e4626e4a9326fd32161459db1a22af7b791902 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 20 Mar 2026 16:34:58 +0100 Subject: emacs: Map ‘C-x p G’ to ‘project-git-grab’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .config/emacs/modules/mm-keybindings.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to '.config/emacs/modules') diff --git a/.config/emacs/modules/mm-keybindings.el b/.config/emacs/modules/mm-keybindings.el index 0df92ce..929dd02 100644 --- a/.config/emacs/modules/mm-keybindings.el +++ b/.config/emacs/modules/mm-keybindings.el @@ -151,7 +151,7 @@ the first command is remapped to the second command." (with-eval-after-load 'project (mm-keymap-set project-prefix-map "g" #'mm-project-find-regexp - "G" #'mm-project-or-external-find-regexp) + "G" #'project-git-grab) (when mm-humanwave-p (mm-keymap-set project-prefix-map -- cgit v1.2.3 From cb3a583e6969262ecab14f026922492b4594a2f7 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 20 Mar 2026 16:35:34 +0100 Subject: emacs: Add ‘mm-humanwave-insert-last-commit-message’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .config/emacs/modules/mm-humanwave.el | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to '.config/emacs/modules') diff --git a/.config/emacs/modules/mm-humanwave.el b/.config/emacs/modules/mm-humanwave.el index f9e59b4..2e58b13 100644 --- a/.config/emacs/modules/mm-humanwave.el +++ b/.config/emacs/modules/mm-humanwave.el @@ -158,4 +158,14 @@ to the `project-find-file' command." (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))))) + (provide 'mm-humanwave) -- cgit v1.2.3 From 4052c02106550f7a33677d28103310fd46b791fd Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 20 Mar 2026 16:36:40 +0100 Subject: emacs: Add Rust commenting support --- .config/emacs/modules/mm-editing.el | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to '.config/emacs/modules') diff --git a/.config/emacs/modules/mm-editing.el b/.config/emacs/modules/mm-editing.el index eb8b7be..91a290e 100644 --- a/.config/emacs/modules/mm-editing.el +++ b/.config/emacs/modules/mm-editing.el @@ -136,22 +136,29 @@ those should be listed in `mm-editing-indentation-settings'." ;;; Code Commenting -(defun mm-c-comment-no-continue () +(defun mm-newcomment-c-config () (setq-local comment-continue " ")) -(defun mm-mhtml-comment-no-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-c-comment-no-continue) + (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-c-comment-no-continue))) - (add-hook 'mhtml-mode #'mm-mhtml-comment-no-continue)) + (add-hook (mm-mode-to-hook ts-mode) #'mm-newcomment-c-config))) + (add-hook 'mhtml-mode #'mm-newcomment-html-config) + (add-hook 'rust-ts-mode #'mm-newcomment-rust-config)) ;;; Multiple Cursors -- cgit v1.2.3 From b64b74516c0e5dd3fa153770fe90c813baa6aa68 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 20 Mar 2026 16:36:50 +0100 Subject: emacs: Map ‘C-c m’ to ‘mm-humanwave-insert-last-commit-message’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .config/emacs/modules/mm-keybindings.el | 5 +++++ 1 file changed, 5 insertions(+) (limited to '.config/emacs/modules') diff --git a/.config/emacs/modules/mm-keybindings.el b/.config/emacs/modules/mm-keybindings.el index 929dd02..aae9b4d 100644 --- a/.config/emacs/modules/mm-keybindings.el +++ b/.config/emacs/modules/mm-keybindings.el @@ -162,6 +162,11 @@ the first command is remapped to the second command." (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 -- cgit v1.2.3 From 5b19afdbedaaccd55e24888df804ea2122f702ac Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 20 Mar 2026 16:37:17 +0100 Subject: emacs: Jira integration --- .config/emacs/modules/mm-humanwave.el | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to '.config/emacs/modules') diff --git a/.config/emacs/modules/mm-humanwave.el b/.config/emacs/modules/mm-humanwave.el index 2e58b13..38fb7f5 100644 --- a/.config/emacs/modules/mm-humanwave.el +++ b/.config/emacs/modules/mm-humanwave.el @@ -168,4 +168,17 @@ to the `project-find-file' command." (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)) + (provide 'mm-humanwave) -- cgit v1.2.3 From 079822d7974d0b17706799f2d01863be9a1e8341 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 20 Mar 2026 16:37:24 +0100 Subject: emacs: Humanwave Icon completion --- .config/emacs/modules/mm-humanwave.el | 70 +++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to '.config/emacs/modules') diff --git a/.config/emacs/modules/mm-humanwave.el b/.config/emacs/modules/mm-humanwave.el index 38fb7f5..54e4a4b 100644 --- a/.config/emacs/modules/mm-humanwave.el +++ b/.config/emacs/modules/mm-humanwave.el @@ -181,4 +181,74 @@ to the `project-find-file' command." (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) -- cgit v1.2.3 From 754fccfdc4820e098f6ec53cc532b1aea52ce1d0 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 20 Mar 2026 16:37:35 +0100 Subject: emacs: Configure ‘grab’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .config/emacs/modules/mm-search.el | 6 ++++++ 1 file changed, 6 insertions(+) (limited to '.config/emacs/modules') diff --git a/.config/emacs/modules/mm-search.el b/.config/emacs/modules/mm-search.el index 9b1c4c4..3afb77e 100644 --- a/.config/emacs/modules/mm-search.el +++ b/.config/emacs/modules/mm-search.el @@ -46,4 +46,10 @@ 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)) + (provide 'mm-search) -- cgit v1.2.3 From 2aae06f23408be081a451de38111dd32c1cf07e7 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 20 Mar 2026 16:38:09 +0100 Subject: emacs: Use global-completion-previde-mode --- .config/emacs/modules/mm-completion.el | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to '.config/emacs/modules') diff --git a/.config/emacs/modules/mm-completion.el b/.config/emacs/modules/mm-completion.el index 79da064..74740b4 100644 --- a/.config/emacs/modules/mm-completion.el +++ b/.config/emacs/modules/mm-completion.el @@ -158,4 +158,12 @@ :custom (find-library-include-other-files nil)) -(provide 'mm-completion) \ No newline at end of file + +;;; 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) -- cgit v1.2.3 From c5797f6a1e6803a5eeff5a251c5ec7bbe91dd298 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 20 Mar 2026 16:38:50 +0100 Subject: emacs: Use cape for CAPF functions --- .config/emacs/modules/mm-completion.el | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to '.config/emacs/modules') diff --git a/.config/emacs/modules/mm-completion.el b/.config/emacs/modules/mm-completion.el index 74740b4..8ff2894 100644 --- a/.config/emacs/modules/mm-completion.el +++ b/.config/emacs/modules/mm-completion.el @@ -158,6 +158,23 @@ :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 -- cgit v1.2.3 From 4e0beba3438a9132eb4e049f53bd9a66d74645b2 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Fri, 20 Mar 2026 16:39:14 +0100 Subject: emacs: Support marginalia for Git branches --- .config/emacs/mango-theme.el | 6 +++ .config/emacs/modules/mm-completion.el | 72 +++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) (limited to '.config/emacs/modules') diff --git a/.config/emacs/mango-theme.el b/.config/emacs/mango-theme.el index 5fec2e0..f18f4c0 100644 --- a/.config/emacs/mango-theme.el +++ b/.config/emacs/mango-theme.el @@ -175,6 +175,12 @@ graphically, so I shouldn’t need to have multiple specs per face. (marginalia-documentation :foreground ,(mango-theme--color 'disabled) :underline nil) + (mm-diffstat-counter-added + :foreground "green" + :weight bold) + (mm-diffstat-counter-removed + :foreground "red" + :weight bold) ;; Tempel (tempel-default diff --git a/.config/emacs/modules/mm-completion.el b/.config/emacs/modules/mm-completion.el index 8ff2894..3367aa1 100644 --- a/.config/emacs/modules/mm-completion.el +++ b/.config/emacs/modules/mm-completion.el @@ -20,10 +20,80 @@ ;;; Annotate Completions -;; TODO: Show git branch descriptions! (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)) -- cgit v1.2.3