For example I have two tabs opened: a/models.py and b/models.py. My conf currently shows only filename of the file opened in that tab. I would like to see path in this case because filenames are the same and otherwise I can't know in which file I am. Maybe a full path is an overkill, but 1st directory that differs would be just awesome! Any thoughts on this, on implementation?
Here's my current conf:
"
" Lightline next.
"
let g:lightline = {
\ 'colorscheme': 'wombat',
\ 'active': {
\ 'left': [ [ 'mode', 'paste' ], [ 'fugitive', 'filename' ], ['ctrlpmark', 'tagbar'] ],
\ 'right': [ [ 'syntastic', 'lineinfo' ], ['percent'], [ 'fileformat', 'fileencoding', 'filetype' ] ]
\ },
\ 'component_function': {
\ 'fugitive': 'MyFugitive',
\ 'filename': 'MyFilename',
\ 'fileformat': 'MyFileformat',
\ 'filetype': 'MyFiletype',
\ 'fileencoding': 'MyFileencoding',
\ 'mode': 'MyMode',
\ 'ctrlpmark': 'CtrlPMark',
\ },
\ 'component_expand': {
\ 'syntastic': 'SyntasticStatuslineFlag',
\ },
\ 'component_type': {
\ 'syntastic': 'error',
\ },
\ 'separator': { 'left': '⮀', 'right': '⮂' },
\ 'subseparator': { 'left': '⮁', 'right': '⮃' },
\ 'component': {
\ 'tagbar': '%{tagbar#currenttag("[%s]", "", "f")}',
\ },
\ }
function! MyModified()
return &ft =~ 'help\|vimfiler\|gundo' ? '' : &modified ? '+' : &modifiable
\ ? '' : '-'
endfunction
function! MyReadonly()
return &ft !~? 'help\|vimfiler\|gundo' && &ro ? '<U+2B64>' : ''
endfunction
function! MyFilename()
let fname = expand('%:t')
return fname == 'ControlP' ? g:lightline.ctrlp_item :
\ fname == '__Tagbar__' ? g:lightline.fname :
\ fname =~ '__Gundo\|NERD_tree' ? '' :
\ &ft == 'vimfiler' ? vimfiler#get_status_string() :
\ &ft == 'unite' ? unite#get_status_string() :
\ &ft == 'vimshell' ? vimshell#get_status_string() :
\ ('' != MyReadonly() ? MyReadonly() . ' ' : '') .
\ ('' != fname ? fname : '[No Name]') .
\ ('' != MyModified() ? ' ' . MyModified() : '')
endfunction
function! MyFugitive()
try
if expand('%:t') !~? 'Tagbar\|Gundo\|NERD' && &ft !~? 'vimfiler' && exists('*fugitive#head')
let mark = '⭠ '
let _ = fugitive#head()
return strlen(_) ? mark._ : ''
endif
catch
endtry
return ''
endfunction
function! MyFileformat()
return winwidth(0) > 70 ? &fileformat : ''
endfunction
function! MyFiletype()
return winwidth(0) > 70 ? (strlen(&filetype) ? &filetype : 'no ft') : ''
endfunction
function! MyFileencoding()
return winwidth(0) > 70 ? (strlen(&fenc) ? &fenc : &enc) : ''
endfunction
function! MyMode()
let fname = expand('%:t')
return fname == '__Tagbar__' ? 'Tagbar' :
\ fname == 'ControlP' ? 'CtrlP' :
\ fname == '__Gundo__' ? 'Gundo' :
\ fname == '__Gundo_Preview__' ? 'Gundo Preview' :
\ fname =~ 'NERD_tree' ? 'NERDTree' :
\ &ft == 'unite' ? 'Unite' :
\ &ft == 'vimfiler' ? 'VimFiler' :
\ &ft == 'vimshell' ? 'VimShell' :
\ winwidth(0) > 60 ? lightline#mode() : ''
endfunction
function! CtrlPMark()
if expand('%:t') =~ 'ControlP'
call lightline#link('iR'[g:lightline.ctrlp_regex])
return lightline#concatenate([g:lightline.ctrlp_prev, g:lightline.ctrlp_item
\ , g:lightline.ctrlp_next], 0)
else
return ''
endif
endfunction
let g:ctrlp_status_func = {
\ 'main': 'CtrlPStatusFunc_1',
\ 'prog': 'CtrlPStatusFunc_2',
\ }
function! CtrlPStatusFunc_1(focus, byfname, regex, prev, item, next, marked)
let g:lightline.ctrlp_regex = a:regex
let g:lightline.ctrlp_prev = a:prev
let g:lightline.ctrlp_item = a:item
let g:lightline.ctrlp_next = a:next
return lightline#statusline(0)
endfunction
function! CtrlPStatusFunc_2(str)
return lightline#statusline(0)
endfunction
let g:tagbar_status_func = 'TagbarStatusFunc'
function! TagbarStatusFunc(current, sort, fname, ...) abort
let g:lightline.fname = a:fname
return lightline#statusline(0)
endfunction
augroup AutoSyntastic
autocmd!
autocmd BufWritePost * call s:syntastic()
augroup END
function! s:syntastic()
SyntasticCheck
call lightline#update()
endfunction
let g:unite_force_overwrite_statusline = 0
let g:vimfiler_force_overwrite_statusline = 0
let g:vimshell_force_overwrite_statusline = 0
How about this one?
let g:lightline = {
...
\ 'tab_component_function': {
\ 'filename': 'MyTabFilename',
\ },
...
\}
function! MyTabFilename(n)
let buflist = tabpagebuflist(a:n)
let winnr = tabpagewinnr(a:n)
let bufnum = buflist[winnr - 1]
let bufname = expand('#'.bufnum.':t')
let buffullname = expand('#'.bufnum.':p')
let buffullnames = []
let bufnames = []
for i in range(1, tabpagenr('$'))
if i != a:n
let num = tabpagebuflist(i)[tabpagewinnr(i) - 1]
call add(buffullnames, expand('#' . num . ':p'))
call add(bufnames, expand('#' . num . ':t'))
endif
endfor
let i = index(bufnames, bufname)
if strlen(bufname) && i >= 0 && buffullnames[i] != buffullname
return substitute(buffullname, '.*/\([^/]\+/\)', '\1', '')
else
return strlen(bufname) ? bufname : '[No Name]'
endif
endfunction
Yes, this works! The only problem was that I was thinking about this in MyFilename instead of tabs.
Then let n be the tab number of the current tab. Simple modification.
function! MyFilename()
let n = tabpagenr()
let buflist = tabpagebuflist(n)
let winnr = tabpagewinnr(n)
let bufnum = buflist[winnr - 1]
let bufname = expand('#'.bufnum.':t')
let buffullname = expand('#'.bufnum.':p')
let buffullnames = []
let bufnames = []
for i in range(1, tabpagenr('$'))
if i != n
let num = tabpagebuflist(i)[tabpagewinnr(i) - 1]
call add(buffullnames, expand('#' . num . ':p'))
call add(bufnames, expand('#' . num . ':t'))
endif
endfor
let i = index(bufnames, bufname)
if strlen(bufname) && i >= 0 && buffullnames[i] != buffullname
return substitute(buffullname, '.*/\([^/]\+/\)', '\1', '')
else
return strlen(bufname) ? bufname : '[No Name]'
endif
endfunction
Awesome! :+1:
Found a bug.

