customizing tab tooltip in gvim to show buffer list - vim

Currently running:
VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Sep 1 2012 18:08:47)
MacOS X (unix) version
Included patches: 1-646
Compiled by Bjorn Winckler <bjorn.winckler#gmail.com>
I have the following code in my .gvimrc which should display a list of all buffers as a tooltip. However, it only shows the list of buffers that are visibly open in the current tab (split windows). The :buffers command lists all the buffers properly.
Am I misunderstanding what this code is meant to do (I'm a newbie to Vim scripting; this code was borrowed from an open sourced configuration)?
"show tooltips on tabs
set guitabtooltip=%{GuiTabToolTip()}
" set up tab tooltips with every buffer name
function! GuiTabToolTip()
let tip = ''
let bufnrlist = tabpagebuflist(v:lnum)
for bufnr in bufnrlist
" separate buffer entries
if tip!=''
let tip .= ' | '
endif
" Add name of buffer
let name=bufname(bufnr)
if name == ''
" give a name to no name documents
if getbufvar(bufnr,'&buftype')=='quickfix'
let name = '[Quickfix List]'
else
let name = '[No Name]'
endif
endif
let tip.=name
" add modified/modifiable flags
if getbufvar(bufnr, "&modified")
let tip .= ' [+]'
endif
if getbufvar(bufnr, "&modifiable")==0
let tip .= ' [-]'
endif
endfor
return tip
endfunction

The source of the buffer is tabpagebuflist(), which, as :help tabpagebuflist() explains, is a list of buffer numbers associated with each window in the current tab page.
To get the list of all buffers, you'd have to use something like
filter(range(1, bufnr('$')), 'buflisted(v:val)')

Related

A particular text tagging system in Vim

Amongst other things I use Vim for my work reports. Not exactly reports but I cannot find a better word for it now.
Those are of a form similar to
20-01-2015 14:43h
<bop> <modular system> <iva>
Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report.
02-03-2015 14:43h
<pob> <some other tag> <some other tag 2>
Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report. Text of report.
Date and time. Tags in second row, and the description that goes describing what was done.
Now this can get lengthy, since these entries are added several times a day, and the text can be significantly longer than two or three lines.
Several people read these, not all of them knowledgeable on the subject in hand. Often progress on some subject is tracked by tracking a certain tag, through the file.
Since I often have other things on my mind as well, I sometimes make a mistake and instead of <modular system> tag write <system modular> tag which makes keeping history very difficult.
So I am wondering, is there a way to use Vim's autocompletion to show a list of all tags (one or more words & numbers in < > brackets) so when adding those I can just pick them off the list, therefore avoiding the problem of mistyping them or mixing them up?
Here's my approach. It uses a separate tags file, so you can edit multiple report files and be able to use any tag in any file. It scans the files for tags and saves them as keys in a dict, so autocomplete should be quite fast. Save this as autoload/tagHelper.vim in your runtimepath, then call tagHelper#AddAutocmds() in your .vimrc. You'll have to set up global variables for the location of a tags file and the pattern to recognize these report files.
let tags = {}
if exists('g:tagFile')
let tagFile = glob(g:tagFile)
else
let tagFile = glob('~/tags.txt')
endif
if exists('g:reportPattern')
let reportPattern = g:reportPattern
else
let reportPattern = 'reports/*'
endif
function! tagHelper#LoadTags()
try
let taglist = readfile(tagFile)
catch
let taglist = []
endtry
for tag in taglist
let tags[tag] = 1
endfor
endfunction
function! tagHelper#AddMappings()
inoremap <buffer> > ><Esc>:call tagHelper#AddTagsFromLine(getline('.'))<CR>a
inoremap <buffer> < <<C-x><C-o>
setlocal omnifunc=tagHelper#CompleteTag
endfunction
function! tagHelper#AddTagsFromLine(line)
let matchStart = 0
while matchStart != 0
let nextMatchStart = match(a:line, '<[^>]\+>', matchStart)
let tag = matchstr(a:line, '<[^>]\+>', matchStart)
let tags[tag] = 1
let matchStart = nextMatchStart + strlen(tag)
endwhile
endfunction
function! tagHelper#AddAllTagsInBuffer()
for line in getline(1, '$')
call tagHelper#AddTagsFromLine(line)
endfor
endfunction
function! tagHelper#CompleteTag(findstart, base)
if a:findstart
let line = getline('.')
let col = col('.')
let start = strridx(line, '<', col) + 1
return start
endif
let matches = []
for tag in keys(tags)
if stridx(tolower(tag), tolower(a:base)) == 0
call add(matches, tag)
endif
endfor
return matches
endfunction
function! tagHelper#SaveTags()
call writefile(keys(tags), tagFile)
endfunction
function! tagHelper#AddAutocmds()
autocmd VimLeave call tagHelper#SaveTags()
exe 'autocmd BufEnter ' . reportPattern . ' call tagHelper#AddAllTagsInBuffer()'
exe 'autocmd BufEnter ' . reportPattern . ' call tagHelper#AddMappings()'
endfunction
My CompleteHelper library makes it easy to build custom completions (and I've already written quite some); you'd need one to match any tag name inside <...>. But even though the library does the hard work of building the list of matches, you'd still have to write the boilerplate code to define the pattern, and assign this to a completion key.
So, prompted by your use case, I've written the SpecialLocationComplete plugin that utilizes the CompleteHelper library and allows the definition of a custom completion via a simple configuration object. And best (for you), it even ships with a CTRL-X CTRL-X T completion for complete tags, just what you asked for (and what I imagine could be more generally useful for XML tags, too)!

Resizing the vim tabline on NERDTree window resize

I am using vim (terminal/console vim NOT gui vim) with NERDTree and NERDTreeTabs.
As you may have guessed I like to use vim's tab functionality to keep track of multiple open files.
I never really liked how the tabs would start at the very "beginning" of the tabline (there would be tabs on top of the NERDTree window). I wanted to have the tabs start from the END of the NERDTree window (i.e. the right edge), resembling an IDE. So I defined my own tabline like so:
" Globals
" NERDTree width
let g:ntw = 25
set showtabline=2 " Always show tabs
function! Tabline(width)
let s = '%#String#'. repeat(' ', a:width).'|'
for i in range(tabpagenr('$'))
let tab = i + 1
let bufnr = tabpagebuflist(tab)[tabpagewinnr(tab) - 1]
let bufname = bufname(bufnr)
let s .= '%' . tab . 'T'
let s .= (tab == tabpagenr() ? '%#TabLineSel#' : '%#TabLine#')
let s .= ' '.(bufname != '' ? fnamemodify(bufname, ':t') : 'New ').' '
if getbufvar(bufnr, "&mod") " If buf is modified
let s .= '+ '
endif
endfor
let s .= '%#TabLineFill#'
return s
endfunction
set tabline=%!Tabline(g:ntw)
let g:NERDTreeWinSize = g:ntw
Basically all I am doing is inserting blank spaces into the tabline before any tabs start. The width of the blank spaces would match the width of NERDTree. Now the problem is when I resize the NERDTree window. Obviously, the tab line's extra spacing does not resize itself automatically, resulting in an ugly mismatch.
I was thinking I could find out a way to execute 'set tabline=%!Tabline(g:ntw)" where g:btw is the current width of NERDTree whenever the NERDTree window is resized. But I am unable to find out a way to do this.
As a side note, since I am using NERDTreeTabs plugin, you can assume that the NERDTree window will ALWAYS exist. You can also assume that the NERDTree window will always be on the left.
So then my questions are:
1) Is there a more elegant way of getting this done?
2) If no to 1), how could I achieve what I am trying to do? (example code please)
Thanks in advance!
Assuming that the NERD_Tree window is always at the left, occupying the full height, its window number is 1. You can then query the current width via winwidth(1) instead of hard-coding it in your g:ntw variable.

