summaryrefslogtreecommitdiff
path: root/.config/emacs/modules/mm-keybindings.el
blob: a025a82eba8c714d1b505d4e1ed553eadf3be0de (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
;;; 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-:’

^L
;;; Helper Macros

(defmacro mm-keymap-set (keymap &rest definitions)
  (declare (indent 1))
  (unless (cl-evenp (length definitions))
    (user-error "Expected an even-number of elements in DEFINITIONS."))
  `(cl-loop for (from to) on (list ,@definitions) by #'cddr
            do (keymap-set ,keymap from to)))

(defmacro mm-keymap-set-repeating (keymap &rest definitions)
  (declare (indent 1))
  (unless (cl-evenp (length definitions))
    (user-error "Expected an even-number of elements in DEFINITIONS."))
  (let ((keymap-gen (gensym "mm-keybindings--repeat-map-")))
    `(progn
       (defvar-keymap ,keymap-gen)
       (cl-loop for (from to) on (list ,@definitions) by #'cddr
                do (progn
                     (keymap-set ,keymap-gen from to)
                     (put to 'repeat-map ',keymap-gen))))))

(defmacro mm-keymap-remap (keymap &rest commands)
  "Define command remappings for a given KEYMAP.
COMMANDS is a sequence of unquoted commands.  For each pair of COMMANDS
the first command is remapped to the second command."
  (declare (indent 1))
  (unless (cl-evenp (length commands))
    (user-error "Expected an even-number of elements in COMMANDS."))
  (macroexp-progn
   (cl-loop for (from to) in (seq-partition commands 2)
            collect `(keymap-set
                      ,keymap
                      ,(concat "<remap> <" (symbol-name from) ">")
                      #',to))))

^L
;;; 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)

^L
;;; Disable ESC as Meta

(keymap-global-set "<escape>" #'ignore)

^L
;;; 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))

^L
;;; 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
  transpose-chars    e/transpose-previous-chars
  transpose-lines    e/transpose-current-and-next-lines
  yank               e/yank)

(with-eval-after-load 'cc-vars
  (setopt c-backspace-function #'backward-delete-char))

^L
;;; 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’

^L
;;; Bind Commands Globally

(mm-keymap-set global-map
  "<next>"    #'e/scroll-up
  "<prior>"   #'e/scroll-down
  "C-<next>"  #'forward-page
  "C-<prior>" #'backward-page

  "C-." #'repeat
  "C-^" #'e/split-line
  "C-/" #'e/mark-line-dwim

  "C-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))

^L
;;; 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)