Complete space-separated words in Vim - 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.

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'

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)

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.

Related

Vim command to introspectively list available commands

It would help me a lot to be able to view a list of Vim commands, and related metadata (eg. a description of each command, if it has aliases, etc.).
I understand that, through Vim plugins, the list of commands can be extended, and also depending on what options Vim was compiled with, can change the list of available commands.
I've done extensive searches online, for things like "vim command to list commands," but have come up empty-handed. The only command lists I can find are static documentation, that don't take into account the version of Vim you're running (including Neovim), what plugins you have installed / enabled, and what options Vim was compiled with.
Question: Is there a Vim command that introspectively lists all of the available commands in Vim?
In searchInRuntime I've the following function that list all commands starting with a leading text (that could be empty). This is an old trick to get what vim would expand through command line completion -- :h c_CTRL-A.
" s:MatchingCommands(ArgLead) {{{3
" return the list of custom commands starting by {FirstLetters}
function! s:MatchingCommands(ArgLead)
silent! exe "norm! :".a:ArgLead."\<c-a>\"\<home>let\ cmds=\"\<cr>"
let cmds = substitute(cmds, '\s\+', '\n', 'g')
" for your purpose, split is probably more fit
return cmds
endfunction
Note that it can't know what the commands are meant for. At best, you can fetch the definition of user commands thanks execute('verbose command '.cmdname) (execute() is a very recent function).
Note by the way that unlike execute('command'), this solution also list standard commands, not just user defined commands.
Regarding other actions available in vim (in case you weren't just looking for vim commands), while we can list user defined mappings (even may be even know that they do when they rely on well named plug-mappings), there is no way to list any other actions like dd, J...
Learn how to look up commands and navigate the built-in :help (there's automatic completion, listing of all candidates with Ctrl + A, and so on); it is comprehensive and also offers many tips. Most (good) plugins also provide their own help pages, so I think that answers your question best.
Don't try to implement some sort of introspection (as one commenter remarked to "shoot yourself in the foot"); rather, use the existing facilities of Vim. You can even write your own documentation pages (under ~/.vim/doc/*.txt); that's what I do: Collect tips, and short clips from other help locations. And it offers a place to document some older plugins that don't have their own help page.

How to autocomplete file paths in Vim, just like in zsh?

In Zsh, I can use filename completion with slashes to target a file deep in my source tree. For instance if I type:
vim s/w/t/u/f >TAB<
zsh replaces the pattern with:
vim src/wp-contents/themes/us/functions.php
What I'd like is to be able to target files the same way at the Vim command line, so that typing
:vi s/w/t/u/f >TAB<
will autocomplete to:
:vi src/wp-contents/themes/us/functions.php
I'm trying to parse the Vim docs for wildmode, but I don't see what settings would give me this. It's doing autocompletion for individual filenames, but not file paths. Does Vim support this natively? Or how can I customize the autocomplete algorithm for files?
Thanks for any advice!
-mykle-
I couldn't find a plugin to do this, so I wrote one. It's called vim-zsh-path-completion. It does what you're looking for, although via <C-s> rather than <Tab>. You can use it with <Tab> for even more control over what matches, though.
It's got bugs, but for basic paths without spaces/special characters, it should work. I think it's useful enough in its current state to be helpful. I hope to iron out the bugs and clean up the code, but I figured I'd start soliciting feedback now.
Thanks for the idea!
Original (wrong) answer, but with some useful information about Vim's wildmode.
Put the following in your .vimrc:
set wildmenu
set wildmode=list:longest
That will complete to the longest unique match on <Tab>, including appending a / and descending into directories where appropriate. If there are multiple matches, it will show a list of matches for what you've entered so far. Then you can type more characters and <Tab> again to complete.
I prefer the following setting, which completes to the first unique match on <Tab>, and then pops up a menu if you hit <Tab> again, which you can navigate with the arrow keys and hit enter to select from:
set wildmode=list:longest,list:full
Check out :help wildmenu and :help wildmode. You might also want to set wildignore to a list of patterns to ignore when completing. I have mine as:
set wildignore=.git,*.swp,*/tmp/*
Vim doesn't have such a feature by default. The closest buil-in feature is the wildmenu/wildmode combo but it's still very different.
A quick look at the script section of vim.org didn't return anything but I didn't look too far: you should dig further. Maybe it's there, somewhere.
Did you try Command-T, LustyExplorer, FuzzyFinder, CtrlP or one of the many similar plugins?
I use CtrlP and fuzzy matching can be done on filepath or filename. When done on filepath, I can use the keysequence below to open src/wp-contents/themes/us/functions.php (assuming functions.php is the only file under us that starts with a f):
,f " my custom mapping for the :CtrlP command
swtuf<CR>
edit
In thinking about a possible solution I'm afraid I was a little myopic. I was focused on your exact requirements but Vim has cool tricks when it comes to opening files!
The :e[dit] command accepts two types of wildcards: * is like the * you would use in your shell and ** means "any subdirectory".
So it's entirely possible to do:
:e s*/w*/t*/u*/f*<Tab>
or something like:
:e **/us/f<Tab>
or even:
:e **/fun<Tab>
Combined with the wildmode settings in Jim's answer, I think you have got a pretty powerful file navigation tool, here.

Can Vim's keyword completion be limited to only same filetype?

I find Vim's keyword completion very useful when I only have files of the same filetype open. But as soon as I start editing more than one filetype, it becomes much less useful. If I'm editing a Python project and then open my vimrc in another tab, keyword completion from inside a Python file will now include keywords from my vimrc. Without disabling the options for complete to look in other buffers, is it possible to have keyword completion work only with buffers of the same filetype?
Good idea. I'm a huge fan of the Vim insert-mode completion, and have written a library that makes it easy to implement custom completions: CompleteHelper.
With a little enhancement to that library (which I've just implemented in version 1.30), it allows to limit the completion candidates to certain buffers. With this, I've implemented your suggestion as the SameFiletypeComplete plugin. Try it out; I hope it's useful to you.
You are using <C-n>/<C-p>, right?
The value of set complete determines the completion sources. The default value includes the content of other buffers and windows in the completion list.
See :help 'complete' for a list of options. This will probably solve your problem:
:set complete=.,t,i
Alternatively, you could use other completion shortcuts like <C-x><C-n>, <C-x><C-p> or <C-x><C-o>, depending on what you want to complete. See :help ins-completion.

handling special characters when executing named buffers in vim

I've used vi for decades, and am now practicing using vim, expecting
eventually to switch to it entirely.
I have a number of questions, but I'll start with the one that
troubles me most. Something I have long done in vi is to type
a bottom-line command into the file I am editing, yank it to a named buffer
(e.g., using the keystrokes "ayy) and execute that buffer (using
:#a^M). This allows me to edit complicated commands till they
work right, and to keep commands that I will use many times as I
work in a file. (I have
in my .exrc file a mapping that reduces this yank-and-execute to a
single keystroke; but that isn't relevant to my question.)
I find that in vim, I need a lot more ^Vs than in vi. This
means, on the one hand, that when I have some command-line in a file
that I expect to use this way, I now need to keep it in two
versions, one for vi and one for vim. Also, the requirement of the
extra ^Vs seems inelegant: evidently various special characters
that are interpreted once when the named buffer is executed in vi
are interpreted twice when its is executed in vim -- but why?
As an example, a command of the form
map =f :w^V|e foo^M
(mapping the keystroke-sequence =f to write the current file
and go to the file foo) works this way in vi, but has to have the form
map =f :w^V^V|e foo^V^M
in vim. (Here in both commands, ^V is gotten by typing ^V^V,
and ^M is gotten by typing ^V^M; so typing the first version
involves typing three ^Vs, and the second, seven.) To be
exact: the first version does work in vim if one actually
types it into the bottom line (with the indicated extra ^Vs);
but the latter is required in an executed named buffer.
Any explanation? Anything I can set to fix this? ("compatible"
doesn't seem to do it.) Any hope that it will be fixed in a future
release? (The system I am on uses version 7.0.)
(I should confess that I'm not a programmer; just a user who has
become proficient in vi.)
Personally, I'd stop using ^V completely. In Vim (I've no idea about Vi), there are various key notations that get round the problems you're having. For your specific example, I'd recommend:
map =f :w<bar>e foo<CR>
where <bar> means 'insert the vertical bar here' and <CR> means 'insert a carriage return here'. See:
:help key-notation
for more information. I find the <CR> much easier to understand than ^V^M.
That's an interesting way of using :#, which I hadn't thought of before. I generally just use the command line history when I need to edit complicated commands, and I tend to save common or complicated commands as mappings or commands in my .vimrc (of course, I have a mapping that will pop open my .vimrc in a new tab). But there are certainly benefits to using vim's normal mode rather than command line mode for editing a complicated command.
As I understand it, you not only want to avoid so many <C-V> characters, you would also like to be able to use the same commands in vim and vi. Unfortunately, that would preclude you from using the (preferred in vim) key-notation. I think that you should be able to use the cmdline mode's Ctrl-R Ctrl-R register to help you out (:help c_<C-R>_<C-R>). E.g.
map <Leader>e mm^"ay$`m:<C-R><C-R>a<CR>
mm - mark cursor location so we can return later
^"ay$ - yank current line into register a (ignoring whitespace at beginning and newline at end)
``m` - return cursor to start position
: - enter command line mode
<C-R><C-R>a - place the literal contents of register a onto the command line, which seems to be where your problem with vim versus vi was coming to into play. I think that <C-R>a would give you the same behaviour you are seeing now with :#a.
- execute the whole thing
Using that mapping, I then typed your example of map =f :w^V|e foo^M into a file, placed my cursor on that line, ran my <Leader>e mapping, verified that your =f mapping had loaded correctly, and then ran it. Obviously you'll want to customize it to fit your needs, but I think that playing around with <C-R><C-R> will basically get you what you want.
All of that said, if you can, I'd strongly recommend taking the plunge and forgetting about compatibility with vi. Then you can use the much simpler key-notation and a host of other vim features. :-)

How to create short snippets in Vim?

I have recently started using Vim as my text editor and am currently working on my own customizations.
I suppose keyboard mappings can do pretty much anything, but for the time being I'm using them as a sort of snippets facility almost exclusively.
So, for example, if I type def{TAB} (:imap def{TAB} def ():<ESC>3ha), it expands to:
def |(): # '|' represents the caret
This works as expected, but I find it annoying when Vim waits for a full command while I'm typing a word containing "def" and am not interested in expanding it.
Is there a way to avoid this or use this function more effectively to this end?
Is any other Vim feature better suited for this?
After taking a quick look at SnippetsEmu, it looks like it's the best option and much easier to customize than I first thought.
To continue with the previous example:
:Snippet def <{}>():
Once defined, you can expand your snippet by typing def{TAB}.
Snipmate - like texmate :)
http://www.vim.org/scripts/script.php?script_id=2540
video:
http://vimeo.com/3535418
snippet def
""" ${1:docstring} """
def ${2:name}:
return ${3:value}
As another suggestion (although slightly different) using vim's built in functionality:
:iabbrev def def(): #<LEFT><LEFT><LEFT><LEFT><LEFT>
Now whenever you type def followed by a space or other non-word character, it will expand to the same as what you've given as the output of SnippetsEmu (the space comes from the space you entered to trigger the completion).
This approach doesn't suffer the "lag" issue you encountered using :inoremap, and is built-into vim. For more information on this feature, look at :help abbrev.
You may be concerned that being triggered by space not tab it will trigger unnecessarily, but in general vim is pretty smart about when to trigger it. The issue can be additionally mitigated by enabling the abbreviation only for certain file-types (eg, python):
au filetype python :iabbrev ... etc
Snip[ets] (Manager|Emu|Mate|.vim) is of course also a perfect solution, but it's nice to be aware of the alternatives (especially when they are built in).
If SnippetsEmu is too heavy or ambitious for what you need (it was for me), I wrote a plugin that manages snippets based on filetype. It even has tab completion when picking the snippet! :)
Get it here: snippets.vim
I just installed UltiSnips. There’s a good article that explains why you might choose UltiSnips: Why UltiSnips?
I haven’t used any of the other snippet plugins; I decided to take the plunge with one that seemed full-featured and would be able to accommodate me as I gain more Vim skills and want to do more sophisticated things.
SnippetsEmu is a useful snippets plugin.
As noted by MDCore, SnippetsEmu is a popular Vim script that does just that and more. If you need only expanding (without moving back the caret), you can use the standard :ab[breviate] command.
:ab[breviate] [<expr>] {lhs} {rhs}
add abbreviation for {lhs} to {rhs}. If {lhs} already
existed it is replaced with the new {rhs}. {rhs} may
contain spaces.
See |:map-<expr>| for the optional <expr> argument.

Resources