Setting filenames in Tab - vim

Can someone tell me how to display filename in the tabs when I open several files using Vim?
Having a name on the tab would make changing to different files much easier.

I think your question was "how do you display only the filename on your tab label". If that was the question, my answer is:
In a gui vim, you would use:
:set guitablabel=%t
However if's in vim, it gets a little more complicate. You have to overwrite the whole line, using :tabline. I modified the example provided in the :help setting-tabline, to add the behaviour you wanted. You would need to add the following code to your vimrc:
set tabline=%!MyTabLine()
function MyTabLine()
let s = ''
for i in range(tabpagenr('$'))
" select the highlighting
if i + 1 == tabpagenr()
let s .= '%#TabLineSel#'
else
let s .= '%#TabLine#'
endif
" set the tab page number (for mouse clicks)
let s .= '%' . (i + 1) . 'T'
" the label is made by MyTabLabel()
let s .= ' %{MyTabLabel(' . (i + 1) . ')} '
endfor
" after the last tab fill with TabLineFill and reset tab page nr
let s .= '%#TabLineFill#%T'
" right-align the label to close the current tab page
if tabpagenr('$') > 1
let s .= '%=%#TabLine#%999Xclose'
endif
return s
endfunction
function MyTabLabel(n)
let buflist = tabpagebuflist(a:n)
let winnr = tabpagewinnr(a:n)
let label = bufname(buflist[winnr - 1])
return fnamemodify(label, ":t")
endfunction
I hope this helps!

Related

How to write `tabline` function in vim?