It should have said foo/x/y and bar/x/y, instead of just x/y.
Not a bug.
You should not use configurations you cannot maintain nor do not understand.
It is IN YOUR CONFIGURATION FILE.
Simply modify the following line to your favorite behavior.
return substitute(buffullname, '.*/\([^/]\+/\)', '\1', '')
Dude, calm down. No need to be mean.
I don't use lightline, but I am writing this comment to address the "same tab name" problem.
Assuming the following files:
z.txt
a/b/c/d.txt
a/b/f/d.txt
My current setup will make the tabline look like so (I reversed-engineered this behavior from Sublime Text 2):
z.txt | d.txt - c | d.txt - f
The code has a lot of extras like treating Nerdtree/FZF tabs specially, and naming the tab according to the left-most buffer when there are splits. But you can remove these extras yourself if you don't want them, or change anything you don't like. I also assumed Unix only.
Anyways, I am just providing the code below without guarantee, as a starting point for you to customize further.
set tabline=%!GetTabLine()
function! GetTabLine()
let tabs = BuildTabs()
let line = ''
for i in range(len(tabs))
let line .= (i+1 == tabpagenr()) ? '%#TabLineSel#' : '%#TabLine#'
let line .= '%' . (i + 1) . 'T'
let line .= ' ' . tabs[i].uniq_name . ' '
endfor
let line .= '%#TabLineFill#%T'
return line
endfunction
function! BuildTabs()
let tabs = []
for i in range(tabpagenr('$'))
let tabnum = i + 1
let buflist = tabpagebuflist(tabnum)
let file_path = ''
let tab_name = bufname(buflist[0])
if tab_name =~ 'NERD_tree' && len(buflist) > 1
let tab_name = bufname(buflist[1])
end
let is_custom_name = 0
if tab_name == ''
let tab_name = '[No Name]'
let is_custom_name = 1
elseif tab_name =~ 'fzf'
let tab_name = 'FZF'
let is_custom_name = 1
else
let file_path = fnamemodify(tab_name, ':p')
let tab_name = fnamemodify(tab_name, ':p:t')
end
let tab = {
\ 'name': tab_name,
\ 'uniq_name': tab_name,
\ 'file_path': file_path,
\ 'is_custom_name': is_custom_name
\ }
call add(tabs, tab)
endfor
call CalculateTabUniqueNames(tabs)
return tabs
endfunction
function! CalculateTabUniqueNames(tabs)
for tab in a:tabs
if tab.is_custom_name | continue | endif
let tab_common_path = ''
for other_tab in a:tabs
if tab.name != other_tab.name || tab.file_path == other_tab.file_path
\ || other_tab.is_custom_name
continue
endif
let common_path = GetCommonPath(tab.file_path, other_tab.file_path)
if tab_common_path == '' || len(common_path) < len(tab_common_path)
let tab_common_path = common_path
endif
endfor
if tab_common_path == '' | continue | endif
let common_path_has_immediate_child = 0
for other_tab in a:tabs
if tab.name == other_tab.name && !other_tab.is_custom_name
\ && tab_common_path == fnamemodify(other_tab.file_path, ':h')
let common_path_has_immediate_child = 1
break
endif
endfor
if common_path_has_immediate_child
let tab_common_path = fnamemodify(common_path, ':h')
endif
let path = tab.file_path[len(tab_common_path)+1:-1]
let path = fnamemodify(path, ':~:.:h')
let dirs = split(path, '/', 1)
if len(dirs) >= 5
let path = dirs[0] . '/.../' . dirs[-1]
endif
let tab.uniq_name = tab.name . ' - ' . path
endfor
endfunction
function! GetCommonPath(path1, path2)
let dirs1 = split(a:path1, '/', 1)
let dirs2 = split(a:path2, '/', 1)
let i_different = 0
for i in range(len(dirs1))
if get(dirs1, i) != get(dirs2, i)
let i_different = i
break
endif
endfor
return join(dirs1[0:i_different-1], '/')
endfunction
Most helpful comment
Dude, calm down. No need to be mean.