Evgeniy
Evgeniy

Reputation: 806

How to set the regex to "w", "e" and "b" keys in Vim?

Is there a way to define what vim should recognize as a word? I want to assign \w+ regex to all word key motions such as "w", "e", "b"... I can do it for normal mode like this:

nnoremap <silent> w :call search('\w\+')<CR>

but it doesn't work for visual mode and operator-pending modes. It would be great if there is a setting to do this.

Upvotes: 0

Views: 242

Answers (2)

anon
anon

Reputation:

From what I understand from your question, and the discussion on Kaz' answer, I think what you're looking for is Kana's smartword plugin: http://www.vim.org/scripts/script.php?script_id=2470.

You're going to have to check the documentation with :help smartword, but the short version is, if you install the plugin and map the built-in word mappings to the plugin ones...

map w  <Plug>(smartword-w)
map b  <Plug>(smartword-b)
map e  <Plug>(smartword-e)
map ge  <Plug>(smartword-ge)

... then the built-ins will skip any non-word characters along the way. I've been using this for many, many years, and I'm quite happy with the way it behaves.

Upvotes: 1

Kaz
Kaz

Reputation: 58588

For the lower-case motions like w and e, the definition of a "word" is controlled by the :iskeyword option; see the :help iskeyword on that. Basically it consists of a list of characters given as individual characters or ranges, separated by commas. I think that various syntax files tweak this for different languages, so that these commands move by identifiers. It doesn't look like you can specify a regular expression for this.

The upper-case motions like W and E don't look like they can be reprogrammed. Their definition of a "WORD" is nonblank characters separated by whitespace, plus that each empty line counts as a "WORD".

However, unfortunately, it looks like there is a behavior in effect whereby the iskeyword characters simply separate the input into sequences of iskeyword characters, non-iskeyword characters and whitespace. When the w and related commands are used, they skip whitespace, but visit both the iskeyword tokens and the non-iskeyword tokens.

Remapping using :map to just a / or ? keystroke sequence works in both visual and command mode:

:map w /\<\w/^M
:map b ?\</\w^M
:map e /\w\>^M

It works in both because the / and ? searches work in both modes. Of course, it's an ugly solution because it clobbers the current search pattern and if you have :set hls (highlightsearch) on, the tips/tails of the words highlight.

The above searches are not very satisfactory because of the way the anchoring operators are behaving. For instance, I can't get them to "land" on the a in something like {abc or (abc.

The following mappings work a better. Each triggers several searches. The /. and ?. searches are used as a trick to go to the next or previous character, such that if we are on the last character of a line, we go to the first one on the next line and vice versa.

:map b ?\w^M?\W^M/.^M
:map w /\W^M/\w^M
:map e /\w^M/\W^M?.^M

There are still some quirks. For instance, a list of words like:

abc
def
ghi

contains no match for the non-word class \W. The matching has to include line endings. Moving forward, an improvement to the w one in this regard is to add a match for the line ending like this:

:map w /\(\W\\|$\)^M/\w^M

Note the double backslash before the pipe! The rightmost backslash escapes the pipe so the processing of the :map command doesn't treat it as a command delimiter. Then we are left with \| which is the regex operator for branching. In a similar vein, the other two mappings can be improved; I'm leaving that as an exercise.

Upvotes: 1

Related Questions