I would like tabs in Vim (not the gVim) look as follows:
Explanation:
Sequence number of tab (1, 2, 3, 4 etc)
Name of file (no path, no shortened path)
If there are more than one file opened, list them in a tab.
If there are duplicate tabs (hence the same file opened in several tabs) they should be highlighted.
If buffer is modified add + at the end of filename.
Could anybody help? I want to have something like this within my .vimrc:
set tabline=%!MyTabLine()
function! MyTabLine()
...
endfunction
I've already wrote my desired tabline function. The behaviour is almost the same, except:
the + sign appears after tab number if any of buffer inside the tab is modified
tab contains only modifiable buffers (it don't clog the line with buffers of netrw file browser, help and read-only ones), but you can change this, just uncomment the desired lines
Here is the code:
set tabline=%!MyTabLine() " custom tab pages line
function! MyTabLine()
let s = ''
" loop through each tab page
for i in range(tabpagenr('$'))
if i + 1 == tabpagenr()
let s .= '%#TabLineSel#'
else
let s .= '%#TabLine#'
endif
if i + 1 == tabpagenr()
let s .= '%#TabLineSel#' " WildMenu
else
let s .= '%#Title#'
endif
" set the tab page number (for mouse clicks)
let s .= '%' . (i + 1) . 'T '
" set page number string
let s .= i + 1 . ''
" get buffer names and statuses
let n = '' " temp str for buf names
let m = 0 " &modified counter
let buflist = tabpagebuflist(i + 1)
" loop through each buffer in a tab
for b in buflist
if getbufvar(b, "&buftype") == 'help'
" let n .= '[H]' . fnamemodify(bufname(b), ':t:s/.txt$//')
elseif getbufvar(b, "&buftype") == 'quickfix'
" let n .= '[Q]'
elseif getbufvar(b, "&modifiable")
let n .= fnamemodify(bufname(b), ':t') . ', ' " pathshorten(bufname(b))
endif
if getbufvar(b, "&modified")
let m += 1
endif
endfor
" let n .= fnamemodify(bufname(buflist[tabpagewinnr(i + 1) - 1]), ':t')
let n = substitute(n, ', $', '', '')
" add modified label
if m > 0
let s .= '+'
" let s .= '[' . m . '+]'
endif
if i + 1 == tabpagenr()
let s .= ' %#TabLineSel#'
else
let s .= ' %#TabLine#'
endif
" add buffer names
if n == ''
let s.= '[New]'
else
let s .= n
endif
" switch to no underlining and add final space
let s .= ' '
endfor
let s .= '%#TabLineFill#%T'
" right-aligned close button
" if tabpagenr('$') > 1
" let s .= '%=%#TabLineFill#%999Xclose'
" endif
return s
endfunction
:help setting-tabline contains a lengthy description, including an example function that sort-of emulates Vim's default tabline. You can use this as a starting point. See :help functions for a complete list of available functions.
Learn how to look up commands and navigate the built-in :help; it is comprehensive and offers many tips. You won't learn Vim as fast as other editors, but if you commit to continuous learning, it'll prove a very powerful and efficient editor.

Show expanded relative path instead of single letters in tabs

When I have multiple tabs open in vim, the path of the file is shown in the tab:
Notice that only the first character of the directories is used:
p/c/game.js
instead of
public/controllers/game.js
Is it possible to show the fully expanded path in the tab, using the full directory names instead of just their first letters?
This should work:
function! MyTabLine()
let s = ''
for i in range(tabpagenr('$'))
" select the highlighting
if i + 1 == tabpagenr()
let s .= '%#TabLineSel#'
else
let s .= '%#TabLine#'
endif
" set the tab page number (for mouse clicks)
let s .= '%' . (i + 1) . 'T'
" the label is made by MyTabLabel()
let s .= ' %{MyTabLabel(' . (i + 1) . ')} '
endfor
" after the last tab fill with TabLineFill and reset tab page nr
let s .= '%#TabLineFill#%T'
" right-align the label to close the current tab page
if tabpagenr('$') > 1
let s .= '%=%#TabLine#%999Xclose'
endif
return s
endfunction
function! MyTabLabel(n)
let buflist = tabpagebuflist(a:n)
let winnr = tabpagewinnr(a:n)
return fnamemodify(bufname(buflist[winnr - 1]), ':p')
endfunction
set tabline=%!MyTabLine()
This code is almost 100% from vim help (see :help setting-tabline). The only tweak is the use of fnamemodify in MyTabLabel to get the full path.

why my tabpagenr always returns 1

I have this loop in my .vimrc to display the tab title as "1: File1.txt" or "2: File2.tx", etc, but both tabpagenr('$') and tabpagenr() always returns 1 no matter how many tabs I open. What am I doing wrong?
for t in range(tabpagenr('$'))
if (t + 1) == tabpagenr()
let &titlestring = t + 1 . ': '
endif
endfor
let &titlestring .= expand("%:M")
if &term == "screen" || &term == "xterm"
set title
endif
It looks like there are some bits missing from your sample code: how do you expect to change your tab labels with only those few lines?
Anyway, without an argument, tabpagenr() returns the number of the current tab. Since you are always in the same tab during your loop, that function always returns the same number.
:help setting-tabline has an example, did you read it?
You didn't tell us on which events your code is executed. If you plainly put this in your ~/.vimrc, it will only be executed once during Vim startup. You need to use :autocmd to update the 'titlestring', at least on every tab page change (i.e. the TabEnter event), or better use an expression in the option to have it continuously evaluated:
:set titlestring=%{tabpagenr()}

How to enumerate tabs in vim?

Vim is very productive editor and I enjoy using it everyday, but I've found that moving between tabs takes more time than it should.
When I want to switch to another tab I often repeat gt or gT multiple times. Vim provides a better way to reach required tab - n + gt, where n is tab number. But to use it you should count tab number first. It quickly become boring if you open a dozen of tabs.
I think it would be nice to enumerate tabs. A single number on each tab in front of file name, something like this:
1 Readme | 2 main.c | 3 main.h | 4 process.h
I hope it is possible to configure vim to do this by editing config or using some plugin.
Is there a way to achieve it?
You can use the tabline option for setting the label of the tabs in console mode of vim.
See the help at :h setting-tabline which also shows a very basic minimal example, which you can tweak to your need, e.g. for what you want, I would use something like this:
fu! MyTabLabel(n)
let buflist = tabpagebuflist(a:n)
let winnr = tabpagewinnr(a:n)
let string = fnamemodify(bufname(buflist[winnr - 1]), ':t')
return empty(string) ? '[unnamed]' : string
endfu
fu! MyTabLine()
let s = ''
for i in range(tabpagenr('$'))
" select the highlighting
if i + 1 == tabpagenr()
let s .= '%#TabLineSel#'
else
let s .= '%#TabLine#'
endif
" set the tab page number (for mouse clicks)
"let s .= '%' . (i + 1) . 'T'
" display tabnumber (for use with <count>gt, etc)
let s .= ' '. (i+1) . ' '
" the label is made by MyTabLabel()
let s .= ' %{MyTabLabel(' . (i + 1) . ')} '
if i+1 < tabpagenr('$')
let s .= ' |'
endif
endfor
return s
endfu
set tabline=%!MyTabLine()
If you are using gvim:
set guitablabel=(%N)\ %t\ %M
Type :help tabline and :help guitablabel to read more.
There is a function MyTabLine() in the doc.

What is a vimrc function to determine if a buffer has been modified?

I have a tabline function that I stole/modified from somewhere, but I would like the filename to have an asterisk before it if it has been modified since the last time it was written to disk (ie if :up would perform an action).
For example this is my tabline when I open vim -p file*.txt
file1.txt file2.txt file3.txt
Then after I change file1.txt and don't save it:
*file1.txt file2.txt file3.txt
My tabline function:
if exists("+showtabline")
function MyTabLine()
let s = ''
let t = tabpagenr()
let i = 1
while i <= tabpagenr('$')
let buflist = tabpagebuflist(i)
let winnr = tabpagewinnr(i)
let s .= ' %*'
let s .= (i == t ? '%#TabLineSel#' : '%#TabLine#')
let file = bufname(buflist[winnr - 1])
let file = fnamemodify(file, ':p:t')
if file == ''
let file = '[No Name]'
endif
let s .= file
let i = i + 1
endwhile
let s .= '%T%#TabLineFill#%='
let s .= (tabpagenr('$') > 1 ? '%999XX' : 'X')
return s
endfunction
set stal=2
set tabline=%!MyTabLine()
endif
I was just looking for the same and found that %m and %M is not well suited, as it tells you whether the currently open buffer is modified. So you cannot see if other buffers are modified (especially for tabs, this is important).
The solution is the function getbufvar. Roughly from the help:
let s .= (getbufvar(buflist[winnr - 1], "&mod")?'*':'').file
instead of
let s .= file
should do the trick. This can be used nicely to show all buffers open in one tab (in case of multiple splits).
tabline uses similar flags as statusline (see :h statusline). So %m is what you need and modifying the lines just before the endwhile as
let s .= file
let s .= (i == t ? '%m' : '')
let i = i + 1
will automatically place the default [+] after the file name in the current tab if there are unsaved changes.

Resources