From: Simon Carter <bbbscarter at gmail.com>
Subject: Evil-mode and camelcase movement
Date: Sat, 2 Jun 2012 20:20:40 +0100
Post by Simon CarterI was wondering if there was a canonical method for allowing camelcase and underscore word movement in evil-mode.
If you are looking for Evil implementation of camelcasemotion.vim
(http://www.vim.org/scripts/script.php?script_id=1905), then you need
to redefine evil-{forward,backward}-word-{begin,end} and
evil-{a,inner}-word with somehow dealing with word boundaries of
CamelCase/snake_case words.
I think using search-forward-regexp is not a good idea for two reasons:
a. There are many other uppercase letters other than [A-Z] and it's
too hard to write them all in a regular expression. You can see the
list of uppercase letters:
http://www.fileformat.info/info/unicode/category/Lu/list.htm
b. I had a hard experience dealing with word boundaries separated by
non-whitespace characters, when I was making a Evil patch to
support Japanese words (a CJK patch 7adc3b1).
For these reasons, I recommend a way using Emacs' native support of
character categories and word boundaries just like in the CJK patch.
First, we need to define new character categories for
uppercase/lowercase letters and underscore.
(define-category ?U "Uppercase")
(define-category ?L "Lowercase")
(define-category ?_ "Underscore")
(modify-category-entry (cons ?A ?Z) ?U)
(modify-category-entry (cons ?a ?z) ?L)
(modify-category-entry ?_ ?_)
(We have (cons ?A ?Z)/(cons ?a ?z) here but I will fix this later to
cover all uppercase/lowercase letters.)
Then, define word boundaries by indicating which categories of
successive characters are separating CamelCase/snake_case words.
(setq evil-little-word-separating-categories
'((?L . ?U) (?_ . ?L) (?_ . ?U)))
(setq evil-little-word-combining-categories
'())
Finally, redefine movement commands by using these definitions. Since
Evil already have mechanism to deal with Emacs' word boundaries, all
we have to do is to activate the above definitions before calling the
original movement commands. This can be done by the following macro.
(defmacro evil-with-little-word (&rest body)
(declare (indent defun)
(debug t))
`(let ((evil-cjk-emacs-word-boundary t) ; turn off CJK word boundary
(word-separating-categories evil-little-word-separating-categories)
(word-combining-categories evil-little-word-combining-categories))
, at body))
With this macro, we are able to have redefinitions as follows:
(evil-define-motion evil-forward-little-word-begin (count)
"Move the cursor to the beginning of the COUNT-th next little word."
:type exclusive
(evil-with-little-word (evil-forward-word-begin count)))
(evil-define-motion evil-backward-little-word-begin (count)
"Move the cursor to the beginning of the COUNT-th previous little word."
:type exclusive
(evil-with-little-word (evil-backward-word-begin count)))
...
I know this is a way-too-long solution, so I put them together with
covering all uppercase/lowercase letters into an Evil plugin:
https://github.com/tarao/evil-plugins/blob/master/evil-little-word.el
I hope this helps you.
--
Lintaro INA
mail: ina at kuis.kyoto-u.ac.jp