d04834524d058e1092343b48a577108b49a81109
[dotfiles.git] / emacs.d / emacs-evil.org
1 #+TITLE:Emacs Evil Config
2 #+AUTHOR: Peng Li
3 #+EMAIL: seudut@gmail.com
4  
5 As the =Evil= mode is significant, and has lots of configurations, it's better put them 
6 in a separate file.
7
8 * Evil mode 
9 ** Install and basic config
10 https://www.emacswiki.org/emacs/Evil.
11 =global-evil-leader-mode= should be set before =evil-mode=.
12 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
13   (use-package evil
14     :ensure t
15     :init
16     ;; (setq evil-default-state 'emacs)
17     (setq evil-emacs-state-cursor '("red" box))
18     (setq evil-normal-state-cursor '("green" box))
19     (setq evil-motion-state-cursor '("green" box))
20     (setq evil-visual-state-cursor '("orange" box))
21     (setq evil-insert-state-cursor '("red" bar))
22     (setq evil-replace-state-cursor '("red" bar))
23     (setq evil-operator-state-cursor '("red" hollow))
24     ;; others, don't move back cursor when exit insert mode
25     ;; (setq evil-move-cursor-back nil)
26     :config
27     (use-package evil-leader
28       :ensure t
29       :init
30       :config
31       (evil-leader/set-leader ";")
32       (global-evil-leader-mode))
33     ;; (require 'evil-leader)
34     (evil-mode t))
35
36   (add-hook 'prog-mode-hook #'(lambda ()
37                                 (modify-syntax-entry ?_ "w")
38                                 ;; (modify-syntax-entry ?- "w")
39                                 ))
40 #+END_SRC
41
42 ** Initial mode and state config
43 - Use =normal= as the default state but exclude some special modes.
44 - Bind =[escape]=  to =normal= mode. This only works on GUI Emacs. If need to work on Terminal, shoudl also bind =(kbd
45   "<ESC>)=, but this will make the combined key =M-= not wor.
46 - Not alias =insert= state to =emacs= state, as it break some vi's feature in insert mode, such as column edit. Instead,
47   here add a advice function to change the sate as emacs when enter insert mode, but this is only limited in some
48   certain modes.
49 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
50   (defvar my-mode-list-to-use-emacs-as-insert '(emacs-lisp-mode
51                                                 org-mode
52                                                 eshell-mode
53                                                 lisp-interaction-mode)
54     "The mode in this list will consider insert state as emacs state by adding `advice-add' below.")
55
56   (defvar my-modes-use-emacs-init '(emacs-lisp-mode
57                                     org-mode
58                                     lisp-interaction-mode
59                                     eshell-mode
60                                     text-mode
61                                     package-menu-mode
62                                     paradox-menu-mode)
63     "The mode in this list will use emacs sate as a initial evil state.")
64
65   (with-eval-after-load "evil"
66     (setq evil-default-state 'normal)
67       ;; (defalias 'evil-inset-mode 'evil-emacs-state)
68     (define-key evil-emacs-state-map [escape] 'evil-normal-state)
69     ;; (define-key evil-emacs-state-map (kbd "<ESC>") 'evil-normal-state)
70     (dolist (mode my-modes-use-emacs-init) (evil-set-initial-state mode 'emacs))
71     (advice-add 'evil-insert-state :after (lambda (&optional arg)
72                                             (when (memq major-mode my-mode-list-to-use-emacs-as-insert)
73                                               (evil-emacs-state)))))
74 #+END_SRC
75
76 * Evil-escape
77 [[https://github.com/syl20bnr/evil-escape][evil-escape]], escape from anything with customizable key sequence.
78 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
79   (use-package evil-escape
80     :ensure t
81     :init
82     (setq-default evil-escape-delay 0.2)
83     (setq-default evil-escape-key-sequence "jj")
84     (setq-default evil-escape-excluded-states '(normal visual motion emacs))
85     (setq-default evil-escape-excluded-major-modes '(emacs-lisp-mode org-mode))
86     :config
87     (evil-escape-mode))
88 #+END_SRC
89
90 * other extention
91 ** Evil-matchit
92 [[https://github.com/redguardtoo/evil-matchit]]
93 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
94   (use-package evil-matchit
95     :ensure t
96     :config
97     (global-evil-matchit-mode 1))
98 #+END_SRC
99
100 ** Evil-visualstar
101 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
102   (use-package evil-visualstar
103     :ensure t
104     :init
105     (setq evil-visualstar/persistent t)
106     :config
107     (global-evil-visualstar-mode))
108 #+END_SRC
109
110 ** Evil-surround
111 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
112   (use-package evil-surround
113     :ensure t
114     :config
115     (global-evil-surround-mode 1))
116 #+END_SRC
117 * Key bindings
118 ** Evil-Leader
119 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
120   (defun sd/swith-to-buffer ()
121     "switch to buffer"
122     (interactive)
123     (if (projectile-project-p)
124         (projectile-switch-to-buffer)
125       (ivy-switch-buffer)))
126
127   (ivy-set-actions
128    'sd/swith-to-buffer
129    '(("j" ivy--switch-buffer-other-window-action "other window")))
130
131   (with-eval-after-load "evil-leader"
132     (cl-loop for (key . fun ) in '(("F" . counsel-projectile-switch-to-buffer)
133                                    ("f" . sd/swith-to-buffer)
134                                    ("b" . counsel-projectile-find-file)
135                                    ("r" . ivy-recentf)
136                                    ("w" . save-buffer)
137                                    ("v" . evil-window-vsplit)
138                                    ("s" . evil-window-split)
139                                    ("t" . sd/hydra-gtags/body)
140                                    ("p" . sd/hydra-projectile/body)
141                                    ("q" . evil-quit)
142                                    ("g" . magit-status)
143                                    ("e" . sd/toggle-project-eshell)
144                                    ("d" . dired)
145                                    ("h" . help))
146              do (evil-leader/set-key key fun)))
147 #+END_SRC
148 ** Basic state bindings
149 There are three kinds key bindings
150 - prefix key is the leader key, defined by evil-leader.
151 - prefix key is the =Ctrl=,
152 - prefix key is =\=, 
153
154 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
155   (with-eval-after-load "evil"
156     (mapc (lambda (map)
157             (define-key map "\C-W s" 'evil-window-split)
158             (define-key map "\C-W v" 'evil-window-vsplit)
159             (define-key map "\C-h" 'evil-window-left)
160             (define-key map "\C-j" 'evil-window-down)
161             (define-key map "\C-k" 'evil-window-up)
162             (define-key map "\C-l" 'evil-window-right)
163             (define-key map (kbd "C->") (lambda () (interactive) (evil-window-increase-width 3)))
164             (define-key map (kbd "C-<") (lambda () (interactive) (evil-window-decrease-width 3)))
165             (define-key map (kbd "C-+") (lambda () (interactive) (evil-window-increase-height 3)))
166             (define-key map (kbd "C--") (lambda () (interactive) (evil-window-decrease-height 3)))
167             (define-key map (kbd "C-=") (lambda () (interactive) (balance-windows)))
168             ;; As ; has been defined as leader, so remap , to ; repeaat t/f
169             (define-key map (kbd ",") 'evil-repeat-find-char))
170           (list evil-normal-state-map evil-motion-state-map))
171
172     ;; insert state
173     (cl-loop for (key-sequence . fun) in '(("C-;" . iedit-mode)
174                                            ("C-n" . next-line)
175                                            ("C-p" . previous-line)
176                                            ("C-a" . move-beginning-of-line)
177                                            ("C-e" . move-end-of-line)
178                                            ("C-h" . delete-backward-char)
179                                            ("C-k" . kill-line))
180              do (define-key evil-insert-state-map (kbd key-sequence) fun))
181
182     ;; remap some vim keybindings
183     (dolist (map (list
184                   evil-normal-state-map
185                   evil-visual-state-map
186                   evil-motion-state-map))
187       (cl-loop for (keys . fun) in '(("'" . evil-goto-mark)
188                                      ("`" . evil-goto-mark-line))
189                do (define-key map (kbd keys) fun)))
190     
191     
192     
193     ;; motion mode
194     ;; (define-key evil-motion-state-map (kbd "SPC") 'scroll-up-command)
195     ;; (define-key evil-motion-state-map (kbd "S-SPC") 'scroll-down-command)
196     )
197
198
199   ;; (keymapp (car (list evil-normal-state-map evil-visual-state-map)))
200
201   ;; (keymapp (car '(evil-normal-state-map evil-visual-state-map)))
202   ;; (keymapp (car `(,evil-normal-state-map ,evil-visual-state-map)))
203
204
205   ;; (keymapp evil-normal-state-map)
206   ;; (keymapp 'evil-normal-state-map)
207   ;; (keymapp `,evil-normal-state-map)
208 #+END_SRC
209
210
211 Let the search highlight persistent, https://stackoverflow.com/questions/25768036/emacs-evil-non-incremental-search-and-persistent-highlighting/34252236
212 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
213   (evil-select-search-module 'evil-search-module 'evil-search)
214
215   (with-eval-after-load "evil"
216     (define-key evil-normal-state-map "\\" nil)
217     (define-key evil-normal-state-map "\\\\" #'evil-ex-nohighlight)
218     (define-key evil-normal-state-map "\\f" #'describe-function)
219     (define-key evil-normal-state-map "\\v" #'describe-variable))
220 #+END_SRC
221
222 ** Eshell
223 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
224   (add-hook 'eshell-mode-hook (lambda ()
225                                 (when (and (boundp 'evil-mode) evil-mode)
226                                   (dolist (key-fun '(("f" . ivy-switch-buffer)
227                                                      ("b" . counsel-projectile-find-file)
228                                                      ("r" . counsel-recentf)
229                                                      ("t" . sd/hydra-window-layout/body)
230                                                      ("e" . sd/toggle-project-eshell)
231                                                      ("d" . dired)
232                                                      ("'" . other-window)
233                                                      ("h" . help)
234                                                      ("q" . evil-quit)))
235                                     (evil-define-key 'emacs eshell-mode-map (kbd (concat evil-leader/leader (car key-fun))) (cdr key-fun))))
236                                 ;; (define-key eshell-mode-map (kbd "C-j") nil)
237                                 ))
238 #+END_SRC
239 ** Dired mode
240 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
241   (with-eval-after-load "evil"
242     ;; file and directory explore
243     (define-key dired-mode-map (kbd "C-h") nil)
244     (define-key dired-mode-map (kbd "C-k") nil)
245     (evil-define-key 'normal dired-mode-map (kbd "H") 'dired-omit-mode)
246     (evil-define-key 'normal dired-mode-map (kbd "g") 'dired-goto-file)
247     (evil-define-key 'normal dired-mode-map (kbd "r") 'revert-buffer)
248     (evil-define-key 'normal dired-mode-map (kbd "i") 'dired-maybe-insert-subdir)
249     (evil-define-key 'normal dired-mode-map (kbd "TAB") 'diredp-next-subdir)
250     (evil-define-key 'normal dired-mode-map (kbd "J") 'diredp-next-subdir)
251     (evil-define-key 'normal dired-mode-map (kbd "K") 'diredp-prev-subdir)
252     (evil-define-key 'normal dired-mode-map (kbd "l") 'dired-display-file)
253     (evil-define-key 'normal dired-mode-map (kbd "f") 'dired-narrow)
254     (evil-define-key 'normal dired-mode-map (kbd "j") 'sd/dired-next-line)
255     (evil-define-key 'normal dired-mode-map (kbd "k") 'sd/dired-previous-line)
256     (evil-define-key 'normal dired-mode-map (kbd "h") 'sd/dired-up-directory)
257     (evil-define-key 'normal dired-mode-map [C-backspace] 'dired-up-directory)
258     ;; file and folder deletion
259     (evil-define-key 'normal dired-mode-map (kbd "m") 'dired-mark)
260     (evil-define-key 'normal dired-mode-map (kbd "u") 'dired-unmark)
261     (evil-define-key 'normal dired-mode-map (kbd "U") 'dired-unmark-all-marks)
262     (evil-define-key 'normal dired-mode-map (kbd "z") #'sd/dired-get-size)
263     (evil-define-key 'normal dired-mode-map (kbd "d") 'dired-flag-file-deletion)
264     (evil-define-key 'normal dired-mode-map (kbd "x") 'dired-do-flagged-delete)
265     (evil-define-key 'normal dired-mode-map (kbd "D") 'dired-do-delete)
266     ;; File and folder creation
267     (evil-define-key 'normal dired-mode-map (kbd "c") 'sd/dired-new-file)
268     (evil-define-key 'normal dired-mode-map (kbd "+") 'dired-create-directory)
269     (evil-define-key 'normal dired-mode-map (kbd "C") 'dired-do-copy)
270     (evil-define-key 'normal dired-mode-map (kbd "R") 'dired-do-rename)
271
272     ;; keep some normap mapping
273     (evil-define-key 'normal dired-mode-map (kbd "/") 'evil-ex-search-forward)
274     (evil-define-key 'normal dired-mode-map (kbd "n") 'evil-search-next)
275     (evil-define-key 'normal dired-mode-map (kbd "N") 'evil-search-previous)
276     (evil-define-key 'normal dired-mode-map (kbd "v") 'evil-visual-char))
277
278 #+END_SRC
279
280 ** expand region
281 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
282   ;; (with-eval-after-load "evil"
283   ;;   (with-eval-after-load "expand-region"
284   ;;     (define-key evil-normal-state-map (kbd "SPC") 'er/expand-region)
285   ;;     (define-key evil-visual-state-map (kbd "SPC") 'er/expand-region)
286   ;;     (define-key evil-visual-state-map (kbd "S-SPC") 'er/contract-region)
287   ;;     (define-key evil-normal-state-map (kbd "S-SPC") 'er/contract-region)))
288 #+END_SRC
289
290 ** Org Mode (worf mode) and Lispy mode
291 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
292   (with-eval-after-load "evil"
293     (with-eval-after-load "lispy"
294       (evil-define-key 'normal lispy-mode-map (kbd "[") (lambda ()
295                                                           (interactive)
296                                                           (call-interactively #'lispy-backward)
297                                                           (evil-emacs-state)))
298       (evil-define-key 'normal lispy-mode-map (kbd "]") (lambda ()
299                                                           (interactive)
300                                                           (call-interactively #'lispy-forward)
301                                                           (evil-emacs-state))))
302     (with-eval-after-load "worf"
303       (evil-define-key 'normal worf-mode-map (kbd "[") (lambda ()
304                                                          (interactive)
305                                                          (call-interactively #'worf-backward)
306                                                          (evil-emacs-state)))
307       (evil-define-key 'normal worf-mode-map (kbd "]") (lambda ()
308                                                          (interactive)
309                                                          (call-interactively #'worf-forward)
310                                                          (evil-emacs-state)))))
311 #+END_SRC
312
313 ** Avy & Evil
314 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
315   (setq avy-keys '(?a ?s ?d ?g
316                       ?h ?k ?l
317                       ?q ?w ?e ?r ?t
318                       ?y ?u ?i ?o ?p
319                       ?z ?x ?c ?v ?b
320                       ?n ?m ?f ?j 59))
321   ;; (setq avy-background t)
322   (setq avy-all-windows nil)
323   (with-eval-after-load "evil"
324     (dolist (map (list evil-normal-state-map
325                        evil-visual-state-map
326                        evil-motion-state-map))
327       (define-key map (kbd "gw") 'avy-goto-word-0-below)
328       (define-key map (kbd "gb") 'avy-goto-word-0-above)
329       (define-key map (kbd "ge") 'avy-goto-word-0)
330       (define-key map (kbd "gc") 'avy-goto-char)))
331 #+END_SRC
332
333 ** ggtags
334 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
335
336 #+END_SRC
337 * Others
338 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
339   (dolist (mode '(c-mode-hook lua-mode-hook))
340     (add-hook mode (lambda () (setq indent-tabs-mode nil))))
341 #+END_SRC
342 * Provide 
343 #+BEGIN_SRC emacs-lisp :tangle yes :results silent
344   (provide 'init-evil-mode)
345 #+END_SRC