-
Notifications
You must be signed in to change notification settings - Fork 0
/
parevil.el
346 lines (272 loc) · 12 KB
/
parevil.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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
;;;; Dependencise
(require 'evil)
(require 'paredit)
(autoload 'enable-paredit-mode "paredit" "Turn on pseudo-structural editing of Lisp code." t) ;; Load Paredit (?)
(add-hook 'emacs-lisp-mode-hook 'enable-paredit-mode) ;; Enable Paredit for Elisp Editing
(add-hook 'lisp-mode-hook 'enable-paredit-mode) ;; Enable Paredit for CL Editing
(add-hook 'lisp-interaction-mode-hook 'enable-paredit-mode) ;; Enable Paredit for Lisp Interaction Mode
(add-hook 'scheme-mode-hook 'enable-paredit-mode) ;; Enable Paredit for Scheme Editing
(add-hook 'slime-repl-mode-hook (lambda () (paredit-mode +1))) ;; Enable Paredit for Slime REPL
(add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode) ;; Enable Paredit for Minibuffer
;;;; Part A -- Evil Paredit Code
;;; evil-paredit.el --- Paredit support for evil keybindings
;;
;; Copyright (C) 2012 Roman Gonzalez
;;
;; Author: Roman Gonzalez <[email protected]>
;; Mantainer: Roman Gonzalez <[email protected]>
;; Keywords: paredit, evil
;;
;; This file is NOT part of GNU Emacs.
;;
;; This file is free software (MIT License)
;; Version: 0.0.2
;; URL: https://github.com/roman/evil-paredit
;; Package-Requires: ((evil "1.0.9") (paredit "25beta"))
;;; Code:
;;;###autoload
(define-minor-mode evil-paredit-mode
"Minor mode for setting up Evil with paredit in a single buffer"
:keymap '()
(let ((prev-state evil-state))
(evil-normal-state)
(evil-change-state prev-state)))
(defun -evil-paredit-check-region (beg end)
(if (fboundp 'paredit-check-region-state)
(if (and beg end)
;; Check that region begins and ends in a sufficiently similar
;; state, so that deleting it will leave the buffer balanced.
(save-excursion
(goto-char beg)
(let* ((state (paredit-current-parse-state))
(state* (parse-partial-sexp beg end nil nil state)))
(paredit-check-region-state state state*))))
(paredit-check-region-for-delete beg end)))
(evil-define-operator evil-paredit-yank (beg end type register yank-handler)
"Saves the characters in motion into the kill-ring."
:move-point nil
:repeat nil
(interactive "<R><x><y>")
(-evil-paredit-check-region beg end)
(cond
((eq type 'block)
(evil-yank-rectangle beg end register yank-handler))
((eq type 'line)
(evil-yank-lines beg end register yank-handler))
(t
(evil-yank-characters beg end register yank-handler))))
(evil-define-operator evil-paredit-yank-line (beg end type register)
"Saves whole lines into the kill-ring."
:motion evil-line
:move-point nil
(interactive "<R><x>")
(let* ((beg (point))
(end (evil-paredit-kill-end)))
(evil-paredit-yank beg end type register)))
(evil-define-operator evil-paredit-delete
(beg end type register yank-handler)
"Delete text from BEG to END with TYPE respecting parenthesis.
Save in REGISTER or in the kill-ring with YANK-HANDLER."
(interactive "<R><x><y>")
(evil-paredit-yank beg end type register yank-handler)
(if (eq type 'block)
(evil-apply-on-block #'delete-region beg end nil)
(delete-region beg end))
;; place cursor on beginning of line
(when (and (evil-called-interactively-p)
(eq type 'line))
(evil-first-non-blank)))
(evil-define-operator evil-paredit-delete-line
(beg end type register yank-handler)
"Delete to end of line respecting parenthesis."
:motion nil
:keep-visual t
(interactive "<R><x>")
(let* ((beg (point))
(end (evil-paredit-kill-end)))
(evil-paredit-delete beg end
type register yank-handler)))
(defun evil-paredit-kill-end ()
"Returns the position where paredit-kill would kill to"
(when (paredit-in-char-p) ; Move past the \ and prefix.
(backward-char 2)) ; (# in Scheme/CL, ? in elisp)
(let* ((eol (point-at-eol))
(end-of-list-p (save-excursion
(paredit-forward-sexps-to-kill (point) eol))))
(if end-of-list-p (progn (up-list) (backward-char)))
(cond ((paredit-in-string-p)
(if (save-excursion (paredit-skip-whitespace t (point-at-eol))
(eolp))
(kill-line)
(save-excursion
;; Be careful not to split an escape sequence.
(if (paredit-in-string-escape-p)
(backward-char))
(min (point-at-eol)
(cdr (paredit-string-start+end-points))))))
((paredit-in-comment-p)
eol)
(t (if (and (not end-of-list-p)
(eq (point-at-eol) eol))
eol
(point))))))
(evil-define-operator evil-paredit-change
(beg end type register yank-handler delete-func)
"Change text from BEG to END with TYPE respecting parenthesis.
Save in REGISTER or the kill-ring with YANK-HANDLER.
DELETE-FUNC is a function for deleting text, default `evil-delete'.
If TYPE is `line', insertion starts on an empty line.
If TYPE is `block', the inserted text in inserted at each line
of the block."
(interactive "<R><x><y>")
(let ((delete-func (or delete-func #'evil-paredit-delete))
(nlines (1+ (- (line-number-at-pos end)
(line-number-at-pos beg)))))
(funcall delete-func beg end type register yank-handler)
(cond
((eq type 'line)
(evil-open-above 1))
((eq type 'block)
(evil-insert 1 nlines))
(t
(evil-insert 1)))))
(evil-define-operator evil-paredit-change-line
(beg end type register yank-handler)
"Change to end of line respecting parenthesis."
:motion evil-end-of-line
(interactive "<R><x><y>")
(let* ((beg (point))
(end (evil-paredit-kill-end)))
(evil-paredit-change beg end type register yank-handler)))
(defun evil-paredit-change-whole-line ()
"Change whole line."
(interactive)
(beginning-of-line)
(evil-paredit-change-line nil nil)
(indent-according-to-mode))
(evil-define-key 'normal evil-paredit-mode-map
(kbd "d") 'evil-paredit-delete
(kbd "c") 'evil-paredit-change
(kbd "y") 'evil-paredit-yank
(kbd "D") 'evil-paredit-delete-line
(kbd "C") 'evil-paredit-change-line
(kbd "S") 'evil-paredit-change-whole-line
(kbd "Y") 'evil-paredit-yank-line
(kbd "X") 'paredit-backward-delete
(kbd "x") 'paredit-forward-delete)
(provide 'evil-paredit)
(add-hook 'emacs-lisp-mode-hook 'evil-paredit-mode)
(add-hook 'lisp-mode-hook 'evil-paredit-mode)
(add-hook 'lisp-interaction-mode-hook 'evil-paredit-mode)
(add-hook 'scheme-mode-hook 'evil-paredit-mode)
(add-hook 'slime-repl-mode-hook 'evil-paredit-mode)
;;; evil-paredit.el ends here
;;;; Part B - ParEvil Code
;; EVIL / Paredit Bindings
;; Cut all remaining expressions in a group
(define-key evil-normal-state-map "gs"
(lambda ()
(interactive)
(let ((starting-point (point))
(ending-point nil))
(save-excursion
(paredit-backward-up)
(evil-jump-item)
(setq ending-point (point)))
(kill-region starting-point ending-point))))
;; Copy all remaining expressions in a group
(define-key evil-normal-state-map "gy"
(lambda ()
(interactive)
(let ((starting-point (point))
(ending-point nil))
(save-excursion
(paredit-backward-up)
(evil-jump-item)
(setq ending-point (point)))
(kill-ring-save starting-point ending-point))))
(evil-define-state paredit
"Paredit state."
:tag " <P> "
:enable (normal))
(setq evil-paredit-state-cursor '(box "purple1"))
;; Escape & Lisp States
(define-key evil-paredit-state-map [escape] (lambda () (interactive) (evil-normal-state)))
(define-key evil-paredit-state-map (kbd "SPC") (lambda () (interactive) (evil-normal-state)))
(defun evil-paredit-normal-state-local-map ()
(define-key evil-normal-state-local-map (kbd "SPC") (lambda () (interactive) (evil-paredit-state)))
;; (define-key evil-insert-state-local-map [escape] 'evil-paredit-state)
)
(add-hook 'emacs-lisp-mode-hook 'evil-paredit-normal-state-local-map)
(add-hook 'lisp-mode-hook 'evil-paredit-normal-state-local-map)
(add-hook 'lisp-interaction-mode-hook 'evil-paredit-normal-state-local-map)
(add-hook 'scheme-mode-hook 'evil-paredit-normal-state-local-map)
(add-hook 'slime-repl-mode-hook 'evil-paredit-normal-state-local-map)
;; Lisp Keys
;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Expressions.html
;; Lets Unbind s (evil-subsitute) to use it for various keys, and make it ss now
(define-key evil-paredit-state-map "s" nil)
(define-key evil-paredit-state-map "ss" 'evil-substitute)
;; Motion Commands
(define-key evil-paredit-state-map "f" 'paredit-forward) ;; C-M-f paredit-forward
(define-key evil-paredit-state-map "b" 'paredit-backward) ;; C-M-b paredit-backward
(define-key evil-paredit-state-map "n" 'paredit-forward-down) ;; C-M-d paredit-forward-down
(define-key evil-paredit-state-map "w" 'paredit-backward-up) ;; C-M-u paredit-backward-up
(define-key evil-paredit-state-map "gn" 'paredit-forward-up) ;; C-M-n paredit-forward-up
(define-key evil-paredit-state-map "gp" 'paredit-backward-down) ;; C-M-p paredit-backward-down
(define-key evil-paredit-state-map "q" 'beginning-of-defun) ;; C-M-a beginning-of-defun
;; (define-key evil-paredit-state-map "w" (lambda ()
;; (interactive)
;; (forward-sexp 2)
;; (backward-sexp))) ;; C-M-f Go to beginning of next word
;; Slurp / Barf
(define-key evil-paredit-state-map "sp" 'paredit-backward-slurp-sexp) ;; C-( paredit-backward-slurp-sexp
(define-key evil-paredit-state-map "sb" 'paredit-forward-slurp-sexp) ;; C-) paredit-forward-slurp-sexp
(define-key evil-paredit-state-map "(" 'paredit-open-round) ;; ( Previously evil-search-word-forward
(define-key evil-paredit-state-map ")" 'paredit-close-round) ;; ) Previously evil-forward-sentence-begin
(define-key evil-paredit-state-map "{" 'paredit-backward-barf-sexp) ;; C-{ paredit-backward-barf-sexp
(define-key evil-paredit-state-map "}" 'paredit-forward-barf-sexp) ;; C-} paredit-forward-barf-sexp
;; Fix M-. for ParEdit Mode (in Normal mode it is evil-repeat-pop-next)
(define-key evil-paredit-state-map (kbd "M-.") 'xref-find-definitions) ;; Previously evil-repeat-pop-next
;; Other Commands
(define-key evil-paredit-state-map "gr" 'paredit-raise-sexp) ;; M-r paredit-raise-sexp
(define-key evil-paredit-state-map "gl" 'paredit-splice-sexp) ;; M-s paredit-splice-sexp
(define-key evil-paredit-state-map "gw" 'paredit-wrap-round) ;; M-( Paredit Wrap Around
(define-key evil-paredit-state-map "gh" 'paredit-recenter-on-sexp)
(define-key evil-paredit-state-map "ge" 'indent-region)
;; Transpose Sexps
(define-key evil-paredit-state-map "t" 'transpose-sexps)
(define-key evil-paredit-state-map "T" (lambda () (interactive) (transpose-sexps -1)))
;; Cut / Copying in Evil Paredit -- C-M-SPC is mark-sexp in paredit mode
;; Notes here https://www.gnu.org/software/emacs/manual/html_node/elisp/Interactive-Call.html
;; Credits Lampilelo on #Emacs for kill-ring-save mark / point
;; p is for prefix-arg
;; Undo
;; (define-key evil-paredit-state-map "su"
;; (lambda (arg)
;; (interactive "p")
;; (evil-undo arg)))
;; Select
(define-key evil-paredit-state-map "se"
(lambda (arg)
(interactive "p")
(mark-sexp arg)))
;; Cut
(define-key evil-paredit-state-map "sd"
(lambda (arg)
(interactive "p")
(mark-sexp arg)
(kill-region (mark) (point) 'region)))
;; Copy
(define-key evil-paredit-state-map "sy"
(lambda (arg)
(interactive "p")
(mark-sexp arg)
(kill-ring-save (mark) (point) 'region)
(message "Copied sexps")))
;; Fix pasting in evil-paredit-state
(define-key evil-paredit-state-map "p"
(lambda ()
(interactive)
(evil-paste-before 1)
(forward-char 1)))