I use Emacs + evil mode.

When I position the cursor on e (in normal state) in a chunk of text such as abc_def_ghi, ciw (change inner word) changes only the def part of the string, while Vim would change the entire abc_def_ghi.

How can I force evil to treat the underscore as Vim does (ie, as part of the word)?

7 Answers 7


The simplest workaround: use ciW to select a whitespace-delimited word.

The bigger issue has to do with the value of the _ character in the syntax table. The issue is that _ is, by default, a symbol constituent in the syntax table, and you want to treat it as a word constituent.

If you're using emacs 24.4, you could try enabling superword-mode. I haven't tried it myself, so your mileage may vary.

An alternative is simply to modify the syntax table yourself and tell Emacs you want it to treat the _ character as a word constituent, like so:

(modify-syntax-entry ?_ "w")

After you do that, ciw works as you want it to, such that it will select all of abc_def_ghi rather than just def.

Doing it this way, however, may be overkill, especially if you only want the _ to count as part of the word for the text object. Instead, you can advise evil-inner-word as follows:

(defadvice evil-inner-word (around underscore-as-word activate)
  (let ((table (copy-syntax-table (syntax-table))))
    (modify-syntax-entry ?_ "w" table)
    (with-syntax-table table

Now, _ is still a symbol constituent for everything except for the inner-word text object, so ciw will do precisely what you want without touching the functionality of anything else.

You can read more about modifying syntax tables on the EmacsWiki node.

  • This works like a charm. To alter all the movements (w, aw, etc.), you can do the same with the following functions too: evil-forward-word-begin,evil-forward-word-end,evil-backward-word-begin,evil-backward-word-end,evil-a-word,evil-inner-word. Note: you need to change underscore-as-word into different, unique (arbitrary) values.
    – sitaktif
    Oct 18, 2016 at 6:33
  • (modify-syntax-entry ?_ "w") didn't work for me for some reason. Doing it interactively didn't work either. Any idea why or how I can debug this? I'm on Spacemacs in case that's relevant. Feb 17, 2018 at 13:23
  • 1
    This explains my problem. Apparently you have to refer to the target syntax table explictly. In my case I used (modify-syntax-entry ?_ "w" rust-mode-syntax-table), then it worked. Feb 17, 2018 at 13:28
  • What are the unintended effects of modifying the syntax entry?
    – luntain
    Feb 28, 2018 at 21:40
  • FTR: superword-mode doesn't affect movement in evil-mode. So it's not a constituent to modifying syntax tables.
    – Hi-Angel
    Dec 24, 2018 at 13:10

The following snippet will make Evil treat an Emacs symbol as a word.

(with-eval-after-load 'evil
    (defalias #'forward-evil-word #'forward-evil-symbol)
    ;; make evil-search-word look for symbol rather than word boundaries
    (setq-default evil-symbol-word-search t))

This has the advantage that it changes depending on the language:


is one symbol in lisp-mode but two symbols (separated by -) in c-mode.


The spacemacs FAQ offers the following language-specific solution:

;; For python
(add-hook 'python-mode-hook #'(lambda () (modify-syntax-entry ?_ "w")))
;; For ruby
(add-hook 'ruby-mode-hook #'(lambda () (modify-syntax-entry ?_ "w")))
;; For Javascript
(add-hook 'js2-mode-hook #'(lambda () (modify-syntax-entry ?_ "w")))

It also works in regular emacs. With evil on, it works with all word-related commands (w, e, *, #, etc)

More generally, this will do it for all major modes:

(add-hook 'after-change-major-mode-hook
          (lambda ()
            (modify-syntax-entry ?_ "w")))
  • 2
    Is using 'prog-mode-hook an option to cover every language? May 11, 2018 at 7:43

Emacs 24 introduced superword-mode, a minor mode that treats underscores as part of words. evil-mode respects this setting.

Here is the documentation:

(superword-mode &optional ARG)

Toggle superword movement and editing (Superword mode). With a prefix argument ARG, enable Superword mode if ARG is positive, and disable it otherwise. If called from Lisp, enable the mode if ARG is omitted or nil.

Superword mode is a buffer-local minor mode. Enabling it changes the definition of words such that symbols characters are treated as parts of words: e.g., in superword-mode, "this_is_a_symbol" counts as one word.

  • 1
    If you are using evil-mode, unfortunately, there is a bug when superword-mode is enable. It causes some erratic behavior when evil-forward-word-begin is called: github.com/emacs-evil/evil/issues/721
    – modulitos
    Aug 2, 2019 at 21:53

The evil FAQ says if you want the underscore to be recognised as a word character:

(modify-syntax-entry ?_ "w")

Alternatively, you can change the w shortcut to move by symbols instead of by words:

(defalias 'forward-evil-word 'forward-evil-symbol)

Doesn't quite answer the OP's question but thought I'd put this here for completeness. I also like evil's default behavior (esp. for python and lisp-dialects where I might only want to change part of a name) UNLESS I'm searching for a word under the cursor, i.e. with "*" or "#", in which case I'd like to search for the symbol under the cursor. You can easily modify evil to adhere to this by setting evil-symbol-word-search, i.e.:

(setq evil-symbol-word-search t)
  • This is the right way to do it. In addition to this setting, I also like to have W (capital rather than lowercase) refer to symbols rather than WORDs, for which you can use this: (defalias #'forward-evil-WORD #'forward-evil-symbol). With these two settings, your # and * search for symbols, w moves by word stopping at underscores, hyphens and spaces, while W moves by symbol, stopping at meaningful points for the code.
    – mindthief
    Dec 2, 2020 at 0:31

I actually quite like this behavior since I might want to just edit a part of the word and keep the other parts intact. If I want to go over the whole word I can always use E, W or B, the uppercase variants. This gives me more fine-grained control.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.