"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" buftabs (C) 2006 Ico Doornekamp
"
" This program is free software; you can redistribute it and/or modify it
" under the terms of the GNU General Public License as published by the Free
" Software Foundation; either version 2 of the License, or (at your option)
" any later version.
"
" This program is distributed in the hope that it will be useful, but WITHOUT
" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
" FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
" more details.
"
" Introduction
" ------------
"
" This is a simple script that shows a tabs-like list of buffers in the bottom
" of the window. The biggest advantage of this script over various others is
" that it does not take any lines away from your terminal, leaving more space
" for the document you're editing. The tabs are only visible when you need
" them - when you are switchin between buffers.
"
" Usage
" -----
" 
" This script draws buffer tabs on vim startup, when a new buffer is created
" and when switching between buffers.
"
" It might be handy to create a few maps for easy switching of buffers in your
" .vimrc file. For example, using F1 and F2 keys:
"
"   noremap <f1> :bprev<CR> 
"   noremap <f2> :bnext<CR>
"
" or using control-left and control-right keys:
"
"   :noremap <C-left> :bprev<CR>
"   :noremap <C-right> :bnext<CR>
"
"
" The following extra configuration variables are availabe:
" 
" * g:buftabs_only_basename
"
"   Define this variable to make buftabs only print the filename of each buffer,
"   omitting the preceding directory name. Add to your .vimrc:
"
"   :let g:buftabs_only_basename=1
"
"
" * g:buftabs_in_statusline
"
"   Define this variable to make the plugin show the buftabs in the statusline
"   instead of the command line. It is a good idea to configure vim to show
"   the statusline as well when only one window is open. Add to your .vimrc:
"
"   set laststatus=2
"   :let g:buftabs_in_statusline=1
"    
"
" * g:buftabs_active_highlight_group
" * g:buftabs_inactive_highlight_group
"
"   The name of a highlight group (:help highligh-groups) which is used to
"   show the name of the current active buffer and of all other inactive
"   buffers. If these variables are not defined, no highlighting is used.
"   (Highlighting is only functional when g:buftabs_in_statusline is enabled)
"
"   :let g:buftabs_active_highlight_group="Visual"
"
"
" * g:buftabs_marker_start   [
" * g:buftabs_marker_end     ]
" * g:buftabs_separator      -
"
"   These strings are drawn around each tab as separators.
"
"   :let g:buftabs_separator = "."  
"   :let g:buftabs_marker_start = "("
"   :let g:buftabs_marker_end = ")"       
"
"
" Changelog
" ---------
" 
" 0.1  2006-09-22  Initial version 
"
" 0.2  2006-09-22  Better handling when the list of buffers is longer then the
"                  window width.
"
" 0.3  2006-09-27  Some cleanups, set 'hidden' mode by default
"
" 0.4  2007-02-26  Don't draw buftabs until VimEnter event to avoid clutter at
"                  startup in some circumstances
"
" 0.5  2007-02-26  Added option for showing only filenames without directories
"                  in tabs
"
" 0.6  2007-03-04  'only_basename' changed to a global variable.  Removed
"                  functions and add event handlers instead.  'hidden' mode 
"                  broke some things, so is disabled now. Fixed documentation
"
" 0.7  2007-03-07  Added configuration option to show tabs in statusline
"                  instead of cmdline
"
" 0.8  2007-04-02  Update buftabs when leaving insertmode
"
" 0.9  2007-08-22  Now compatible with older Vim versions < 7.0
"
" 0.10 2008-01-26  Added GPL license
"
" 0.11 2008-02-29  Added optional syntax highlighting to active buffer name
"
" 0.12 2009-03-18  Fixed support for split windows
"
" 0.13 2009-05-07  Store and reuse right-aligned part of original statusline
"
" 0.14 2010-01-28  Fixed bug that caused buftabs in command line being
"                  overwritten when 'hidden' mode is enabled.
" 
" 0.15 2010-02-16  Fixed window width handling bug which caused strange
"                  behaviour in combination with the bufferlist plugin.
"									 Fixed wrong buffer display when deleting last window.
"									 Added extra options for tabs style and highlighting.
"
"	0.16 2010-02-28  Fixed bug causing errors when using buftabs in vim
"                  diff mode.
"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

let w:buftabs_enabled = 0
let w:original_statusline = matchstr(&statusline, "%=.*")

"
" Don't bother when in diff mode
"

if &diff                                      
	finish
endif     


"
" Called on VimEnter event
"

function! Buftabs_enable()
	let w:buftabs_enabled = 1
endfunction


"
" Persistent echo to avoid overwriting of status line when 'hidden' is enabled
" 

