Ctrl+Space for omni and keyword completion in vim - vim

I Want to use Ctrl+Space for omni-completion (and keyword completion if there is no omni-completion) in vim. I've tried this which I found somewhere on the web:
inoremap <expr> <c-space> pumvisible() ? "\<C-n>" : "\<C-x>\<C-o>\<C-n>\<C-p>\<C-r>=pumvisible() ? \"\\<Down>\" : \"\\<CR>\""
however it's not working. Anyone who is using Ctrl+Space for this too who can show me the correct way (which works) to do it?
Worth noting is that it needs to work in the terminal version of vim NOT gvim.

Try this:
inoremap <expr> <C-Space> pumvisible() \|\| &omnifunc == '' ?
\ "\<lt>C-n>" :
\ "\<lt>C-x>\<lt>C-o><c-r>=pumvisible() ?" .
\ "\"\\<lt>c-n>\\<lt>c-p>\\<lt>c-n>\" :" .
\ "\" \\<lt>bs>\\<lt>C-n>\"\<CR>"
imap <C-#> <C-Space>

The above way is "kind of" working, but it's so unreadable that almost nobody could say what it actually does. The solution above is not good.
Short Answer - Use this:
function! Auto_complete_string()
if pumvisible()
return "\<C-n>"
else
return "\<C-x>\<C-o>\<C-r>=Auto_complete_opened()\<CR>"
end
endfunction
function! Auto_complete_opened()
if pumvisible()
return "\<Down>"
end
return ""
endfunction
inoremap <expr> <Nul> Auto_complete_string()
inoremap <expr> <C-Space> Auto_complete_string()
This answer also respects that there are two possible values (depending on terminal/gvim usage) for Ctrl+Space: <C-Space> and <Nul>.
I use a similar approach as the first one in jedi-vim, but more customizable.
Long Answer - What the above does:
The whole escaping of the above answer is so confusing, that I've split the above answer into a readable format:
function! Auto_complete_string()
if pumvisible()
return "\<C-n>"
else
return "\<C-x>\<C-o>\<C-r>=Auto_complete_opened()\<CR>"
end
endfunction
function! Auto_complete_opened()
if pumvisible()
return "\<c-n>\<c-p>\<c-n>"
else
return "\<bs>\<C-n>"
end
endfunction
inoremap <expr> <Nul> Auto_complete_string()
This clearly shows what it is doing. There's some weird stuff happening in Auto_complete_opened. It's not just doing completion, it's doing two additional things after trying to complete:
When trying to use the omnicompletion, it somehow does a <C-n><C-p><C-n>, which could IMHO just be abbreviated to <C-n>.
In case completion is unsuccessful, it uses a backspace and does a completion again, not <C-o><C-x> but <C-n>, which just doesn't make a lot of sense.
I'm not saying that this is not what some user might want, but it's probably not what most users want! My short answer takes that in credit and gives you a simple way to edit it. You can now just easily change things if you want to (for example <Down> to <C-n>, if you want the first entry to be written from the beginning on).

For iterm2 and vim these lines works for me, I got from jedi-vim
" Next three lines are to enable C-Space to autocomplete, omnicomplete
inoremap <C-Space> <C-x><C-o>
imap <buffer> <Nul> <C-Space>
smap <buffer> <Nul> <C-Space>

Related

How to remap CoC VIM autocomplete key?

