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.
Related
For example, suppose I want to implement a plugin that draws a margin line at 80 colums using custom characters (suppose I want the line to made from a column of * characters).
How can that be done in Vim or Neovim?
But more generically, is there a way to draw stuff over the text buffer without affecting the text content?
For example, how can I draw an inner rectangle inside a window which I can make bright colored in order to show the active window? The effect would be that the first line visible line of what is currently a text buffer would be filled with --- characters, the right-most column of the what is currently a text buffer would be filled with |. This would be inside the window, separate from the statuslines or vertical split lines.
Etc. How to do such things?
Some plugins that currently draw over the text buffer in different ways:
https://github.com/easymotion/vim-easymotion
https://github.com/Yggdroot/indentLine
EasyMotion does not draw over the text, i don't think this is possible.
What it does is defined in following function (sourcecode):
function! EasyMotion#helper#VarReset(var, ...) "{{{
if ! exists('s:var_reset')
let s:var_reset = {}
endif
if a:0 == 0 && has_key(s:var_reset, a:var)
" Reset var to original value
" setbufvar( or bufname): '' or '%' can be used for the current buffer
call setbufvar('%', a:var, s:var_reset[a:var])
elseif a:0 == 1
" Save original value and set new var value
let new_value = a:0 == 1 ? a:1 : ''
" Store original value
let s:var_reset[a:var] = getbufvar("", a:var)
" Set new var value
call setbufvar('%', a:var, new_value)
endif
endfunction "}}}
So it saves every replaced char and restores them afterwards.
I haven't looked at indentLine but it probably does intelligent listchars, as there is never text under the indentchar.
Anyway it isn't as if I am an expert on one of the plugin or vim in general. I just write this answer because i think there are easier way to achieve what you want. You could for example highlight the border lines with a certain color, or change the background for the active split. There is also a plugin for dimming inactive splits: https://github.com/blueyed/vim-diminactive
autocmd VimResized * <foo> will run the command <foo> whenever the vim application's window is resized.
Is there a way to run different commands depending on whether the resize is a shrink or a grow?
And, if so, are there any caveats for console vim?
A window is 2-dimensionnal, so the concept of shrinking or growing is quite imprecise : are you talking about the height, or about the width, or about the area?
Let's assume you're talking about the area.
A simple way to do it is to save the last size of the window, on startup and on each time the win is resized; then you just have to compare the last size and the new one, each time the win is resized:
" Defines a command to save the current dims:
command! SaveVimDims let g:last_lines=&lines | let g:last_columns=&columns
" Saves the dims on startup:
au VimEnter * SaveVimDims
" Calls the func below, each the win is resized:
au VimResized * call VimResized_Func()
function! VimResized_Func()
" Gets the area of the last dims:
let last_area = g:last_lines * g:last_columns
" Saves the new dims:
SaveVimDims
" Gets the area of the new dims:
let cur_area = g:last_lines * g:last_columns
" Compares the areas:
if cur_area < last_area
" do something when shrinking
else
" do something when growing
endif
endf
This was only tested with Gvim; I never use Vim in console. Hope it'll work as well
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)')
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__')
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. :)