function! Pecho(msg)
	let s:hold_ut=&ut|let &ut=1
	let s:Pecho=a:msg
	aug Pecho
		au CursorHold * ec s:Pecho
					\|let &ut=s:hold_ut
					\|aug Pecho|exe 'au!'|aug END|aug! Pecho
	aug END
endf


"
" Draw the buftabs
"

function! Buftabs_show(deleted_buf)

	let l:i = 1
	let l:list = ''
	let l:start = 0
	let l:end = 0
	if ! exists("w:from") 
		let w:from = 0
	endif

	if ! exists("w:buftabs_enabled")
		return
	endif

	" Walk the list of buffers

	while(l:i <= bufnr('$'))

		" Only show buffers in the list, and omit help screens
	
		if buflisted(l:i) && getbufvar(l:i, "&modifiable") && a:deleted_buf != l:i

			" Get the name of the current buffer, and escape characters that might
			" mess up the statusline

			if exists("g:buftabs_only_basename")
				let l:name = fnamemodify(bufname(l:i), ":t")
			else
				let l:name = bufname(l:i)
			endif
			let l:name = substitute(l:name, "%", "%%", "g")
			
			" Append the current buffer number and name to the list. If the buffer
			" is the active buffer, enclose it in some magick characters which will
			" be replaced by markers later. If it is modified, it is appended with
			" an exclaimation mark

			if winbufnr(winnr()) == l:i
				let l:start = strlen(l:list)
				let l:list = l:list . "\x01"
			else
				let l:list = l:list . ' '
			endif
				
      let l:buftabs_separator = "-"
      if exists("g:buftabs_separator")
        let l:buftabs_separator = g:buftabs_separator
      endif

			let l:list = l:list . l:i . l:buftabs_separator
			let l:list = l:list . l:name

			if getbufvar(l:i, "&modified") == 1
				let l:list = l:list . "!"
			endif
			
			if winbufnr(winnr()) == l:i
				let l:list = l:list . "\x02"
				let l:end = strlen(l:list)
			else
				let l:list = l:list . ' '
			endif
		end

		let l:i = l:i + 1
	endwhile

	" If the resulting list is too long to fit on the screen, chop
	" out the appropriate part

	let l:width = winwidth(0) - 12

	if(l:start < w:from) 
		let w:from = l:start - 1
	endif
	if l:end > w:from + l:width
		let w:from = l:end - l:width 
	endif
		
	let l:list = strpart(l:list, w:from, l:width)

	" Replace the magic characters by visible markers for highlighting the
	" current buffer. The markers can be simple characters like square brackets,
	" but can also be special codes with highlight groups

	let l:buftabs_marker_start = "["
  if exists("g:buftabs_marker_start")
    let l:buftabs_marker_start = g:buftabs_marker_start
  endif

	let l:buftabs_marker_end = "]"
  if exists("g:buftabs_marker_end")
    let l:buftabs_marker_end = g:buftabs_marker_end
  endif
  
	if exists("g:buftabs_active_highlight_group")
		if exists("g:buftabs_in_statusline")
			let l:buftabs_marker_start = "%#" . g:buftabs_active_highlight_group . "#" . l:buftabs_marker_start
			let l:buftabs_marker_end = l:buftabs_marker_end . "%##"
		end
	end

	if exists("g:buftabs_inactive_highlight_group")
		if exists("g:buftabs_in_statusline")
			let l:list = '%#' . g:buftabs_inactive_highlight_group . '#' . l:list
			let l:list .= '%##'
			let l:buftabs_marker_end = l:buftabs_marker_end . '%#' . g:buftabs_inactive_highlight_group . '#'
		end
	end

	let l:list = substitute(l:list, "\x01", l:buftabs_marker_start, 'g')
	let l:list = substitute(l:list, "\x02", l:buftabs_marker_end, 'g')

	" Show the list. The buftabs_in_statusline variable determines of the list
	" is displayed in the command line (volatile) or in the statusline
	" (persistent)

	if exists("g:buftabs_in_statusline")
		let &l:statusline = l:list . w:original_statusline
	else
		redraw
		call Pecho(l:list)
	end

endfunction


" Hook to events to show buftabs at startup, when creating and when switching
" buffers

autocmd VimEnter * call Buftabs_enable()
autocmd VimEnter,BufNew,BufEnter,BufWritePost * call Buftabs_show(-1)
autocmd BufDelete * call Buftabs_show(expand('<abuf>'))
if version >= 700
	autocmd InsertLeave,VimResized * call Buftabs_show(-1)
end

" vi: ts=2 sw=2