Vim minibufexpl and taglist ctrl+tab switch

I have two of the most popular plugins installed - minibufexpl.vim and taglist.vim.
Each plugin works very well separately. When I have taglist opened and I click on several different tabs in minibufexpl, the buffer changes and with it also taglist menu is changed. The problem is when I use Ctrl+Tab and Ctrl+Shift+Tab to move between buffers and have taglist menu opened at the same time. What happens then is that actually the contents of the taglist menu gets populated with the new buffer (instead of my main portion of the window).
These are the commands that I use:
" --------------------
" TagList
" --------------------
" F4: Switch on/off TagList
nnoremap <silent> <F4> :TlistToggle<CR>
" TagListTagName - Used for tag names
highlight MyTagListTagName gui=bold guifg=Black guibg=Orange
" TagListTagScope - Used for tag scope
highlight MyTagListTagScope gui=NONE guifg=Blue
" TagListTitle - Used for tag titles
highlight MyTagListTitle gui=bold guifg=DarkRed guibg=LightGray
" TagListComment - Used for comments
highlight MyTagListComment guifg=DarkGreen
" TagListFileName - Used for filenames
highlight MyTagListFileName gui=bold guifg=Black guibg=LightBlue
"let Tlist_Ctags_Cmd = $VIM.'/vimfiles/ctags.exe' " location of ctags tool
let Tlist_Show_One_File = 1 " Displaying tags for only one file~
let Tlist_Exist_OnlyWindow = 1 " if you are the last, kill yourself
let Tlist_Use_Right_Window = 1 " split to the right side of the screen
let Tlist_Sort_Type = "order" " sort by order or name
let Tlist_Display_Prototype = 0 " do not show prototypes and not tags in the taglist window.
let Tlist_Compart_Format = 1 " Remove extra information and blank lines from the taglist window.
let Tlist_GainFocus_On_ToggleOpen = 1 " Jump to taglist window on open.
let Tlist_Display_Tag_Scope = 1 " Show tag scope next to the tag name.
let Tlist_Close_On_Select = 1 " Close the taglist window when a file or tag is selected.
let Tlist_Enable_Fold_Column = 0 " Don't Show the fold indicator column in the taglist window.
let Tlist_WinWidth = 40
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" minibufexpl "
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
let g:miniBufExplMapCTabSwitchBufs = 1 "Map control-tab and control-shift-tab for switching between buffers
let g:miniBufExplUseSingleClick = 1 "Change buffer with single click on a buffer
let g:miniBufExplModSelTarget = 1 "If you use other explorers like TagList you can (As of 6.2.8) put:
let g:miniBufExplTabWrap = 1 " make tabs show complete (no broken on two lines)
let g:miniBufExplMaxSize = 1 " <max lines: defualt 0> setting this to 0 will mean the window gets as big as needed to fit all your buffers.
I just ran into the same problem. It seems to be solved by using an already existing FuzzyFinder fix for TagList as well inside the CycleBuffer() function.
1598,1600c1598,1601
< " Don't bother autoupdating the MBE window, and skip the FuzzyFinder window
< " (Thanks toupeira!)
< if (bufname('%') == '-MiniBufExplorer-' || bufname('%') == '[fuf]')
---
> " Don't bother autoupdating the MBE window, and skip the FuzzyFinder and
> " TagList window
> " (Thanks toupeira!)
> if (bufname('%') == '-MiniBufExplorer-' || bufname('%') == '[fuf]' || bufname('%') == '__Tag_List__')

Is there a way to diff two registers in vim? [duplicate]

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

Vim script: Buffer/CheatSheet Toggle

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. :)

Resources