I am trying to remap the autocomplete key from the "Enter" key to "TAB" because I keep autocompleting when I intend to go to the next line. The code below is the default option for coc, and I think this is where I should be able to remap the key.
" make <CR> auto-select the first completion item and notify coc.nvim to
" format on enter, <cr> could be remapped by other vim plugin
inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm()
\: "\<c-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
I thought that changing the <cr> in the beginning to <TAB> would work. However, although it does allow me to autocomplete using TAB, it creates weird auto indentations in some cases. For example:
//normal behavior
someFunction(){
//cursor here appropriately indented
}
//behavior after I made the changes mentioned above
someFunction(){
//cursor here}
I assume I just fundamentally don't understand something about coc or remapping keys in VIM.
Why can't I simply change that <cr> to <TAB>? How can I go about remapping the autocomplete key from "Enter" to "TAB"?
I don't understand vimscript too well, but I managed to get something working by trial and error.
Default Setting:
inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm()
\: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
Autocompleting on Tab:
"This expression seems to be responsible for coc formatting on enter
inoremap <silent><expr> <cr> "\C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
"I this just says autocomplete with the first option if pop up menu is open.
"If it is not open, just do a regular tab.
inoremap <silent><expr> <TAB> pumvisible() ? coc#select_confirm() : "\<C-g>u\<TAB>"
Replace the following line from the example coc config
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
\: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
with this:
inoremap <silent><expr> <TAB> coc#pum#visible() ? coc#pum#confirm() : "\<C-g>u\<TAB>"
This was based on #christofuy's answer but updated after this line changed.

vim autocmd hook after performing a search in the text?

I had a look at the list of events autocmd can handle, but I could not find one about search queries.
What I would like to do is to add some custom behavior after each text search is performed. I was able to remap the * command with this command:
map * *<F11>
In this case I mapped <F11> to a :call My_function() which will do something with the search pattern contained in #/.
But I still need to add my custom behavior to the / command, which is more complicated, as before it's completed it's getting the input search pattern.
Do you have any hint on how to proceed? Can I use autocmd? Or maybe is there a map trick?
An (bad) way to do it would be to remap the return key (and the esc key)
when / is pressed, something like that:
function! MyCustomBehaviour()
echo "Oui oui"
endf
function! UnmapSearch()
cunmap <cr>
cunmap <esc>
endf
function! MapSearch()
cnoremap <cr> <cr>:call UnmapSearch()<bar>call MyCustomBehaviour()<cr>
cnoremap <silent> <esc> <c-c>:call UnmapSearch()<cr>
endf
noremap / :<c-u>call MapSearch()<cr>/
It's a bad way because it's quite buggy : if you press Ctrl-C while editing the
search, it won't unmap <cr> and <esc>, then the next time you will enter : (command-line) mode,
the mappings will still be active... That's a problem that can't be solved (<c-c> can't be
remapped).
It's also a bad way because remapping directly the / key this way, IMO, is not a good practice.
But... This was the only solution I found some times ago to half-solve this problem.
Another workaround (the one I finally choose) can be written in one line :
cnoremap <c-cr> <cr>:call MyCustomBehaviour()<cr>

Is it wrong to have two statements inside an if on vimscript?

I recently decided to revamp my .vimrc.
As per instructions here, I added a small snippet in a file called ultisnips_tab_hack.vim, which is sourced in my .vimrc.
The last line of that snippet is this:
inoremap <expr> <CR> pumvisible() ? "\<C-R>=ExpandSnippetOrCarriageReturn()\<CR>" : "\<CR>"
Which from what I could tell was mapping Enter to an expression that would test if the pop-up menu was visible. If it was, the inserted text would be decided by the ExpandSnippetOrCarriageReturn() function that is defined in the snippet. Else a simple carriage return would be inserted.
This snippet is supposed to make YouCompleteMe and Ultisnips behave, and, as per this other comment, the last line should be modified to the following to make it also behave with vim-endwise.
let g:endwise_no_mappings = 1
inoremap <expr> <CR> pumvisible() ? "\<C-R>=ExpandSnippetOrCarriageReturn()\<CR>" : "\<CR>\<C-R>=EndwiseDiscretionary()\<CR>"
Which is the same except that if the pop-up menu is not visible, it will also call the vim-endwise function to decide if something else should be inserted. And also, the endwise mapping is disabled, so that it won't conflict with our custom mapping.
So, I was trying to make a solution that would work whether vim-endwise was loaded or not (because I wanted to load it only on ruby files). And what I tried was:
if exists("*EndwiseDiscretionary")
let g:endwise_no_mappings = 1
inoremap <expr> <CR> pumvisible() ? "\<C-R>=ExpandSnippetOrCarriageReturn()\<CR>" : "\<CR>\<C-R>=EndwiseDiscretionary()\<CR>"
else
inoremap <expr> <CR> pumvisible() ? "\<C-R>=ExpandSnippetOrCarriageReturn()\<CR>" : "\<CR>"
endif
To my surprise, that gave me the following weird error on vim when I pressed Enter (and vim-endwise was loaded).
E15: Invalid Expression: ExpandSnippetOrCarriageReturn()\
And also, the following text was inserted: pumvisible() ? " instead of a carriage return.
To my even-more-surprise, though, the following caused no errors at all, whether vim-endwise was loaded or not.
let g:endwise_no_mappings = 1
if exists("*EndwiseDiscretionary")
inoremap <expr> <CR> pumvisible() ? "\<C-R>=ExpandSnippetOrCarriageReturn()\<CR>" : "\<CR>\<C-R>=EndwiseDiscretionary()\<CR>"
else
inoremap <expr> <CR> pumvisible() ? "\<C-R>=ExpandSnippetOrCarriageReturn()\<CR>" : "\<CR>"
endif
I've been bitten by some weird vimscript stuff before, so I'm now wondering if two statements inside an if causes this kind of problems and I'm supposed to always extract them to a function.
Or maybe I need a special separator that I don't know of, or something like that. Maybe it's a problem with a variable assignment right above a mapping?
Can any vim guru please elucidate me?
TL;DR
Causes weird E15: Invalid Expression: ExpandSnippetOrCarriageReturn()\ error when I press Enter on insert mode:
if exists("*EndwiseDiscretionary")
let g:endwise_no_mappings = 1
inoremap <expr> <CR> pumvisible() ? "\<C-R>=ExpandSnippetOrCarriageReturn()\<CR>" : "\<CR>\<C-R>=EndwiseDiscretionary()\<CR>"
else
inoremap <expr> <CR> pumvisible() ? "\<C-R>=ExpandSnippetOrCarriageReturn()\<CR>" : "\<CR>"
endif
Work as intended:
let g:endwise_no_mappings = 1
if exists("*EndwiseDiscretionary")
inoremap <expr> <CR> pumvisible() ? "\<C-R>=ExpandSnippetOrCarriageReturn()\<CR>" : "\<CR>\<C-R>=EndwiseDiscretionary()\<CR>"
else
inoremap <expr> <CR> pumvisible() ? "\<C-R>=ExpandSnippetOrCarriageReturn()\<CR>" : "\<CR>"
endif

Vim script: run an execute when mapping?

So I'm not sure how to go about running some some code in my mappings, like:
nnoremap <Return> :execute "normal! if 1 echo('one') endif"<cr>
Also tried it without the 'normal' - tried different combinations with separating the commands via '\' and '|' but nothing worked - keep getting variable not defined errors.
Any idea how?
EDIT:
So here's what I'm actually doing:
" Quickly toggle between insert/normal modes
nnoremap <A-e> i
inoremap <silent><A-e> <esc>:call GoRightIfNotBOL()<cr>
" Returns 1 if the cursor is at the beginning of a line "
function! IsBOL()
return col('.') == 1
endfu
function! GoRightIfNotBOL()
if !IsBOL()
execute "normal l"
endif
endfu
So instead of calling GoRightIfNotBOL I thought I could inline its code cause really, I can't think of another location where I would be using this function, and it's pretty small.
you are looking for <expr> mapping
read :h <expr> there you'll find examples.
If your codes were a bit long, put them in a function, and call that function in your mapping. It is more readable if you later want to do some change on it.
An example with inoremap <expr>:
inoremap <expr> <YourKeys> "<esc>".(col('.')>1?'l':'')

how do I conditionally bind a key to do two different actions in vim?

I'd like to bind <C-n> to do one of two things in Vim depending on the state of the editor. If I have tabs open I'd like it to switch to the next tab, otherwise I'd like it to open a new tab. I've looked at the help and come up with this, but it's not working, and I'm a viml noob.
function TabBind()
if range(tabpagenr()) < 2
nno <C-n> :tabnew
else
nno <C-n> :tabn
endif
endfunction
Is this possible? and if so how?
The idea is that you map a function that decides what to do on the fly.
function TabBind()
if tabpagenr('$') < 2
tabnew
else
tabn
endif
endfunction
nno <C-n> :call TabBind()<cr>
You can also define such simple thing as one-liners. For instance I have the following mapping to go to the next diff (in diff mode), or to the next error message otherwise.
nnoremap <expr> <silent> <F3> (&diff ? "]c:call \<sid>NextDiff()\<cr>" : ":cn\<cr>")
In your case, your mapping will be:
nnoremap <expr> <silent> <c-n> (tabpagenr('$') < 2 ? ":tabnew\<cr>" : ":tabn\<cr>")

Resources