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
|
;;; keybindings --- General Keyboard Shortcuts -*- lexical-binding: t; coding: utf-8; -*-
;; author: Craig Jennings <c@cjennings.net>
;;; Commentary:
;; Commonly used files should be easy to jump to. The "jump-to" keymap has the
;; "C-c j" prefix and immediately opens files defined in user-constants.el.
;; "Hostile Keybindings" are those that are close to keybindings I use commonly
;; so they're easy to hit by accident, but they have painful results. I'd
;; rather avoid the pain by unsetting they keybindings and view the error '<key>
;; is undefined' message. Finally, I'm providing messages to train me to use
;; faster keybindings and provide feedback when evaluating buffers.
;;; Code:
;; Loaded earlier in init.el
(eval-when-compile (require 'user-constants))
;; ------------------------------- Custom Keymap -------------------------------
(defvar-keymap cj/custom-keymap
:doc "User custom prefix keymap base for nested keymaps.")
(keymap-global-set "C-;" cj/custom-keymap)
;; ------------------------------ Jump To Commands -----------------------------
(defun cj/jump-open-var (var)
"Open the file whose path is stored in VAR.
Errors if VAR is unbound, not a non-empty string, or the file does not exist."
(unless (boundp var)
(user-error "Variable %s is not bound" var))
(let ((path (symbol-value var)))
(unless (and (stringp path) (> (length path) 0))
(user-error "Variable %s does not contain a valid file path" var))
(unless (file-exists-p path)
(user-error "File does not exist: %s" path))
(find-file path)))
(defconst cj/jump--specs
'(("r" reference reference-file)
("s" schedule schedule-file)
("i" inbox inbox-file)
("c" contacts contacts-file)
("m" macros macros-file)
("n" reading-notes reading-notes-file)
("w" webclipped webclipped-file)
("g" gcal gcal-file)
("I" emacs-init emacs-init-file))
"Specs for jump commands: each entry is (KEY NAME-SYM VAR-SYM).")
(defvar-keymap cj/jump-map
:doc "Key map for quick jumps to commonly used files.")
;; Define commands and populate the keymap from the specs.
(dolist (spec cj/jump--specs)
(pcase-let ((`(,key ,name ,var) spec))
(let* ((fn (intern (format "cj/jump-to-%s" name)))
(doc (format "Open the file from variable `%s'." var)))
;; Define a named command that opens the file from VAR.
(defalias fn
`(lambda ()
,doc
(interactive)
(cj/jump-open-var ',var)))
;; Bind it under the prefix map.
(keymap-set cj/jump-map key fn))))
;; Bind the prefix globally (user-reserved prefix).
(keymap-global-set "C-c j" cj/jump-map)
;; nicer prefix label in which-key
(with-eval-after-load 'which-key
(which-key-add-key-based-replacements "C-c j" "Jump to common files."))
;; ---------------------------- Keybinding Discovery ---------------------------
(use-package free-keys
:commands (free-keys)
:bind (:map help-map
("C-k" . free-keys)))
(use-package which-key
:commands (which-key-mode)
:hook (emacs-startup . which-key-mode)
:custom
(which-key-idle-delay 1.0)
(which-key-popup-type 'side-window)
;; :init
;; ;; Load + enable after a short idle so it doesn't count toward startup.
;; (run-with-idle-timer 0.5 nil
;; (lambda ()
;; (require 'which-key nil t)
;; ;; Ensure config has applied, then enable the mode.
;; (with-eval-after-load 'which-key
;; (unless (bound-and-true-p which-key-mode)
;; (which-key-mode 1)))))
:config
(which-key-setup-side-window-bottom)
;; never show keybindings that have been 'cj/disabled'
(push '((nil . "cj/disabled") . t) which-key-replacement-alist))
;; ---------------------------- General Keybindings ----------------------------
;; Avoid hostile bindings
(keymap-global-unset "C-x C-f") ;; find-file-read-only
(keymap-global-set "C-x C-f" #'find-file)
(keymap-global-unset "C-z") ;; suspend-frame is accidentally hit often
(keymap-global-unset "M-o") ;; facemenu-mode
;; Add commonly-used general keybindings
(keymap-global-set "M-*" #'calculator)
(keymap-global-set "M-Y" #'yank-media)
;; Normally bound to ESC ESC ESC, hit ESC once to get out of unpleasant situations.
(keymap-global-set "<escape>" #'keyboard-escape-quit)
;; remap C-x \ to sort-lines (from remap activate-transient-input-method)
(keymap-global-unset "C-x \\")
(keymap-global-set "C-x \\" #'sort-lines)
;; training myself to use C-/ for undo (bound internally) as it's faster.
(keymap-global-unset "C-x u")
(keymap-global-set "C-x u"
#'(lambda () (interactive)
(message (concat "Seriously, " user-name
"? Use 'C-/'. It's faster."))))
(provide 'keybindings)
;;; keybindings.el ends here
|