Make vim keyword completion menu show function parameters - vim

Problem
I want to make the vim keyword completion menu show the parameters of the functions it proposes to me.
I would like it to look something like this :
This is omni-completion using ctags, it is great but it is slow, so i can't use it with a large tags file.
Issues
Here's what my current keyword completion using ctags looks like (set complete=t) :
My research
I tried to look at vim's doc (ins-completion, 'complete', 'completeopt', 'completefunc', 'omnifunc', 'ft-c-omni') but the only way to achieve my goal seems to write my own 'completefunc' what i don't feel like to do.
However i found that i can get a popup menu showing the informations i want, but with my current configuration (set completeopt=menuone,noinsert,popup) it shows up only in omni completion which, again, is too slow.

I didn't manage to get vim keyword completion to behave as i want so i browsed the vim documentation (:h tag, popup, popup_atcursor) and i came to the conclusion that creating my own simple popup should do the trick.
Code
" get the parameters of a function and put it in a popup using ctags
func GetFuncParamsFromTag()
silent write
" jump to tag under cursor
silent execute "normal \<c-]>"
" if there is '(' on the same line, it may be a function
if search('(', "n") == winsaveview()["lnum"]
" yank the function's name and parameters
silent execute "normal v/)\<cr>y\<c-t>"
" remove any previously present popup
call popup_clear()
" make the popup spawn above/below the cursor
call popup_atcursor(getreg('0'), #{moved: [0, 80], highlight: 'WildMenu'})
endif
endfunc
nnoremap <silent> <leader>? :call GetFuncParamsFromTag()<cr>
Preview
It looks like this :
You just have to press <leader>? on a function's name in Normal mode and you get a nice little popup showing only the prototype of the function.
EDIT:
I found a workaround to get this to work when i use vim completion.
autocmd CompleteDone * execute "normal ^,?" | call feedkeys("\<esc>:autocmd! InsertLeave * ++once call popup_clear()\<cr>A")
This autocmd brings a popup whenever you complete a word, so if you type
myImcompleteFunctionTag<c-]><c-y>
it will complete your tag, then open the popup, and leave you in insert mode at the end of the line.
The rest of the autocmd closes the popup the next time you leave insert mode.

Related

How to know what events will trigger when doing specific operation in VIM?

I am studying VIM events, but I found some events may not working well like ##TabLeave won't be triggered when using gt/gT to switch between tabpages. What can I do to know what event has been triggered by VIM when I am doing a specific operation, like typing tabmove command to execute it? I am writing a plugin to make my VIM tabpage can source back to previously visited tabpage, but the problem is tabmove command won't trigger anything, anyone can help me on this?
function! catchSomeEventTriggerByTabmCmd()
let histCmd = histget('cmd', -1)
if match(histCmd, '^tabm') == 0
DoUpdateJumpQueue()
endif
endfunction
... I found some events may not working well like ##TabLeave won't be triggered when using 'gt/gT' to switch between tabpages.
gt/gT does trigger TabLeave. example:
:let g:foo = 1
:autocmd TabLeave * let g:foo = g:foo + 1 | echom "TabLeave Event " . g:foo
:tabnew
Now do a few gt/gT's. You should get messages
What can I do to know what event has been triggered by VIM when I am doing a specific operation, like typing 'tabmove' command to execute it? I am writing a plugin to make my VIM tabpage can source back to previously visited tabpage, but the problem is 'tabmove' command won't trigger anything, anyone can help me on this?
I am not sure you can use an event/autocmd like TabLeave to capture anything from :tabmove. It probably is also going to be tricky to use tab page numbers as well, since :tabmove modifies them.
Luckily, Vim always has to focus a window, so instead of trying to have a history of tab pages, maybe have a history have window id's. You may be able to use win_getid() and win_gotoid() to accomplish your history behavior.
For more help see:
:h win_getid()
:h win_gotoid()
:h windowid

NERDTree live-preview (like sublime sidebar)

