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)?


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.

| improve this answer | |
  • 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 '16 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. – Helder S Ribeiro Feb 17 '18 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. – Helder S Ribeiro Feb 17 '18 at 13:28
  • What are the unintended effects of modifying the syntax entry? – luntain Feb 28 '18 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 '18 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.

| improve this answer | |

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")))
| improve this answer | |
  • 2
    Is using 'prog-mode-hook an option to cover every language? – BallpointBen May 11 '18 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.

| improve this answer | |
  • 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 '19 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)
| improve this answer | |

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.

| improve this answer | |

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 "#". You can easily modify evil to adhere to this by setting evil-symbol-word-search, i.e.:

(setq evil-symbol-word-search t)
| improve this answer | |

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.