Reputation: 806
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
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
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