summaryrefslogtreecommitdiff
path: root/.config/emacs
diff options
context:
space:
mode:
Diffstat (limited to '.config/emacs')
-rw-r--r--.config/emacs/early-init.el9
-rw-r--r--.config/emacs/editing.el2
-rw-r--r--.config/emacs/init.el44
-rw-r--r--.config/emacs/modules/mm-buffer-menu.el15
-rw-r--r--.config/emacs/modules/mm-completion.el44
-rw-r--r--.config/emacs/modules/mm-dired.el9
-rw-r--r--.config/emacs/modules/mm-editing.el133
-rw-r--r--.config/emacs/modules/mm-keybindings.el8
-rw-r--r--.config/emacs/modules/mm-modeline.el7
-rw-r--r--.config/emacs/modules/mm-projects.el84
-rw-r--r--.config/emacs/modules/mm-theme.el35
-rw-r--r--.config/emacs/modules/mm-treesit.el130
-rw-r--r--.config/emacs/modules/mm-window.el72
-rw-r--r--.config/emacs/site-lisp/gh.el39
-rw-r--r--.config/emacs/site-lisp/number-format-mode.el129
15 files changed, 578 insertions, 182 deletions
diff --git a/.config/emacs/early-init.el b/.config/emacs/early-init.el
index b48d643..0dfbfa6 100644
--- a/.config/emacs/early-init.el
+++ b/.config/emacs/early-init.el
@@ -76,17 +76,14 @@
;; set threshold to 8 MiB which seems to be a good middleground for now.
;; A higher threshold means less garbage collections but I’ve had issues
;; with those garbage collections causing long freezes when they occur.
-(let ((saved-file-name-handler-alist file-name-handler-alist)
- (saved-vc-handled-backends vc-handled-backends))
- (setopt file-name-handler-alist nil
- vc-handled-backends nil)
+(let ((saved-file-name-handler-alist file-name-handler-alist))
+ (setopt file-name-handler-alist nil)
(add-hook
'emacs-startup-hook
(defun mm-restore-emacs-settings ()
(setopt gc-cons-threshold (* 1024 1024 8)
gc-cons-percentage 0.1
- file-name-handler-alist saved-file-name-handler-alist
- vc-handled-backends saved-vc-handled-backends))))
+ file-name-handler-alist saved-file-name-handler-alist))))
;;; Avoid Flashbang
diff --git a/.config/emacs/editing.el b/.config/emacs/editing.el
index 72d5b48..9fb2acb 100644
--- a/.config/emacs/editing.el
+++ b/.config/emacs/editing.el
@@ -231,7 +231,6 @@ This function is identical to `mm-search-forward-char' with N negated."
THING is any symbol that can be given to ‘bounds-of-thing-at-point’.
If there is an active region, the next THING will be marked."
- (require 'multiple-cursors)
(let ((bounds (bounds-of-thing-at-point thing)))
(if (null bounds)
(progn
@@ -260,7 +259,6 @@ If there is an active region, the next THING will be marked."
With prefix arg N, the regions are rotated N places (backwards if N is
negative)."
(interactive "p")
- (require 'multiple-cursors)
(when (= (mc/num-cursors) 1)
(user-error "Cannot transpose with only one cursor."))
(unless (use-region-p)
diff --git a/.config/emacs/init.el b/.config/emacs/init.el
index 99e99de..56e8476 100644
--- a/.config/emacs/init.el
+++ b/.config/emacs/init.el
@@ -122,8 +122,9 @@ buffer suppressed."
(setopt
package-vc-register-as-project nil
- package-gnupghome-dir (getenv "GNUPGHOME")
package-user-dir (expand-file-name "pkg" mm-data-directory)
+ package-gnupghome-dir (or (getenv "GNUPGHOME")
+ (expand-file-name "gnupg" package-user-dir))
package-archives (cl-loop with proto = (if (gnutls-available-p) "https" "http")
for (name . url) in
'(("gnu" . "elpa.gnu.org/packages/")
@@ -176,31 +177,23 @@ buffer suppressed."
(echo-keystrokes 0.01) ; 0 disables echoing
(echo-keystrokes-help nil)
(extended-command-suggest-shorter nil)
- (help-window-select t)
(initial-buffer-choice t)
(initial-scratch-message mm-initial-scratch-message)
(kill-do-not-save-duplicates t)
(large-file-warning-threshold nil)
(make-backup-files nil)
(mode-require-final-newline nil)
- (next-error-recenter '(4)) ; ‘center of window’
+ (next-error-recenter '(4)) ; ‘center of window’
(read-extended-command-predicate #'command-completion-default-include-p)
(remote-file-name-inhibit-auto-save t)
(remote-file-name-inhibit-delete-by-moving-to-trash t)
(require-final-newline nil)
(save-interprogram-paste-before-kill t)
- (scroll-conservatively 101) ; (info "(Emacs)Auto Scrolling")
- (scroll-error-top-bottom t)
- (scroll-margin 10)
(user-full-name "Thomas Voss")
(user-mail-address "mail@thomasvoss.com")
- (vc-follow-symlinks t)
- (vc-handled-backends '(Git))
:config
(load custom-file :noerror)
- (setq-default
- fill-column 80
- truncate-partial-width-windows nil)
+ (setq-default fill-column 80)
(dolist (mode '(text-mode emacs-lisp-mode lisp-mode))
(add-hook (mm-mode-to-hook mode)
(defun mm-set-fill-column ()
@@ -216,12 +209,6 @@ buffer suppressed."
(add-hook 'before-save-hook #'delete-trailing-whitespace)
(prefer-coding-system 'utf-8)
- ;; Show trailing whitespace but only in relevant buffers
- (dolist (mode '(conf-mode prog-mode text-mode))
- (add-hook (mm-mode-to-hook mode)
- (defun mm-show-trailing-whitespace ()
- (setopt show-trailing-whitespace t))))
-
;; Disabled modes
(blink-cursor-mode -1)
(line-number-mode -1)
@@ -235,16 +222,6 @@ buffer suppressed."
(show-paren-delay 0))
-;;; Display Line Numbers
-
-(use-package display-line-numbers
- :hook prog-mode
- :custom
- (display-line-numbers-type 'relative)
- (display-line-numbers-width-start 99)
- (display-line-numbers-grow-only t))
-
-
;;; Auto Revert Buffers
(use-package autorevert
@@ -265,17 +242,6 @@ buffer suppressed."
(bookmark-save-flag 1))
-;;; Smoother Scrolling
-
-(use-package pixel-scroll
- :init
- (pixel-scroll-precision-mode)
- :config
- ;; Make it easier to use custom scroll functions
- (dolist (binding '("<next>" "<prior>"))
- (keymap-unset pixel-scroll-precision-mode-map binding :remove)))
-
-
;;; Automatically Create- and Delete Directories
(defun mm-auto-create-directories (function filename &rest arguments)
@@ -331,6 +297,7 @@ the buffer without saving it."
;;; Load Modules
(require 'mm-abbrev) ; Text Expansion
+(require 'mm-buffer-menu) ; Buffer Menu
(require 'mm-calc) ; Emacs Calc
(require 'mm-completion) ; Completions
(require 'mm-dired) ; Dired
@@ -345,6 +312,7 @@ the buffer without saving it."
(require 'mm-tetris) ; Emacs Tetris
(require 'mm-theme) ; Themeing
(require 'mm-treesit) ; Tree-Sitter
+(require 'mm-window) ; Windowing
(when mm-darwin-p
(require 'mm-darwin)) ; MacOS
(when mm-lsp-p
diff --git a/.config/emacs/modules/mm-buffer-menu.el b/.config/emacs/modules/mm-buffer-menu.el
new file mode 100644
index 0000000..7b725c6
--- /dev/null
+++ b/.config/emacs/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/modules/mm-completion.el b/.config/emacs/modules/mm-completion.el
index 85763b7..79da064 100644
--- a/.config/emacs/modules/mm-completion.el
+++ b/.config/emacs/modules/mm-completion.el
@@ -87,23 +87,26 @@
;;; Completion Popups
-(use-package corfu
- :ensure t
- :hook prog-mode
- :bind ( :map corfu-map
- ("C-<return>" . newline))
- :custom
- (corfu-auto t)
- (corfu-cycle t)
- (corfu-auto-prefix 1)
- (corfu-auto-delay .1)
- (corfu-min-width 20)
- :config
- ;; I complete with RET and this interferes with ‘tempel-next’
- (keymap-unset corfu-map "TAB" :remove)
- (with-eval-after-load 'savehist
- (corfu-history-mode)
- (add-to-list 'savehist-additional-variables 'corfu-history)))
+(mm-comment
+ (use-package corfu
+ :ensure t
+ :hook prog-mode
+ :bind ( :map corfu-map
+ ("C-<return>" . newline))
+ :custom
+ (corfu-auto t)
+ (corfu-cycle t)
+ (corfu-auto-prefix 1)
+ (corfu-auto-delay .1)
+ (corfu-min-width 20)
+ :config
+ ;; I complete with RET and this interferes with ‘tempel-next’
+ (keymap-unset corfu-map "TAB" :remove)
+ (with-eval-after-load 'savehist
+ (corfu-history-mode)
+ (add-to-list 'savehist-additional-variables 'corfu-history))
+ (with-eval-after-load 'multiple-cursors
+ (add-to-list 'mc/unsupported-minor-modes #'corfu-mode))))
;;; Save Minibuffer History
@@ -138,12 +141,7 @@
" -path '*/.git*' -prune"
" -or -path '*/vendor/*' -prune"
")")
- " "))
- :config
- (with-eval-after-load 'pulsar
- (setopt consult-after-jump-hook nil)
- (dolist (command #'(pulsar-recenter-top pulsar-reveal-entry))
- (add-hook 'consult-after-jump-hook command))))
+ " ")))
;;; Dynamic Abbreviations
diff --git a/.config/emacs/modules/mm-dired.el b/.config/emacs/modules/mm-dired.el
index 10db837..9e78466 100644
--- a/.config/emacs/modules/mm-dired.el
+++ b/.config/emacs/modules/mm-dired.el
@@ -6,10 +6,19 @@
: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/modules/mm-editing.el b/.config/emacs/modules/mm-editing.el
index 50a31c9..540bae4 100644
--- a/.config/emacs/modules/mm-editing.el
+++ b/.config/emacs/modules/mm-editing.el
@@ -24,18 +24,20 @@
(dolist (command #'(align-region
c-backslash-region
comment-dwim
- makefile-backslash-region))
+ makefile-backslash-region
+ sh-backslash-region))
(advice-add command :around #'mm-editing-force-space-indentation))
;;; Recenter The Screen When Jumping
-(dolist (command #'(backward-page
- backward-paragraph
- forward-page
- forward-paragraph
- pop-global-mark))
- (advice-add command :around #'mm-do-and-center))
+(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
@@ -45,7 +47,8 @@
indent-tabs-mode (not mm-humanwave-p))
(defvar mm-editing-indentation-settings-alist
- '((c-mode . (:extras c-basic-offset))
+ '((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))
(emacs-lisp-mode . (:width 8 :spaces t)) ; GNU code uses 8-column tabs
@@ -64,7 +67,10 @@
(sgml-mode . (:extras sgml-basic-offset))
(sh-mode . (:extras sh-basic-offset))
(tex-mode . (:width 2))
- (vimscript-ts-mode . (:extras vimscript-ts-mode-indent-level)))
+ (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.
@@ -122,18 +128,22 @@ those should be listed in `mm-editing-indentation-settings'."
;;; Code Commenting
-(defun mm-c-comment-no-leading-stars ()
+(defun mm-c-comment-no-continue ()
(setq-local comment-continue " "))
+(defun mm-mhtml-comment-no-continue ()
+ (setq-local comment-continue " "))
+
(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-leading-stars)
+ (add-hook (mm-mode-to-hook mode) #'mm-c-comment-no-continue)
(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-leading-stars))))
+ (add-hook (mm-mode-to-hook ts-mode) #'mm-c-comment-no-continue)))
+ (add-hook 'mhtml-mode #'mm-mhtml-comment-no-continue))
;;; Multiple Cursors
@@ -150,7 +160,6 @@ region are marked, otherwise all matches in the buffer are marked."
(or (use-region-end) (point-max))
(read-string
(format-prompt ,(concat "Match " noun) nil))))
- (require 'multiple-cursors)
(if (string-empty-p ,noun-symbol)
(message "Command aborted")
(catch 'mm--no-match
@@ -177,47 +186,52 @@ region are marked, otherwise all matches in the buffer are marked."
(mm--define-mc-marking-command
mm-mark-all-in-region-regexp re-search-forward "regexp")
-(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= (car args) 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)
+(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
- :defer 2
+ :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)
- ("C-$" . #'mm-mark-all-in-region)
+ :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
- (advice-add #'load :filter-args #'mm-silent-mc-load)
+ (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
- (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))
- (add-to-list 'mc/unsupported-minor-modes #'corfu-mode))
- :config
- (keymap-unset mc/keymap "<return>" :remove))
+ (keymap-unset mc/keymap "<return>" :remove)))
;;; Increment Numbers
@@ -304,11 +318,33 @@ is as described by `emmet-expand-line'."
(emmet-self-closing-tag-style ""))
+;;; 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 csv-mode :ensure t)
-(use-package git-modes :ensure t)
-(use-package sed-mode :ensure t)
+(use-package awk-ts-mode :ensure t)
+(use-package git-modes :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)
;;; Mode-Specific Configurations
@@ -325,6 +361,7 @@ is as described by `emmet-expand-line'."
;;; Add Missing Extensions
-(add-to-list 'auto-mode-alist '("\\.tmac\\'" . nroff-mode))
+(dolist (pattern '("\\.tmac\\'" "\\.mom\\'"))
+ (add-to-list 'auto-mode-alist (cons pattern 'nroff-mode)))
(provide 'mm-editing) \ No newline at end of file
diff --git a/.config/emacs/modules/mm-keybindings.el b/.config/emacs/modules/mm-keybindings.el
index 42d2bfb..a5919de 100644
--- a/.config/emacs/modules/mm-keybindings.el
+++ b/.config/emacs/modules/mm-keybindings.el
@@ -100,12 +100,16 @@ the first command is remapped to the second command."
(keymap-global-unset "C-x C-l" :remove) ; ‘downcase-region’
(keymap-global-unset "C-x C-u" :remove) ; ‘upcase-region’
+;; The following conflict with ‘ace-window’
+(with-eval-after-load 'mhtml-mode
+ (keymap-unset html-mode-map "M-o" :remove))
+
;;; Bind Commands Globally
(mm-keymap-set global-map
- "<next>" #'e/scroll-up
- "<prior>" #'e/scroll-down
+ ;; "<next>" #'e/scroll-up
+ ;; "<prior>" #'e/scroll-down
"C-<next>" #'forward-page
"C-<prior>" #'backward-page
diff --git a/.config/emacs/modules/mm-modeline.el b/.config/emacs/modules/mm-modeline.el
index 88783c5..d1ec6f0 100644
--- a/.config/emacs/modules/mm-modeline.el
+++ b/.config/emacs/modules/mm-modeline.el
@@ -38,7 +38,8 @@
(propertize " (modified)" 'face 'mm-modeline-buffer-modified-face)))
(defconst mm-modeline-mode-acronyms
- '("css" "csv" "gsp" "html" "json" "mhtml" "scss" "toml" "tsv")
+ '("css" "csv" "gsp" "html" "json" "mhtml" "rfc" "scss" "sql" "toml" "tsv"
+ "url")
"List of acronyms in major mode names that should be capitalized.")
(defconst mm-modeline-remap-alist
@@ -50,7 +51,9 @@
("Gmake" . "GMake")
("Imake" . "IMake")
("Js" . "JavaScript")
- ("Ts Mode" . "Tree-Sitter Mode"))
+ ("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
diff --git a/.config/emacs/modules/mm-projects.el b/.config/emacs/modules/mm-projects.el
index 2ce88f7..71006d5 100644
--- a/.config/emacs/modules/mm-projects.el
+++ b/.config/emacs/modules/mm-projects.el
@@ -20,14 +20,14 @@ This is intended to be called interactively via
(mm-projects-project-magit-status "Git Status" ?s)))
:config
(unless mm-darwin-p
- (if-let ((repo-directory (getenv "REPODIR"))
- (directories
- (cl-loop
- for author in (directory-files repo-directory :full "\\`[^.]")
- append (cl-loop
- for path in (directory-files author :full "\\`[^.]")
- collect (list (concat path "/"))))))
- (progn
+ (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))
@@ -35,6 +35,14 @@ This is intended to be called interactively via
(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
@@ -43,9 +51,13 @@ This is intended to be called interactively via
("[" . magit-section-backward-sibling)
("]" . magit-section-forward-sibling))
:custom
- (transient-default-level 7)
+ (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."
@@ -60,6 +72,15 @@ This is intended to be called interactively via
(transient-append-suffix #'magit-push '(1 -1)
'("a" "all remotes" mm-projects-magit-push-current-to-all-remotes)))
+(use-package magit-repos
+ :ensure nil ; Part of ‘magit’
+ :if (not mm-darwin-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
@@ -75,4 +96,49 @@ This is intended to be called interactively via
(require 'ansi-color)
(add-hook 'compilation-filter-hook #'ansi-color-compilation-filter))
+
+;;; GitHub Pull Requests
+
+(require 'gh)
+(keymap-global-set "C-c p" #'gh-create-pr)
+
+;; (defun mm-gh--get-labels ()
+;; (with-temp-buffer
+;; (call-process "gh" nil t nil "label" "list" "--json" "name")
+;; (goto-char (point-min))
+;; (let* ((data (json-parse-buffer))
+;; (labels (seq-map (lambda (x) (gethash "name" x)) data)))
+;; (sort labels
+;; :in-place t
+;; :lessp (lambda (x y)
+;; (let ((prefix-x-p (string-prefix-p "Sprint " x))
+;; (prefix-y-p (string-prefix-p "Sprint " y)))
+;; (cond
+;; ((and prefix-x-p prefix-y-p) (string> x y))
+;; (prefix-x-p t)
+;; (prefix-y-p nil)
+;; (:else (string< x y)))))))))
+
+;; (defun mm-gh-create-pr (title draftp labels)
+;; "Create a GitHub pull request using the gh CLI.
+;; If DRAFT is non-nil, the PR will be created as a draft.
+;; LABELS should be a comma-separated string of GitHub labels."
+;; (interactive
+;; (list
+;; (read-string (format-prompt "PR Title" nil))
+;; (y-or-n-p "Create as draft PR? ")
+;; (completing-read-multiple (format-prompt "PR Labels" nil)
+;; (mm-gh--get-labels))))
+;; (let* ((branch (car (vc-git-branches)))
+;; (title (format "%s %s" branch title))
+;; (flags `("--fill-verbose" "--title" ,title "--assignee" "@me"))
+;; (label-string (mapconcat #'identity labels ",")))
+;; (when draftp
+;; (setq flags (append flags '("--draft"))))
+;; (when labels
+;; (setq flags (append flags `("--label" ,label-string))))
+;; (with-temp-buffer
+;; (apply #'call-process "gh" nil t nil "pr" "create" flags)
+;; (message (buffer-string)))))
+
(provide 'mm-projects) \ No newline at end of file
diff --git a/.config/emacs/modules/mm-theme.el b/.config/emacs/modules/mm-theme.el
index 3e14fe2..90b89ba 100644
--- a/.config/emacs/modules/mm-theme.el
+++ b/.config/emacs/modules/mm-theme.el
@@ -16,7 +16,9 @@
"The default monospace font.
This is a plist containing a font name, -weight, and -height.")
-(defvar mm-theme-proportional-font '("SF Pro" :weight regular :height 162)
+(defvar mm-theme-proportional-font
+ `(,(if mm-darwin-p "Microsoft Sans Serif" "OpenSans")
+ :weight regular :height 162)
"The default proportional font.
This is a plist containing a font name, -weight, and -height.")
@@ -38,7 +40,7 @@ _FRAME is ignored."
(prop-height (plist-get prop-props :height)))
;; Some characters in this font are larger than usual
(when (string= mono-family "Iosevka Smooth")
- (dolist (rune '(?… ?— ?← ?→ ?⇐ ?⇒ ?⇔))
+ (dolist (rune '(?․ ?‥ ?… ?— ?← ?→ ?⇐ ?⇒ ?⇔))
(set-char-table-range char-width-table rune 2)))
(set-face-attribute 'default nil
:font mono-family
@@ -74,7 +76,7 @@ _FRAME is ignored."
((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:
@@ -203,7 +205,32 @@ See also the `mm-theme-background-opacity' variable."
;;; 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) . 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-darwin-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) \ No newline at end of file
diff --git a/.config/emacs/modules/mm-treesit.el b/.config/emacs/modules/mm-treesit.el
index df3d85a..1d4defa 100644
--- a/.config/emacs/modules/mm-treesit.el
+++ b/.config/emacs/modules/mm-treesit.el
@@ -15,49 +15,65 @@
(setopt treesit-font-lock-level 4)
(setopt treesit-language-source-alist
- '((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")
- (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")
- (html "https://github.com/tree-sitter/tree-sitter-html")
- (javascript "https://github.com/tree-sitter/tree-sitter-javascript")
- (python "https://github.com/tree-sitter/tree-sitter-python")
- (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")))
+ '((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")
+ (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")
+ (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")
+ (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")
+ (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")))
;;; Install Missing Parsers
-(defun mm-treesit-sync-sources ()
- "Sync Tree-Sitter parsers.
-Reinstall the Tree-Sitter parsers specified by
- `treesit-language-source-alist'."
+(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)
- (let ((total (length treesit-language-source-alist))
- (count 0)
- (work treesit-language-source-alist)
- (processors-to-use (max 1 (1- (num-processors)))))
- (while work
- (let ((specs (seq-take work processors-to-use)))
- (dolist (spec specs)
- (async-start
- `(lambda ()
- ,(async-inject-variables "\\`treesit-language-source-alist\\'")
- (treesit-install-language-grammar ',(car spec)))
- (lambda (_)
- (setq count (1+ count))
- (message "Done syncing Tree-Sitter grammar for `%s' [%d/%d]"
- (car spec) count total))))
- (setq work (seq-drop work processors-to-use))))))
-
-(thread-last
- (mapcar #'car treesit-language-source-alist)
- (seq-remove #'treesit-language-available-p)
- (mapc #'treesit-install-language-grammar))
+ (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
@@ -79,13 +95,18 @@ Reinstall the Tree-Sitter parsers specified by
;; 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)
+ :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
@@ -94,28 +115,38 @@ Reinstall the Tree-Sitter parsers specified by
;; anyway. Same goes for ‘typescript-ts-mode’.
(defvar mm-treesit-language-file-name-alist
'((go . "\\.go\\'")
- (go-mod . "/go\\.mod\\'")
+ (gomod . "/go\\.mod\\'")
+ (tsx . "\\.tsx\\'")
(typescript . "\\.ts\\'"))
"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
+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 (alist-get lang mm-treesit-language-remap-alist lang))
- (symbol-name (symbol-name lang))
- (name-mode (intern (concat symbol-name "-mode")))
- (name-ts-mode (intern (concat symbol-name "-ts-mode"))))
+ (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)
@@ -128,6 +159,9 @@ This alist is used to configure `auto-mode-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
diff --git a/.config/emacs/modules/mm-window.el b/.config/emacs/modules/mm-window.el
new file mode 100644
index 0000000..0ce77c7
--- /dev/null
+++ b/.config/emacs/modules/mm-window.el
@@ -0,0 +1,72 @@
+;;; mm-window.el --- Window configurations -*- lexical-binding: t; -*-
+
+
+;;; Unique Buffer Names
+
+(use-package uniquify
+ :custom
+ (uniquify-buffer-name-style 'forward))
+
+
+;;; Highlight Whitespace
+
+(use-package whitespace
+ :bind (("<f1>" . whitespace-mode)
+ ("C-c z" . delete-trailing-whitespace))
+ :custom
+ (whitespace-style
+ '( face trailing spaces tabs space-mark tab-mark empty indentation
+ space-after-tab space-before-tab))
+ (whitespace-display-mappings
+ '((space-mark 32 [?·] [?.]) ; Space
+ (space-mark 160 [?␣] [?_]) ; Non-Breaking Space
+ (tab-mark 9 [?» ?\t] [?> ?\t]))))
+
+
+;;; Line Numbers
+
+(use-package display-line-numbers
+ :bind ("<f2>" . display-line-numbers-mode)
+ :custom
+ (display-line-numbers-grow-only t)
+ (display-line-numbers-type 'relative)
+ (display-line-numbers-width-start 99))
+
+
+;;; Select Help Windows
+
+(use-package help
+ :custom
+ (help-window-select t))
+
+
+;;; Window Scrolling
+
+(use-package window
+ :custom
+ (scroll-conservatively 101) ; (info "(Emacs)Auto Scrolling")
+ (scroll-error-top-bottom t)
+ (scroll-margin 10)
+ :config
+ (setq-default truncate-partial-width-windows nil))
+
+
+;;; Smoother Scrolling
+
+(mm-comment
+ (use-package pixel-scroll
+ :init
+ (pixel-scroll-precision-mode)
+ :config
+ ;; Make it easier to use custom scroll functions
+ (dolist (binding '("<next>" "<prior>"))
+ (keymap-unset pixel-scroll-precision-mode-map binding :remove))))
+
+
+;;; Ace Window
+
+(use-package ace-window
+ :ensure t
+ :bind ("M-o" . ace-window))
+
+(provide 'mm-window) \ No newline at end of file
diff --git a/.config/emacs/site-lisp/gh.el b/.config/emacs/site-lisp/gh.el
new file mode 100644
index 0000000..0461b18
--- /dev/null
+++ b/.config/emacs/site-lisp/gh.el
@@ -0,0 +1,39 @@
+;;; gh.el --- GitHub integration for Emacs -*- lexical-binding: t; -*-
+
+(defun gh-get-labels ()
+ "Return a list of labels in the current GitHub repository."
+ (with-temp-buffer
+ (call-process "gh" nil t nil "label" "list" "--sort" "name" "--json" "name")
+ (goto-char (point-min))
+ (seq-map (lambda (x) (gethash "name" x))
+ (json-parse-buffer))))
+
+;; TODO: Set title and body in a buffer like Magit
+(defun gh-create-pr (title &optional labels draftp)
+ "Create a GitHub pull request.
+If DRAFTP is non-nil, the PR will be created as a draft.
+
+LABELS is a list of labels. A list of available labels can be fetched
+via `gh-get-labels'."
+ (interactive
+ (list
+ (read-string (format-prompt "PR Title" nil))
+ (completing-read-multiple (format-prompt "PR Labels" nil)
+ (gh-get-labels))
+ (y-or-n-p "Create PR as a draft? ")))
+ (let* ((project (project-name (project-current)))
+ (flags `("--fill-verbose" "--assignee" "@me"))
+ (label-string (mapconcat #'identity labels ",")))
+ ;; TODO: Remove this
+ (when (string= project "blixem")
+ (setq title (format "%s %s" (car (vc-git-branches)) title)))
+ (setq flags (append flags `("--title" ,title)))
+ (when draftp
+ (setq flags (append flags '("--draft"))))
+ (when labels
+ (setq flags (append flags `("--label" ,label-string))))
+ (with-temp-buffer
+ (apply #'call-process "gh" nil t nil "pr" "create" flags)
+ (message (buffer-string)))))
+
+(provide 'gh) \ No newline at end of file
diff --git a/.config/emacs/site-lisp/number-format-mode.el b/.config/emacs/site-lisp/number-format-mode.el
new file mode 100644
index 0000000..cbc5937
--- /dev/null
+++ b/.config/emacs/site-lisp/number-format-mode.el
@@ -0,0 +1,129 @@
+;;; number-format-mode.el --- Format numbers in the current buffer -*- lexical-binding: t; -*-
+
+(eval-when-compile
+ (require 'cl-macs)
+ (require 'seq))
+
+(defgroup number-format nil
+ "Customization group for `number-format'."
+ :group 'convenience) ; TODO: Is this the right group?
+
+(defcustom number-format-separator "."
+ "Thousands separator to use in numeric literals."
+ :type 'string
+ :package-version '(number-format-mode . "1.0.0")
+ :group 'number-format)
+
+(defcustom number-format-predicate nil
+ "Function determining if a number should be formatted.
+When formatting a number, this function is called with the START and END
+range of the number in the buffer. If this function returns non-nil the
+number is formatted.
+
+If this function is nil then all numbers are formatted."
+ :type 'function
+ :package-version '(number-format-mode . "1.0.0")
+ :group 'number-format)
+
+(defvar-local number-format--overlays (make-hash-table :test 'eq))
+(defconst number-format--regexp "\\b[0-9]\\{4,\\}\\b")
+
+(defun number-format--add-separators (s)
+ (while (string-match "\\(.*[0-9]\\)\\([0-9][0-9][0-9].*\\)" s)
+ (setq s (concat (match-string 1 s)
+ number-format-separator
+ (match-string 2 s))))
+ s)
+
+(defun number-format--adjust-overlays (ov _1 beg end &optional _2)
+ (let* ((ov-beg (overlay-start ov))
+ (ov-end (overlay-end ov))
+ (overlays (overlays-in ov-beg ov-end)))
+ (mapcar #'delete-overlay (gethash ov number-format--overlays))
+ (save-excursion
+ (goto-char ov-beg)
+ (if (looking-at number-format--regexp :inhibit-modify)
+ (puthash ov (number-format--at-range ov-beg ov-end)
+ number-format--overlays)
+ (delete-overlay ov)
+ (remhash ov number-format--overlays)))))
+
+(defun number-format--at-range (beg end)
+ (when (or (null number-format-predicate)
+ (funcall number-format-predicate beg end))
+ (let* ((offsets [3 1 2])
+ (len (- end beg))
+ (off (aref offsets (mod len 3))))
+ (goto-char (+ beg off)))
+ (let (overlays)
+ (while (< (point) end)
+ (let* ((group-end (+ (point) 3))
+ (ov (make-overlay (point) group-end)))
+ (overlay-put ov 'before-string ".")
+ (overlay-put ov 'evaporate t)
+ (push ov overlays)
+ (goto-char group-end)))
+ overlays)))
+
+(defun number-format--jit-lock (beg end)
+ (let ((line-beg (save-excursion (goto-char beg) (line-beginning-position)))
+ (line-end (save-excursion (goto-char end) (line-end-position))))
+ (number-unformat-region line-beg line-end)
+ (number-format-region line-beg line-end)))
+
+;;;###autoload
+(defun number-format-region (beg end)
+ "Format numbers between BEG and END.
+When called interactively, format numbers in the active region."
+ (interactive "r")
+ (save-excursion
+ (goto-char beg)
+ (save-restriction
+ (narrow-to-region beg end)
+ (number-unformat-region beg end)
+ (while (re-search-forward number-format--regexp nil :noerror)
+ (save-excursion
+ (cl-destructuring-bind (beg end) (match-data)
+ (let ((ov (make-overlay beg end nil nil :rear-advance)))
+ (overlay-put ov 'evaporate t)
+ (dolist (sym '(insert-behind-hooks
+ insert-in-front-hooks
+ modification-hooks))
+ (overlay-put ov sym '(number-format--adjust-overlays)))
+ (puthash ov (number-format--at-range beg end)
+ number-format--overlays))))))))
+
+;;;###autoload
+(defun number-unformat-region (beg end)
+ "Unformat numbers between BEG and END.
+When called interactively, unformat numbers in the active region."
+ (interactive "r")
+ (dolist (ov (overlays-in beg end))
+ (when-let ((overlays (gethash ov number-format--overlays)))
+ (mapcar #'delete-overlay overlays)
+ (remhash ov number-format--overlays)
+ (delete-overlay ov))))
+
+;;;###autoload
+(defun number-format-buffer ()
+ "Format numbers in the current buffer."
+ (interactive)
+ (number-format-region (point-min) (point-max)))
+
+;;;###autoload
+(defun number-unformat-buffer ()
+ "Unformat numbers in the current buffer."
+ (interactive)
+ (number-unformat-region (point-min) (point-max)))
+
+;;;###autoload
+(define-minor-mode number-format-mode
+ "TODO"
+ :lighter " Number-Format"
+ :group 'number-format
+ (number-unformat-buffer)
+ (if number-format-mode
+ (jit-lock-register #'number-format--jit-lock)
+ (jit-lock-unregister #'number-format--jit-lock)))
+
+(provide 'number-format) \ No newline at end of file