Sublime's sidebar has a cool feature, where I can just press the arrow keys and get a quick glance of what each file looks like in the editor pane. It doesn't actually open the file -- just shows it in the editor pane.
I want to do the same thing with NERDTree in Vim (or Vinegar/netrw, doesn't really matter). I know NERDTree lets me use go to open the file under the cursor while keeping the tree in focus, but (a) that requires two keystrokes, and (b) it creates a new buffer for every file I "preview" like this, so... not much of a preview really.
Is there a way to make NERDTree or Vim emulate this Sublime feature?
Yes, there is. Vim has a feature called "preview window". You can open a file in the preview window with :pedit <filename>. If you want to plug this into NERDTree, you could create a file in the ~/.vim/nerdtree_plugin/ directory, for example "live_preview_mapping.vim", with the following contents:
if exists("g:loaded_nerdree_live_preview_mapping")
finish
endif
let g:loaded_nerdree_live_preview_mapping = 1
call NERDTreeAddKeyMap({
\ 'key': '<up>',
\ 'callback': 'NERDTreeLivePreview',
\ 'quickhelpText': 'preview',
\ })
function! NERDTreeLivePreview()
" Get the path of the item under the cursor if possible:
let current_file = g:NERDTreeFileNode.GetSelected()
if current_file == {}
return
else
exe 'pedit '.current_file.path.str()
endif
endfunction
The first part is simply a load guard, so the file is sourced only once, just boilerplate. The second part adds a keymap using the NERDTree API for the <up> key that calls the given callback function.
The callback function is the meat of the code, but it should be fairly easy to understand -- it takes the node under the cursor, if there is one, and executes a :pedit with the filename.
You can even do this more easily with a simple filetype-specific mapping, something like this:
autocmd FileType nerdtree nnoremap <buffer> <up> :call NERDTreeLivePreview()<cr>
But the former is the approach recommended by the plugin (see :help NERDTreeAPI). If nothing else, this adds a help entry to the ? key for it, and it keeps nerdtree extensions in one place.
For more info on what you can do with the preview window, try :help preview-window. For instance, you can close it with <c-w>z, but you can map that to whatever you'd like, that's not really related to the NERDTree anymore. If you're unhappy with where the window shows up, consider changing the "pedit" to "botright pedit" or "leftabove pedit" or whatever you want. Check the help for :leftabove and take a look at the related commands below.
NERDTree doesn't offer anything automatic out of the box. I like a preview window that hijacks the last active window and allows for opening the buffer there, or to split with the original buffer. This extension does that, and its source code is pretty short.
https://github.com/numEricL/nerdtree-live-preview
With netrw, to preview a file: with the cursor atop a file, press "p".

`vimdiff` not compatible with autocmd?

I was used to use vimdiff and loading the compared files.
Now, on vimdiff execution, it happens:
"a" [readonly] 5454L, 269796C
"b" [readonly] 241L, 10170C
Press ENTER or type command to continue
The only configuration change is the introduction of these two autocmd instructions:
autocmd BufNewFile * call s:Function()
autocmd BufReadPre * call s:Function()
Can this be a normal behavior? Can it be a mistake of mine? Can be something depending on Vim versioning? Can the desired configuration change be combined with a straightforward vimdiff load (no ENTER key needed to continue)?
The dreaded hit-enter prompt is usually triggered by additional :echo[msg] commands, here inside your s:Function(). Either remove them, or silence the output via :silent:
autocmd BufNewFile * silent call s:Function()
If you want to keep whatever messages are displayed in your function, you can set your 'cmdheight' option higher to allow displaying more messages before the "hit enter" prompt appears. This, and other suggestions here: http://vim.wikia.com/wiki/Avoiding_the_"Hit_ENTER_to_continue"_prompts

How do I turn on search highlighting from a vim script?

If I do either of the following two:
call search("searchString")
exec "/ searchString"
From a script, then vim does the search but does not highlight the results, even though hlsearch. Doing the same searches from outside a script highlights the results.
Just found out the answer myself:
call search(l:searchString)
call matchadd('Search', l:searchString)
The
feedkeys()
function is the key (pun intended):
call feedkeys("/pattern\<CR>")
or cleaner:
" highlights – or doesn’t – according to 'hlsearch' option
function SearcH(pattern)
let #/ = a:pattern
call feedkeys("/\<CR>")
endfunction
I know this is late. However when I searched for the answer to this problem this page came up. So I feel compelled to help fix it.
call search(l:searchString)
call matchadd('Search', l:searchString)
Did not work for me. (when run from inside a function) It did higlight the words I wanted to search for but n/N wouldn't cycle between them. Also when I performed a new search the "l:serachStirng" pattern still remained highlighted. This answer on this link worked much better
Vim search and highlighting control from a script
Which gave me:
let #/ = l:searchString
then run
normal n
outside the funciton (so the highlighting is done immediately without the user needing to press n)
To turn on, press ESC type :set hls
To turn off, press ESC type :set nohls
Found answer here:
http://vim.1045645.n5.nabble.com/highlighting-search-results-from-within-a-function-tt5709191.html#a5709193
```
One solution would be
function! XXXX()
execute '/this'
return #/
endfunction
and to use the following instead of ":call XXXX()".
:let #/ = XXXX()
```
I believe this works from inside a function
(to just enable highlighting and nothing more):
call feedkeys(":\<C-u>set hlsearch \<enter>")
You need to put this in your .vimrc file
" Switch syntax highlighting on, when the terminal has colors
" Also switch on highlighting the last used search pattern.
if &t_Co > 2 || has("gui_running")
syntax on
set hlsearch
endif
The .vimrc file is usually located in your home directory, or you can find it using "locate .vimrc"

Selecting resulting files from grep in vim

After I run a grep search in vim with :grep, I get a list of files. Is there a way to select one of those files and open it in a new tab at that particular line?
Just for completeness, as well as the :copen command, there's also :cw, which only opens the "quickfix" window if there are entries (so if your grep has no results, it won't appear).
I think the easiest way (without defining a mapping) of making the files open in a new tab would be to do:
:cw " Open the quickfix window
Ctrl-W T " Switch the window into a new tab
<ENTER> " Open the file/line
Alternatively, you could do:
:cw " Open the quick fix window
Ctrl-W <ENTER> " Open the file/line in a new window
Ctrl-W T " Move the new window to a new tab
If you want to do it by default, you could probably use the BufEnter and BufLeave autocmds to create and remove a mapping when entering and leaving the quickfix window; however, this is probably not trivial.
:help :cw
:help :copen
:help quickfix
For achieving what you want you have to open the quickfix/error window after calling grep:
:copen
I have a script that makes it for me every time i use grep.
I came upon this thread looking for an answer to a very similar question. The answer presented above, though correct, failed to describe a convenient way to open ALL the files in the QuickFix window at once ... into either buffers or tabs.
There doesn't seem to be a built in command to do it, but it's trivial as a VIM plugin ... somebody has done it here
http://pastebin.com/J9RwciFQ
It's 12 lines of code (one function) ... pasted here to save you a click during your analysis. Do follow the pastebin link if you are going to try to implement this though ... my plugin is installed in pathogen directory and I modified the plugin from the original slightly (details after code).
~/.v/b/v/p/quickfixopenall.vim
" Create command
command! QuickFixOpenAll :call StartQuickFixOpenAll()
function! StartQuickFixOpenAll()
if empty(getqflist())
return
endif
let s:prev_val = ""
for d in getqflist()
let s:curr_val = bufname(d.bufnr)
if (s:curr_val != s:prev_val)
exec "edit " . s:curr_val
endif
let s:prev_val = s:curr_val
endfor
endfunction
So once I have a grep result I'm satisfied with ... the plugin has a function :QuickFixOpenAll ... I had to modify the plugin as given (added the following line to the quickfixplugin.vim). And I renamed his given function StartQuickFixOpenAll ...
" Create command
command! QuickFixOpenAll :call StartQuickFixOpenAll()
Then you have all the files in the grep result open as buffers ... if you want to run any commeon operations such as find/replace you can prefix the regular command with the "bufdo" command which will perform your command in all ... in VIM type "help bufdo"
You can fairly trivially modify this plugin if you wan to use tabs ... it uses the commaned "edit" ... just replace that with "tabe" and :QuickFixOpenAll will open each result buffer in a new tab.
If you get a list of files you can browse them in a tree-like manner via
:cn
:colder
For more information
:help grep
and scroll to the bottom of the entry

Resources