I have content stored in a variable (out) which I want to replace with the current buffer. I'm currently doing it like this (simplified version):
let splitted = split(out, '\n')
if line('$') > len(splitted)
execute len(splitted) .',$delete'
endif
call setline(1, splitted)
(Detailed: https://github.com/fatih/vim-go/blob/master/autoload/go/fmt.vim#L130)
However setline() here causes slowness on some machines and https://github.com/fatih/vim-go/issues/459. I've profilde it myself but for me setline was not a problem. Anyway, I need a solution which is more faster. So I've come up with several other solutions.
First one is, which puts the output to a register, deletes all lines and then puts it back:
let #a = out
% delete _
put! a
$ delete _
Second solution would be using append() (which was used previously in vim-go https://github.com/fatih/vim-go/commit/99a1732e40e3f064300d544eebd4153dbc3c60c7):
let splitted = split(out, '\n')
%delete _
call append(0, splitted)
$delete _
They both work! However they both also causes a side effect which I'm still couldn't solve and is also written in the title. The problem is described as:
If a buffer is opened in another view (say next to next), and
we call one of the two solutions above, it breaks the cursor of
the other view and jumps to the bottom
Here is a GIF showing it better (whenever I call :w one of the procedures above is called): http://d.pr/i/1buDZ
Is there a way, to replace the content of a buffer, which is fast and doesn't break the layout? Or how can I prevent it with one of the procedures above?
Thanks.
Did you try winsaveview() and winrestview()?
:let old_view=winsaveview()
:% delete _
:put! =out
:$ delete _
:call winrestview(old_view)
However I don't know anything about pasting text in a quicker way
Try using the redraw command.
I have faced similar issues of strange delays a few times, where profiling doesn't shows anything suspicious. But the redraw command solved it in most cases and it doesn't disrupt the window layout (the last time I found this problem was in vim-addon-qf-layout plugin).
If the problem still happens you could try using the following approach, which is slight different from your first example; I've been using it for quite some time without any delays:
function! s:setCurrentLine(content)
silent put =a:content
" delete original line
silent '[-1delete _
endfunction
What about this? It saves the view for each window with the current buffer opened inside, then restores all the views after the modifications. It seems to work for me.
function! BufListSave()
let cur_buf = winbufnr(0)
let cur_tab = tabpagenr()
let buflist = []
for i in range(tabpagenr('$'))
let tab_array = []
let tab_buflist = tabpagebuflist(i+1)
for j in range(len(tab_buflist))
if tab_buflist[j] == cur_buf
exe "tabn ".(i+1)
let cur_win = winnr()
exe (j+1)."wincmd w"
call add(tab_array, {"win":j+1, "view":winsaveview()})
exe cur_win."wincmd w"
endif
endfor
call add(buflist, tab_array)
endfor
exe "tabn ".cur_tab
return buflist
endfunction
function! BufListRest(buflist)
let cur_tab = tabpagenr()
for i in range(len(a:buflist))
let tab_array = a:buflist[i]
if len(tab_array) == 0
continue
endif
exe "tabn ".(i+1)
let cur_win = winnr()
for wi in tab_array
exe "".wi['win']."wincmd w"
call winrestview(wi['view'])
endfor
exe cur_win."wincmd w"
endfor
exe "tabn ".cur_tab
endfunction
function! Do_It()
let buf_list = BufListSave()
%delete _
put! =out
$delete _
call BufListRest(buf_list)
endfunction
function! Do_It_Silently()
silent call Do_It()
endfunction
Related
I have the following plugin I wrote to test popup windows
"plugin/morning/morning.vim"
augroup morning_command_line_popup
autocmd!
au CmdlineLeave * call morning#close()
au CmdlineEnter * call morning#open()
au CmdlineChanged * call morning#update()
augroup END
"autoload/morning.vim"
function morning#open()
let opt = {}
let opt.border = []
let opt.minwidth = &columns / 3
let g:morning_window_handle = popup_create(":echo 'hi'", opt)
endfunction
function morning#close()
call popup_close(g:morning_window_handle)
endfunction
function morning#update()
call popup_show(g:morning_window_handle)
endfunction
The first time I enter the command line, the popup window appears. Every successive time that I enter the command line, it doesn't appear. I know the events are being fired and the functions are being called because if I put echom commands in the functions the messages show. Anyone know what could be wrong?
I figured out that if I redraw after showing the popup window, it seems to work consistently. I don't know if there's a reason why it won't redraw normally, or if doing this is extremely inefficient. This also has the side effect of overwriting wildmenu.
function morning#open()
let opt = {}
let opt.border = []
let opt.minwidth = &columns / 3
let g:morning_window_handle = popup_create(":echo 'hi'", opt)
redraw
endfunction
function morning#close()
call popup_close(g:morning_window_handle)
endfunction
function morning#update()
call popup_settext(g:morning_window_handle, string(getcmdline()))
call popup_show(g:morning_window_handle)
redraw
endfunction
I created unite source cmdmatch which lets you among other things fuzzy complete wildmenu items. I would like to find a better method to obtain the completion list (method I use is given here and is problematic because with large number of completion items screen will be filled up entirely [to see why just press :<c-a> if you didn't remap <c-a>])
The other solution would be to hide vim's cmd line completely while I am grabbing the list although I don't think that is possible in vim (or at least limit the amount of text it displays so it doesn't fill up screen). Any ideas ?
EDIT
First try has the same flickering problem although it looks like it works faster
fu! GetCompletion(input)
call feedkeys(":" . a:input . "FF\<esc>\<cr>")
endf
cno FF <C-A><C-\>eg:Save()<CR>
fu! g:Save()
let g:x = getcmdline()
endf
Result can be seen as:
:call GetCompletion('help a')
:echo x
SOLUTION
let g:cmdmatch = {}
fu! g:cmdmatch.set_c( base ) dict
let self.c = a:base
endfu
fu! GetCommandCompletion( base )
cno [MATCH] <c-a><c-\>eg:cmdmatch.set_c(getcmdline())<cr>
sil! exe 'norm :' . a:base . '[MATCH]'
cu [MATCH]
retu g:unite_cmdmatch.c
endf
Test: echo GetCommandCompletion("help '")
The trick is to execute the entire completion with :silent, so that the output won't actually happen (but completion is still magically done). The following function retrieves the completions already parsed into a List, by triggering the completion and then wrapping the output in :return split('...'). Of course, you can also :return '...' if you need a single string.
function! GetCommandCompletion( base )
silent execute "normal! :" a:base . "\<C-a>')\<C-b>return split('\<CR>"
endfunction
demo
:let cmds = GetCommandCompletion('no')
:echo cmds
['noautocmd', 'nohlsearch', 'noreabbrev', 'noremap', 'noremenu', 'normal']
I have bundles ultisnips and youcompleteme installed on my macvim.
The problem is that ultisnips doesn't work because tab is bound by ycm.
I tried putting let g:UltiSnipsExpandTrigger = "<s-tab>" so that I can trigger the snippet completion with shift-tab, but it doesn't work for some unknown reason. I could use caps as the trigger, but so far I've found no way to do that.
Do any of you use those two add-ons together?
What can I do to make shift-tab work?
Can you recommend another key to trigger snippets?
Another option is using the SuperTab plugin:
" if you use Vundle, load plugins:
Bundle 'ervandew/supertab'
Bundle 'Valloric/YouCompleteMe'
Bundle 'SirVer/ultisnips'
" make YCM compatible with UltiSnips (using supertab)
let g:ycm_key_list_select_completion = ['<C-n>', '<Down>']
let g:ycm_key_list_previous_completion = ['<C-p>', '<Up>']
let g:SuperTabDefaultCompletionType = '<C-n>'
" better key bindings for UltiSnipsExpandTrigger
let g:UltiSnipsExpandTrigger = "<tab>"
let g:UltiSnipsJumpForwardTrigger = "<tab>"
let g:UltiSnipsJumpBackwardTrigger = "<s-tab>"
Here YouCompleteMe is bound to a different combination Ctrln, but then that combination is bound to tab through SuperTab. UltiSnips and SuperTab play nice together, so you can then just bind UltiSnips to tab directly and everything will work out.
Try this suggestion on a page from the YouCompleteMe issue tracker. In your .vimrc:
let g:UltiSnipsExpandTrigger="<c-j>"
While this setting will make expanding a snippet share the default mapping for jumping forward within a snippet, it simulates TextMates' behavior as mentioned in the UltiSnips help tags.
Since I've mapped my Caps Lock key to Ctrl, this mapping works pretty smoothly.
copy the following code to your vimrc, and enjoy. This function will handle all issues between YCM and UltiSnips.
function! g:UltiSnips_Complete()
call UltiSnips#ExpandSnippet()
if g:ulti_expand_res == 0
if pumvisible()
return "\<C-n>"
else
call UltiSnips#JumpForwards()
if g:ulti_jump_forwards_res == 0
return "\<TAB>"
endif
endif
endif
return ""
endfunction
au BufEnter * exec "inoremap <silent> " . g:UltiSnipsExpandTrigger . " <C-R>=g:UltiSnips_Complete()<cr>"
let g:UltiSnipsJumpForwardTrigger="<tab>"
let g:UltiSnipsListSnippets="<c-e>"
" this mapping Enter key to <C-y> to chose the current highlight item
" and close the selection list, same as other IDEs.
" CONFLICT with some plugins like tpope/Endwise
inoremap <expr> <CR> pumvisible() ? "\<C-y>" : "\<C-g>u\<CR>"
i have this in my vimrc
"" YouCompleteMe
let g:ycm_key_list_previous_completion=['<Up>']
"" Ultisnips
let g:UltiSnipsExpandTrigger="<c-tab>"
let g:UltiSnipsListSnippets="<c-s-tab>"
thats what i did on my first try, but i misspelled UltiSnips with Ultisnips.. oh well, worked out in the end!
I personally chose to not use <tab> with YouCompleteMe but navigate it manually.
So I added this to my .vimrc:
let g:ycm_key_list_select_completion=[]
let g:ycm_key_list_previous_completion=[]
which simply disables the tab key for YCM. Instead you use the movement keys (arrows or CTRL-N/CTRL-P) and select the entry with CR. UltiSnips works default with tab.
Just putting together answers by Michaelslec, Joey Liu and along with solutions I found in this issue thread and this guy's vimrc, I now have this which solved pretty much all problems.
function! g:UltiSnips_Complete()
call UltiSnips#ExpandSnippet()
if g:ulti_expand_res == 0
if pumvisible()
return "\<C-n>"
else
call UltiSnips#JumpForwards()
if g:ulti_jump_forwards_res == 0
return "\<TAB>"
endif
endif
endif
return ""
endfunction
function! g:UltiSnips_Reverse()
call UltiSnips#JumpBackwards()
if g:ulti_jump_backwards_res == 0
return "\<C-P>"
endif
return ""
endfunction
if !exists("g:UltiSnipsJumpForwardTrigger")
let g:UltiSnipsJumpForwardTrigger = "<tab>"
endif
if !exists("g:UltiSnipsJumpBackwardTrigger")
let g:UltiSnipsJumpBackwardTrigger="<s-tab>"
endif
au InsertEnter * exec "inoremap <silent> " . g:UltiSnipsExpandTrigger . " <C-R>=g:UltiSnips_Complete()<cr>"
au InsertEnter * exec "inoremap <silent> " . g:UltiSnipsJumpBackwardTrigger . " <C-R>=g:UltiSnips_Reverse()<cr>"
Based on Siegfried's answer, I am using the following which seems more natural:
let g:ycm_key_list_select_completion = ['<C-j>']
let g:ycm_key_list_previous_completion = ['<C-k>']
let g:UltiSnipsExpandTrigger = "<C-l>"
let g:UltiSnipsJumpForwardTrigger = "<C-j>"
let g:UltiSnipsJumpBackwardTrigger = "<C-k>"
I also use the c-hjkl bindings somewhere else (switching from a pane to another), but that would only be in normal mode, so there's no problem.
Although I know this post is a little old, I have my own function that is a little more optimized than the one given above:
function! g:UltiSnips_Complete()
call UltiSnips#ExpandSnippetOrJump()
if g:ulti_expand_or_jump_res == 0
if pumvisible()
return "\<C-N>"
else
return "\<TAB>"
endif
endif
return ""
endfunction
Of course, if you just keep the settings that Joey Liu provided and then just use this function everything will work just perfectly!
EDIT: Also, I use another function to increase back-stepping functionality between YouCompleteMe and UltiSnips. I'll show you what I mean:
function! g:UltiSnips_Reverse()
call UltiSnips#JumpBackwards()
if g:ulti_jump_backwards_res == 0
return "\<C-P>"
endif
return ""
endfunction
Then just put this in your .vimrc:
au BufEnter * exec "inoremap <silent> " . g:UltiSnipsJumpBackwardTrigger . " <C-R>=g:UltiSnips_Reverse()<cr>"
As well as let g:UltiSnipsJumpBackwardTrigger="<s-tab>" and your set!
I use both of them together. By default YouCompleteMe binds <Tab> and <Down> to select the next completion item and also <S-Tab> and <Up> to select the previous completion item. You can change the YouCompleteMe bindings with the g:ycm_key_list_select_completion and g:ycm_key_list_previous_completion options. Note that the names of these options were recently changed when the option was changed from a single string to a list of strings.
While Many answer works fine in this post, I just want to say that the problem is caused by key binding collision between YCM and UltiSnip, while YCM support UltiSnip snippets by default, it takes the default UltiSnip expand trigger <tab> as its completion select key, so UltiSnip snippets will not be expaned by <tab>. Give them different key binding will solve the problem, I personally use <c-n and <c-p> for YCM and use the default <tab> for UltiSnip. You can get more details with help youcompleteme doc in vim.
I installed the UltiSnips plugin after the YouCompleteMe plugin so I thought they were conflicting, but in reality I had something more interfering:
set paste
Make sure to remove that from .vimrc if it's present.
I use ; to expand UltiSnips, it's so nifty for me
let g:UltiSnipsExpandTrigger = ";"
I use kj. This is what is in my .vimrc:
let g:UltisnipsExpandTrigger="kj".
It rarely happens that I run into word that has kj in it. If this is the case I would just wait a couple of seconds after typing k and that type j.
As mentioned by others, mapping C-j to ultisnips works great.
let g:UltiSnipsExpandTrigger="<c-j>"
Now, if you go a bit further and install xcape and use
xcape -e "Shift_L=Control_R|J"
You unleash the power of using just the shift key for utlitsnips.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
(Vim)diff two subroutines in same file
Sometimes I see a block of code I suspect to be identical to another block in the same file, but it's a bit too long for visual inspection and I may just be missing something. I've tried to visually select the block and yank to the the default register, put that register into / (find), but it didn't match even the original block.
Is there a way to select a section, yank it in a register, select another section then diff the two, without creating a bunch of new files? I imagine the diff results opening in a new buffer in a tab or split.
EDIT: My question is basically a duplicate of This one. I found this answer to be the most helpful & closest to what I was looking for. The only thing I'd change is to make it output in Unified format so it looks like the diff output I'm used to (it has more info as well). I suppose this means using a different diff utility.
Inspired from my lh#path#strip_common() function:
echo matchstr(#a.'##'.#b, '^\zs\(.*\)\ze.\{-}##\1.*$')
will show what is common between registers #a and #b.
You can show more information with:
function ShowDiff(a,b)
" I expect neither string to contain '##'
let start = matchstr(a:a.'##'.a:b, '^\zs\(.*\)\ze.\{-}##\1.*$')
let end= matchstr(a:a.'##'.a:b, '^.\{-}\zs\(.*\)\ze##.\{-}\1$')
let a = a:a[len(start): -len(end)-1]
let b = a:b[len(start): -len(end)-1]
echo "identical beginning: ".strlen(start )." chars -> ".start
echo "identical ending : ".strlen(end)." chars -> ".end
echo "typical to a : ".strlen(a)." chars -> ".a
echo "typical to b : ".strlen(b)." chars -> ".b
endfunction
Used with:
:call ShowDiff(#a, #b)
You could use the following sequence assuming that the two segments are already in registers, 'a and 'b. Could probably be put into a macro or function.
new
only
put a
diffthis
vnew
put b
diffthis
This creates a new buffer, makes it the only visible buffer, puts 'a into it, sets it up to be diff'd, then opens a new buffer in a vertical split, puts 'b into this split empty buffer and also sets it up to diff. Immediately vim (or gvim) will show the differences.
When done, type :ls to get the list of buffers, use :buffer *N* to return back to the original file and use :bdel! *N* to delete the created buffers (named "[No Name]").
Here's a function to open two new windows side by side, each containing the specified register contents (called as DiffRegs(#a, #1), for instance) and diff them. The new buffers will not be written or modifiable:
" A list for bookkeeping..
let g:diffreg_buffers = []
function! DiffRegs(reg1, reg2)
" Preserve the unnamed register
let s:nonamereg = ##
let ## = a:reg1
" new window
:new
normal P
setlocal nomodifiable
setlocal buftype=nofile
diffthis
call add(g:diffreg_buffers, bufnr('%'))
let ## = a:reg2
:vsp +enew
normal P
setlocal nomodifiable
setlocal buftype=nofile
diffthis
call add(g:diffreg_buffers, bufnr('%'))
let ## = s:nonamereg
endfunction " DiffRegs(reg1, reg2)
" Function to wipe all buffers we're diffing with the function above
function! EndDiffs()
for buffer in g:diffreg_buffers
exe ':buffer ' . buffer
diffoff
quit
endfor
let g:diffreg_buffers = []
endfunction " EndDiffs()
You can bind those to key combinations of your choice, but if you don't call EndDiffs() after each call to DiffRegs(), you'll run into issues.
To compare quickly two different parts of a file, you can split the view in two by using:
:sp horizontal split
or
:vsp vertical split
Once you have splitted the screen, you must use :diffthis in each window to hightlight the differences. (Then :diffoff to leave diff mode)
Then to go back to a single window you can quit one of them with :q or use CTRLwo
I want to make a vim cheat sheet plugin. It's real simple:
I want to toggle my cheatsheets. A vertsplit toggle, like Taglist or NERDTree.
I want the cheatsheet to be filetype specific. So I toggle my c++ cheatsheet when I have opened a .cpp file.
I want the cheatsheet to be horizontally split. So it shows two files, my syntax cheat sheet and my snippet trigger cheat sheet.
I already have a collection of these cheatsheets, in vimhelp format, but now I have to manually open them.
I haven't really done any vim scripting, but I imagine this would be really simple to put together. I'm sorta sick of googling unrelated codesnippets, so what I'm asking here is:
Could anyone give me a short sum-up of what I need to learn in regards to vim scripting to piece this together. What I have a hard time finding is how to toggle the buffer window.
If you know any intro tutorials that covers the material I need to get this up and running, please provide a link.
tx,
aktivb
The function below may not do exactly what you want, and I haven't tested it, but it should give you some ideas.
The main idea is that the function reads the filetype of the current buffer (you can test this by typing :echo &ft) and then sets the path of the appropriate cheat sheat. If it exists, this path is then opened (read-only and non-modifiable) in a split window. You can then call this function any way you wish, for example by mapping it to the {F5} key as shown.
I'm not sure about the toggling possibilities (is this really easier than just closing the split window?) but you could look at the bufloaded() function, which returns whether or not a given file is currently being accessed.
function! Load_Cheat_Sheet()
let l:ft = &ft
if l:ft == 'html'
let l:path = 'path/to/html/cheat/sheet'
elseif l:ft == 'c'
let l:path = 'path/to/c/cheat/sheet'
elseif l:ft == 'tex'
let l:path = 'path/to/tex/cheat/sheet'
endif
if l:path != '' && filereadable(l:path)
execute ':split +setlocal\ noma\ ro ' l:path
endif
endfunction
map <F5> :call Load_Cheat_Sheet()<CR>
Hope this helps. Just shout if anything is unclear, or you want to know more.
I had forgotten about this until I got a notice about Eduan's answer. Since I posted this question I've done quite a bit of vim scripting, including getting this to work:
let g:cheatsheet_dir = "~/.vim/bundle/cheatsheet/doc/"
let g:cheatsheet_ext = ".cs.txt"
command! -nargs=? -complete=customlist,CheatSheetComplete CS call ToggleCheatSheet(<f-args>)
nmap <F5> :CS<CR>
" strip extension from complete list
function! CheatSheetComplete(A,L,P)
return map(split(globpath(g:cheatsheet_dir, a:A.'*'.g:cheatsheet_ext)),
\ "v:val[".strlen(expand(g:cheatsheet_dir)).
\ ":-".(strlen(g:cheatsheet_ext) + 1)."]")
endfun
" specify cheatsheet or use filetype of open buffer as default
" instead of saving window status in a boolean variable,
" test if the file is open (by name). If a boolean is used,
" you'll run into trouble if you close the window manually with :wq etc
function! ToggleCheatSheet(...)
if a:0
let s:file = g:cheatsheet_dir.a:1.g:cheatsheet_ext
else
if !exists("s:file") || bufwinnr(s:file) == -1
let s:file = g:cheatsheet_dir.&ft.g:cheatsheet_ext
endif
endif
if bufwinnr(s:file) != -1
call ToggleWindowClose(s:file)
else
call ToggleWindowOpen(s:file)
endif
endfun
" stateless open and close so it can be used with other plugins
function! ToggleWindowOpen(file)
let splitr = &splitright
set splitright
exe ":vsp ".a:file
exe ":vertical resize 84"
if !splitr
set splitright
endif
endfun
function! ToggleWindowClose(file)
let w_orig = bufwinnr('%')
let w = bufwinnr(a:file)
exe w.'wincmd w'
exe ':silent wq!'
if w != w_orig
exe w_orig.'wincmd w'
endif
endfun
Thought I would add to Goulash's answer.
I think in order to implement the toggle you would simply use some if statements and a global variable.
let g:cheatsheet_toggle_on=0
if (g:cheatsheet_toggle_on == 0)
" Turn the cheatsheet on
" Also make sure to know that the toggle is on:
let g:cheatsheet_toggle_on=1
elseif (g:cheatsheet_toggle_on=1
" Do whatever you need to turn it off, here
endif
Hope this figures out that logic. :)