about summary refs log tree commit diff stats
path: root/lisp/+key.el
blob: 4638e9552a1fcc9c950f0138517810432e491e10 (plain)
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
;;; +key.el --- minor mode for keymaps -*- lexical-binding: t; -*-

;;; Commentary:

;; Much of the code here was cribbed from https://emacs.stackexchange.com/a/358,
;; which in turn was cribbed in part from
;; https://github.com/kaushalmodi/.emacs.d/blob/master/elisp/modi-mode.el,
;; https://github.com/jwiegley/use-package/blob/master/bind-key.el and
;; elsewhere.

;; The basic idea is to have a minor-mode for my personal key customizations,
;; especially a "leader key" set up à la vim.  In Emacs, I use `C-z' for this
;; leader key, because of its easy location and relative uselessness by default.

;;; Code:

(require 'easy-mmode)
(require 'setup nil t)

;; I need to define this map before the proper mode map.
(defvar +key-leader-map (let ((map (make-sparse-keymap))
                               (c-z (global-key-binding "\C-z")))
                           (define-key map "\C-z" c-z)
                           map)
  "A leader keymap under the \"C-z\" bind.")

;; http://xahlee.info/emacs/emacs/emacs_menu_app_keys.html and
(defvar +key-menu-map (let ((map (make-sparse-keymap)))
                        (define-key map (kbd "<menu>")
                          #'execute-extended-command)
                        map)
  "Custom bindings behind the menu key.")

(defvar +key-mode-map (let ((map (make-sparse-keymap)))
                        (define-key map "\C-z" +key-leader-map)
                        (define-key map (kbd "<menu>") +key-menu-map)
                        map)
  "Keymap for `+key-mode'.")

(defun turn-off-+key-mode ()
  "Turn off `+key-mode'."
  (+key-mode -1))

;;;###autoload
(define-minor-mode +key-mode
  "A minor mode with keybindings that will override every other mode."
  :init-value t
  :lighter " +"
  (if +key-mode
      (progn                            ; Enable
        (add-to-list 'emulation-mode-map-alists
                     `((+key-mode . ,+key-mode-map)))
        ;; Disable in minibuffer
        (add-hook 'minibuffer-setup-hook #'turn-off-+key-mode)
        ;; compat Linux-Windows
        (define-key key-translation-map (kbd "<apps>") (kbd "<menu>"))
        ;; curse you, thinkpad keyboard!!!
        (define-key key-translation-map (kbd "<print>") (kbd "<menu>"))
        )
    ;; Disable
    (setq emulation-mode-map-alists
          (assoc-delete-all '+key-mode emulation-mode-map-alists
                            (lambda (a b)
                              (equal (car a) b))))
    (remove-hook 'minibuffer-setup-hook #'turn-off-+key-mode)
    (define-key key-translation-map (kbd "<print>") nil)
    (define-key key-translation-map (kbd "<apps>") nil)))

;;;###autoload
(defun +key-setup ()
  "Ensure `+key-mode' happens after init."
  (if after-init-time
      (+key-global-mode)
    (add-hook 'after-init-hook #'+key-global-mode)))

;;;###autoload
(define-globalized-minor-mode +key-global-mode +key-mode +key-mode)

;; Extras for `setup'
(with-eval-after-load 'setup
  (setup-define :+key
    (lambda (key command)
      `(define-key +key-mode-map ,key ,command))
    :documentation "Bind KEY to COMMAND in `+key-mode-map'."
    :debug '(form sexp)
    :ensure '(kbd func)
    :repeatable t)
  
  (setup-define :+leader
    (lambda (key command)
      `(define-key +key-leader-map ,key ,command))
    :documentation "Bind KEY to COMMAND in `+key-leader-map'."
    :debug '(form sexp)
    :ensure '(kbd func)
    :repeatable t)

  (setup-define :+menu
    (lambda (key command)
      `(define-key +key-menu-map ,key ,command))
    :documentation "Bind KEY to COMMAND in `+key-leader-map'."
    :debug '(form sexp)
    :ensure '(kbd func)
    :repeatable t))

(provide '+key)
;;; +key.el ends here