schoettl
schoettl

Reputation: 360

Complete space-separated words in Vim

I often like to complete more just a Vim keyword. For example, I want to complete an arbitrary pathname or something like self.logger.debug("...") which I already have somewhere in my text file.

C-n and C-p use the 'iskeyword' option and thus only complete Vim keywords.

What is the best way to implement a space-separated word completion?

inoremap <C-m> ???

My only idea is to change 'iskeyword', use normal word completion, and reset 'iskeyword' it after that.

Upvotes: 2

Views: 430

Answers (3)

Ingo Karkat
Ingo Karkat

Reputation: 172590

I have written a plugin that is powered by my CompleteHelper plugin that does just that:

The WORDComplete plugin finds matches for WORDs that start with the non-blank characters in front of the cursor and end at the next whitespace. By default, it is triggered in insert mode with <C-x><C-w>. Like the built-in completions, the source buffers it considers can be configured.

Upvotes: 1

Peter Rincker
Peter Rincker

Reputation: 45117

Both @Ingo Karkat and @Luc Hermitte provide excellent solutions. However if you want to do this natively then Vim provides some solutions which might help you. Typically completion uses plain <c-n>/<c-p> however there is an completion submode accessed via <c-x>.

Filename completion

Use <c-x><c-f> to start completing a filename. You can use <c-n>/<c-p> just like you normally would after you have started completion to move between options. If the completion ends in a directory (e.g. /usr/bin/) then just execute <c-x><c-f> to start completion into that directory.

Whole line completion

If you are commonly using the same line, but it isn't worth making a snippet or an abbreviation, then type the start of the line you wish then <c-x><c-l> to start line completion. Then just use <c-n>/<c-p> as you normally would.

Multi-word completion

You can use <c-x><c-n>/<c-x><c-p> to complete another word that follows the current word. This one is sort of tough to explain without just trying it.

Let's say you have the following text:

self.logger.debug("foo")

Let's say you would like another self.logger.debug somewhere else.

  • So type: sel then use <c-p> to as you normally would complete to self
  • Then use <c-x><c-p> to complete to self.logger (may need to do some <c-p>/<c-n> to get to .logger).
  • Once self.logger is completed then use <c-x><c-p> again for the .debugger part.

Note: this does use iskeyword so it may not complete exactly as you want, but should be pretty close.

For more help

:h ins-completion
:h compl-whole-line
:h compl-current
:h compl-filename
:h 'complete'

Upvotes: 3

Luc Hermitte
Luc Hermitte

Reputation: 32946

IMO, snippets are the best way to proceed in your case -- as you certainly don't want to change 'iskeyword' option (it'd trigger too many undesired side-effects, and as you said you'd need to restore it afterward, which is not trivial if possible at all). You could use abbreviations or mappings, but then you'd loose the "completion" feeling/feature you'd get with snippet plugins.

There exist plenty different snippet plugins. I'm quite sure there are plenty answers here on SO, or on vi.SE which describe the existing plugins.

For pathnames, you have i_CTRL-X_CTRL-f, but indeed it stops at each directory. In that case you could may be override i_CTRL-X_CTRL-f to alter &isk (and key sequences that valid/abort completion), trigger the completion, and then restore &isk and the mappings when you validate/abort the completion. This restoration at the end of completion is what some snippet plugins do. That's what I do in the core functions used in mu-template to take care of the completion. (Explanations of how this works on vi.SE)

Upvotes: 1

Related Questions