5

I regularly use Vim to write Ruby code, which allows ! as part of method identifiers and also uses it as logical negation. Currently, I configure iskeyword to include ! (using autocmd Filetype ruby set iskeyword+=\!) so that method name "words" include the !. For example, in

def foo!
  puts "foo was called"
end

foo!

if my cursor is on any part of foo! on the first line, hitting * will jump to the next occurrence (i.e. the call site). This works well, however, Ruby also uses ! for negation, e.g.

def some_condition
  true
end

!some_condition ? 'it was false' : 'it was true'

and if I hit * on the callsite (!some_condition) then Vim searches for !some_condition since ! is included in iskeyword and thus doesn't find the method definition.

Ideally, I'd like to able to tell Vim "treat ! as part of a keyword, only if it appears at the end of a word" so that I can search for both of my examples: method names that end in !, and methods that are negated with a leading !.

From searching the docs and Google, I don't think there is a way to this, but I'd appreciate any ideas!

If it matters, I'm using

> vim --version
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Nov 24 2016 16:42:57)
Included patches: 1-52
Extra patches: 8.0.0056

1 Answer 1

3

No, that is not possible. Vim treats all those 'is...' options as collections of characters (like [a-zA-z]), and cannot do more precise regular expression-like assertions.

In fact, the 'iskeyword' set has its own character class (:help /\k), so it is limited to be a simple set of characters. If this were changed, that correspondence of "a keyword" and a \k\+ match would be lost, and plugins would be broken.

Alternative approaches

Fiddling with 'iskeyword' is convenient, as it affects many built-in motions and text objects. But as we've now seen, it has these inherent limitations that cannot be overcome. However, Vim can be extended with custom motions and text objects. For your example, you can define a text object pair am / im (a method / inner method, matching \k\+!\?, the former also surrounding whitespace). (My CountJump plugin can help with defining custom motions and text object, also the textobj-user plugin.)

Many people have extended * to also work on the visual selection (e.g. through my SearchHighlighting plugin, or one of its many alternatives). You can then combine the text object with visual mode to search for the next method occurrence: vim*. Or you define a custom search <Leader>/{motion} and can then skip visual mode: <Leader>/im

Yes, this is not as convenient as defining 'iskeyword' and hitting *. But it is far more extensible: you can define additional text objects, e.g. for method name + its arguments, class names, ...

1
  • 3
    slight amendment: If one needs this for syntax highlighting, one should use :syn iskeyword instead of changing the 'iskeyword' option directly in syntax scripts. Oct 24, 2019 at 7:45

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.