commit c0b8f5d1d2ac8107b92f4e271ae790a50eb6c769
parent f727fc97310fcca96a90e653f946eec671cb5472
Author: Michael Neuper <michael@michaelneuper.com>
Date: Tue, 4 Aug 2026 18:50:57 +0200
highlight conventional commits in magit
Add custom faces and highlighting for conventional commit types, scopes,
and breaking changes in magit log and revision buffers. Enable magit-prime
for better performance and integrate magit-todos with improved suffix regex.
Include magit-forge for GitHub integration.
Diffstat:
| M | config.org | | | 160 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | init.el | | | 2 | +- |
2 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/config.org b/config.org
@@ -1382,14 +1382,174 @@ Also disable inlay hints.
:desc "Toggle inlay hints" "t h" #'eglot-inlay-hints-mode))
#+end_src
*** magit
+**** magit
Add icons to =magit= and make the commit summary bold.
#+begin_src emacs-lisp
+;; REVIEW https://github.com/magit/magit/issues/2942
(after! magit
(setopt magit-format-file-function #'magit-format-file-nerd-icons)
+ (setq auth-sources '("~/.authinfo")) ;; FIXME not using apple keychain
+
+ (with-eval-after-load 'magit
+ (setq magit-revision-show-gravatars '("^Author: " . "^Commit: ")))
+
(custom-set-faces!
'(git-commit-summary :weight bold)))
#+end_src
+
+Highlight conventional commit prefixes in magit log and revision buffers,
+with separate faces for types, scopes, and breaking-change markers.
+#+begin_src emacs-lisp
+;; REVIEW: remove when https://github.com/magit/magit/issues/4027 is in doom's version of magit
+(defface my/magit-conventional-commit-default-face
+ '((t (:inherit font-lock-comment-face :weight bold)))
+ "Default face for conventional commit keywords.")
+
+(defface my/magit-conventional-commit-scope-face
+ '((t (:inherit (default my/magit-conventional-commit-default-face)
+ :weight bold)))
+ "Face for conventional commit scopes.")
+
+(defface my/magit-conventional-commit-feat-face
+ '((t (:inherit (success my/magit-conventional-commit-default-face))))
+ "Face for `feat' conventional commits.")
+
+(defface my/magit-conventional-commit-fix-face
+ '((t (:inherit (error my/magit-conventional-commit-default-face))))
+ "Face for `fix' and breaking conventional commits.")
+
+(defface my/magit-conventional-commit-revert-face
+ '((t (:inherit (error my/magit-conventional-commit-default-face))))
+ "Face for `revert' conventional commits.")
+
+(defface my/magit-conventional-commit-docs-face
+ '((t (:inherit my/magit-conventional-commit-default-face)))
+ "Face for `docs' conventional commits.")
+
+(defface my/magit-conventional-commit-style-face
+ '((t (:inherit my/magit-conventional-commit-default-face)))
+ "Face for `style' conventional commits.")
+
+(defface my/magit-conventional-commit-refactor-face
+ '((t (:inherit my/magit-conventional-commit-default-face)))
+ "Face for `refactor' conventional commits.")
+
+(defface my/magit-conventional-commit-perf-face
+ '((t (:inherit my/magit-conventional-commit-default-face)))
+ "Face for `perf' conventional commits.")
+
+(defface my/magit-conventional-commit-test-face
+ '((t (:inherit my/magit-conventional-commit-default-face)))
+ "Face for `test' conventional commits.")
+
+(defface my/magit-conventional-commit-build-face
+ '((t (:inherit my/magit-conventional-commit-default-face)))
+ "Face for `build' conventional commits.")
+
+(defface my/magit-conventional-commit-ci-face
+ '((t (:inherit my/magit-conventional-commit-default-face)))
+ "Face for `ci' conventional commits.")
+
+(defface my/magit-conventional-commit-chore-face
+ '((t (:inherit my/magit-conventional-commit-default-face)))
+ "Face for `chore' conventional commits.")
+
+(defconst my/magit-conventional-commit-keywords
+ '(("feat" . my/magit-conventional-commit-feat-face)
+ ("fix" . my/magit-conventional-commit-fix-face)
+ ("docs" . my/magit-conventional-commit-docs-face)
+ ("style" . my/magit-conventional-commit-style-face)
+ ("refactor" . my/magit-conventional-commit-refactor-face)
+ ("perf" . my/magit-conventional-commit-perf-face)
+ ("test" . my/magit-conventional-commit-test-face)
+ ("build" . my/magit-conventional-commit-build-face)
+ ("ci" . my/magit-conventional-commit-ci-face)
+ ("chore" . my/magit-conventional-commit-chore-face)
+ ("revert" . my/magit-conventional-commit-revert-face))
+ "Faces for conventional commit types.")
+
+(defun my/magit-conventional-commit-face (type breaking-p)
+ "Return the face for TYPE, forcing red when BREAKING-P is non-nil."
+ (if breaking-p
+ 'my/magit-conventional-commit-fix-face
+ (or (cdr (assoc-string type my/magit-conventional-commit-keywords t))
+ 'my/magit-conventional-commit-default-face)))
+
+(defun my/magit-highlight-conventional-commit-keywords ()
+ "Highlight conventional commit keywords in magit summary buffers."
+ (save-excursion
+ (goto-char (point-min))
+ (let ((limit (line-end-position)))
+ (while (re-search-forward
+ "^\\([[:space:]]*\\)\\([[:alpha:]][[:alnum:]-]*\\)\\(?:\\(!\\)\\)?\\(?:\\(([^)]*)\\)\\)?\\(?:\\(!\\)\\)?\\(:\\)"
+ limit t)
+ (let* ((type-group 2)
+ (bang-before-scope-group 3)
+ (scope-group 4)
+ (bang-after-scope-group 5)
+ (colon-group 6)
+ (type (match-string-no-properties type-group))
+ (breaking-p (or (match-beginning bang-before-scope-group)
+ (match-beginning bang-after-scope-group)))
+ (face (my/magit-conventional-commit-face type breaking-p)))
+ (put-text-property (match-beginning type-group) (match-end type-group)
+ 'font-lock-face face)
+ (when (match-beginning bang-before-scope-group)
+ (put-text-property (match-beginning bang-before-scope-group)
+ (match-end bang-before-scope-group)
+ 'font-lock-face face))
+ (when (match-beginning scope-group)
+ (put-text-property (match-beginning scope-group) (match-end scope-group)
+ 'font-lock-face (if breaking-p
+ face
+ 'my/magit-conventional-commit-scope-face)))
+ (when (match-beginning bang-after-scope-group)
+ (put-text-property (match-beginning bang-after-scope-group)
+ (match-end bang-after-scope-group)
+ 'font-lock-face face))
+ (put-text-property (match-beginning colon-group) (match-end colon-group)
+ 'font-lock-face 'default))))))
+
+(add-hook! '(magit-log-wash-summary-hook
+ magit-revision-wash-message-hook)
+ :append #'my/magit-highlight-conventional-commit-keywords)
+#+end_src
+
+**** magit-prime
+Speed up magit.
+#+begin_src emacs-lisp :tangle packages.el
+(when (modulep! :tools magit)
+ (package! magit-prime))
+#+end_src
+
+#+begin_src emacs-lisp
+(use-package! magit-prime
+ :when (modulep! :tools magit)
+ :hook (magit-mode . magit-prime-mode))
+#+end_src
+
+**** magit-todos
+Display TODOs in magit buffer.
+#+begin_src emacs-lisp :tangle packages.el
+(when (modulep! :tools magit)
+ (package! magit-todos))
+#+end_src
+
+Change the suffix regex to make the =:= and the end of the keyword optional.
+So this regex should match:
+- =TODO bar=
+- =TODO: bar=
+- =TODO(foo): bar=
+- =TODO[foo]: bar=
+#+begin_src emacs-lisp
+(use-package! magit-todos
+ :when (modulep! :tools magit)
+ :hook (magit-status-mode . magit-todos-mode)
+ :config
+ (setq magit-todos-keyword-suffix "\\(?::\\|\\(?:[([][^])]+[])]\\)?\\|:\\)?"))
+#+end_src
+
*** pdf
Automatically enable dark mode in pdfs.
#+begin_src emacs-lisp
diff --git a/init.el b/init.el
@@ -88,8 +88,8 @@
(lookup +docsets) ; navigate your code and its documentation
llm ; when I said you needed friends, I didn't mean...
(lsp +eglot +booster) ; M-x vscode
- magit ; a git porcelain for Emacs
;;make ; run make tasks from Emacs
+ (magit +forge) ; a git porcelain for Emacs
;;pass ; password manager for nerds
pdf ; pdf enhancements
;;terraform ; infrastructure as code