-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathcb-use-package-extensions.el
205 lines (170 loc) · 7.38 KB
/
cb-use-package-extensions.el
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
;;; cb-use-package-extensions.el --- Extra keywords for use-package. -*- lexical-binding: t; -*-
;; Copyright (C) 2016 Chris Barrett
;; Author: Chris Barrett <[email protected]>
;; Package-Requires: ((use-package "20160706.1520") (dash "20160619.611"))
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Adds extra keywords to `use-package'.
;;
;; 1. `:evil-bind'
;;
;; `:evil-bind' provides a mechanism for setting up evil keybindings, similar
;; to the `:bind' keyword.
;;
;; The value for `:evil-bind' is a list, which should start with the keyword
;; `:state' followed by a symbol representing the evil state for the
;; subsequent bindings.
;;
;; (use-package foo
;; :evil-bind (:state normal
;; ("a" . foo)
;; ("b" . bar)))
;;
;; Bindings are specified as `(KEY-SEQUENCE . FUNCTION)' pairs, and can be
;; interleaved with further `:state' declarations to declare bindings for
;; different states:
;;
;; (use-package foo
;; :evil-bind (:state normal
;; ("a" . foo)
;; :state insert
;; ("b" . bar)))
;;
;; Bindings specified in this way are global evil keybindings, defined using
;; `evil-global-set-key'.
;;
;; It is possible to declare bindings for certain maps, by using the `:map'
;; keyword followed by the name of a keymap. Subsequent keybinding pairs are
;; defined only when that keymap is active, using `evil-define-key'.
;;
;; The example below demonstrates setting a global binding in normal state,
;; as well as a mode-specific binding in insert state:
;;
;; (use-package foo
;; :evil-bind (:state normal
;; ("a" . foo)
;; :state insert
;; :map foo-mode-map
;; ("b" . bar)))
;;
;; 2. `:leader-bind'
;;
;; `:leader-bind' provides a way to declare Spacemacs leader key bindings. It
;; takes a list of conses, similar to `:evil-bind'.
;;
;; (use-package foo
;; :leader-bind (("a" . foo)
;; ("b" . bar)))
;;
;; By default, bindings are set for all modes. The `:mode' keyword and a
;; major-mode name can be inserted into the list to set those bindings for the
;; major mode prefix instead.
;;
;; (use-package foo
;; :leader-bind (("a" . foo)
;; :mode foo-mode
;; ("b" . bar)))
;;; Code:
(require 'use-package)
(require 'dash)
(defun use-package-normalize/:evil-bind (name keyword args)
(use-package-as-one (symbol-name keyword) args
(lambda (label args)
(use-package-normalize-pairs name label args nil t nil))))
(defun use-package-handler/:evil-bind
(name _kw args rest state)
(let ((commands (-keep #'cdr-safe (-filter #'consp args))))
(use-package-concat
(use-package-process-keywords name
(use-package-sort-keywords (use-package-plist-maybe-put rest :defer t))
(use-package-plist-append state :commands commands))
`((ignore
(with-eval-after-load 'evil
,@(->>
;; Traverse `args' pairwise to process keyword-value pairs.
(-zip-pair args (-snoc (cdr args) nil))
(--keep
(-let (((&plist :evil-state s :map keymap) state)
((fst . snd) (when (listp it) it)))
(cond
;; Assume the current item is a (:KEYWORD . VALUE) pair. Update the state based on that value.
((equal :map fst)
(setq state (plist-put state :map snd))
nil)
((equal :state fst)
(setq state (plist-put state :evil-state snd))
nil)
;; Assume the current item is a (VALUE@i . VALUE@i+1) pair.
;; Ignore the second element and just process the first.
((and (consp fst) keymap)
(unless s
(use-package-error (format "No evil state declared before: %s" fst)))
(-let [(k . fn) fst]
`(evil-define-key ',s
,keymap
,(if (stringp k) `(kbd ,k) k)
#',fn)))
((consp fst)
(unless s
(use-package-error (format "No evil state declared before: %s" fst)))
(-let [(k . fn) fst]
`(evil-global-set-key ',s
,(if (stringp k) `(kbd ,k) k)
#',fn)))
;; A symbol is presumed to be the value of a previous kvp.
((symbolp fst)
nil)
;; Anything else is invalid.
(t
(use-package-error (format "Expected :map, :state or (KEY . FN), but got: %s"
fst)))))))))))))
(defun use-package-normalize/:leader-bind (name keyword args)
(use-package-as-one (symbol-name keyword) args
(lambda (label args)
(use-package-normalize-pairs name label args nil t nil))))
(defun use-package-handler/:leader-bind
(name _kw args rest state)
(let ((commands (-keep #'cdr-safe (-filter #'consp args))))
(use-package-concat
(use-package-process-keywords name
(use-package-sort-keywords (use-package-plist-maybe-put rest :defer t))
(use-package-plist-append state :commands commands))
`((ignore
,@(->>
;; Traverse `args' pairwise to process keyword-value pairs.
(-zip-pair args (-snoc (cdr args) nil))
(--keep
(-let (((&plist :mode mode) state)
((fst . snd) (when (listp it) it)))
(cond
;; Assume the current item is a (:KEYWORD . VALUE) pair. Update the state based on that value.
((equal :mode fst)
(setq state (plist-put state :mode snd))
nil)
;; Assume the current item is a (VALUE@i . VALUE@i+1) pair.
;; Ignore the second element and just process the first.
((and mode (consp fst))
(-let [(k . fn) fst]
`(spacemacs/set-leader-keys-for-major-mode ',mode ,k #',fn)))
((consp fst)
(-let [(k . fn) fst]
`(spacemacs/set-leader-keys ,k #',fn)))
;; A symbol is presumed to be the value of a previous kvp.
((symbolp fst)
nil)
;; Anything else is invalid.
(t
(use-package-error (format "Expected :mode or (KEY . FN), but got: %s" fst))))))))))))
(add-to-list 'use-package-keywords :leader-bind t)
(add-to-list 'use-package-keywords :evil-bind t)
(provide 'cb-use-package-extensions)
;;; cb-use-package-extensions.el ends here