Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: dont mess window layout when closing buffer (closes #19) #21

Merged
merged 1 commit into from
Oct 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ Left-click to go, middle-click or close button to close.

![unique-name](./static/unique-name.png)

##### bbye.vim for closing buffers

A modified version of [bbye.vim](https://github.com/moll/vim-bbye) is included in this
plugin to close buffers without messing with you window layout and more. Available
as `BufferClose` and `bufferline#bbye#delete(buf)`.

## Install

Is ~~two~~ one dependency a lot for one plugin? Yes it is. But is Barbar a very good
Expand All @@ -81,7 +87,11 @@ required functions, or if you complain loud enough.

## Usage

No default mappings are provided, here is an example:
### Mappings & commands

No default mappings are provided, here is an example. It is recommended to use
the `BufferClose` command to close buffers instead of `bdelete` because it will
not mess your window layout.

```vim
" Magic buffer-picking mode
Expand All @@ -105,8 +115,14 @@ nnoremap <silent> <A-6> :BufferGoto 6<CR>
nnoremap <silent> <A-7> :BufferGoto 7<CR>
nnoremap <silent> <A-8> :BufferGoto 8<CR>
nnoremap <silent> <A-9> :BufferLast<CR>
" Close buffer
nnoremap <silent> <A-c> :BufferClose<CR>
" Wipeout buffer
" :BufferWipeout<CR>
```

### Highlighting

For the highligh groups, here are the default ones:
```vim

Expand Down Expand Up @@ -190,3 +206,8 @@ a "barbar".
It is pronounced like "Jar Jar" in "Jar Jar Binks", but with Bs.

No, barbar has nothing to do with barbarians.

## License

barbar.nvim: Distributed under the terms of the JSON license.
bbye.vim: Distributed under the terms of the GNU Affero license.
109 changes: 109 additions & 0 deletions autoload/bufferline/bbye.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
" Bbye
"
" source: https://github.com/moll/vim-bbye/blob/master/plugin/bbye.vim
" license:
"
" Copyright (C) 2013 Andri Möll
"
" This program is free software: you can redistribute it and/or modify it under
" the terms of the GNU Affero General Public License as published by the Free
" Software Foundation, either version 3 of the License, or any later version.
"
" Additional permission under the GNU Affero GPL version 3 section 7:
" If you modify this Program, or any covered work, by linking or
" combining it with other code, such other code is not for that reason
" alone subject to any of the requirements of the GNU Affero GPL version 3.
"
" In summary:
" - You can use this program for no cost.
" - You can use this program for both personal and commercial reasons.
" - You do not have to share your own program's code which uses this program.
" - You have to share modifications (e.g bug-fixes) you've made to this program.
"
" For the full copy of the GNU Affero General Public License see:
" http://www.gnu.org/licenses.

function! bufferline#bbye#delete(action, bang, buffer_name)
let buffer = s:str2bufnr(a:buffer_name)
let w:bbye_back = 1

if buffer < 0
return s:error("E516: No buffers were deleted. No match for ".a:buffer_name)
endif

if getbufvar(buffer, "&modified") && empty(a:bang)
let error = "E89: No write since last change for buffer "
return s:error(error . buffer . " (add ! to override)")
endif

" If the buffer is set to delete and it contains changes, we can't switch
" away from it. Hide it before eventual deleting:
if getbufvar(buffer, "&modified") && !empty(a:bang)
call setbufvar(buffer, "&bufhidden", "hide")
endif

" For cases where adding buffers causes new windows to appear or hiding some
" causes windows to disappear and thereby decrement, loop backwards.
for window in reverse(range(1, winnr("$")))
" For invalid window numbers, winbufnr returns -1.
if winbufnr(window) != buffer | continue | endif
execute window . "wincmd w"

" Bprevious also wraps around the buffer list, if necessary:
try | exe bufnr("#") > 0 && buflisted(bufnr("#")) ? "buffer #" : "bprevious"
catch /^Vim([^)]*):E85:/ " E85: There is no listed buffer
endtry

" If found a new buffer for this window, mission accomplished:
if bufnr("%") != buffer | continue | endif

call s:new(a:bang)
endfor

" Because tabbars and other appearing/disappearing windows change
" the window numbers, find where we were manually:
let back = filter(range(1, winnr("$")), "getwinvar(v:val, 'bbye_back')")[0]
if back | exe back . "wincmd w" | unlet w:bbye_back | endif

" If it hasn't been already deleted by &bufhidden, end its pains now.
" Unless it previously was an unnamed buffer and :enew returned it again.
"
" Using buflisted() over bufexists() because bufhidden=delete causes the
" buffer to still _exist_ even though it won't be :bdelete-able.
if buflisted(buffer) && buffer != bufnr("%")
exe a:action . a:bang . " " . buffer
endif

doautocmd BufWinEnter
endfunction

function! s:str2bufnr(buffer)
if empty(a:buffer)
return bufnr("%")
elseif a:buffer =~# '^\d\+$'
return bufnr(str2nr(a:buffer))
else
return bufnr(a:buffer)
endif
endfunction

function! s:new(bang)
exe "enew" . a:bang

setl noswapfile
" If empty and out of sight, delete it right away:
setl bufhidden=wipe
" Regular buftype warns people if they have unsaved text there. Wouldn't
" want to lose someone's data:
setl buftype=
" Hide the buffer from buffer explorers and tabbars:
setl nobuflisted
endfunction

" Using the built-in :echoerr prints a stacktrace, which isn't that nice.
function! s:error(msg)
echohl ErrorMsg
echomsg a:msg
echohl NONE
let v:errmsg = a:msg
endfunction
9 changes: 8 additions & 1 deletion doc/barbar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ at the top of your window. And it does it well so it's more than a bar. Barbar.
2. Mappings & Commands *barbar-mappings* *barbar-commands*

The plugin doesn't provide default mappings as there isn't any standard. The
list below is the mappings I use.
list below is the mappings I use. It is recommended to use the `BufferClose`
command to close buffers instead of `bdelete` because it will not mess your
window layout.

The name of each command should be descriptive enough for you to use it.

Expand Down Expand Up @@ -49,6 +51,11 @@ The name of each command should be descriptive enough for you to use it.
nnoremap <silent> <A-7> :BufferGoto 7<CR>
nnoremap <silent> <A-8> :BufferGoto 8<CR>
nnoremap <silent> <A-9> :BufferLast<CR>

" Close buffer
nnoremap <silent> <A-c> :BufferClose<CR>
" Wipeout buffer
" :BufferWipeout<CR>
<

==============================================================================
Expand Down
71 changes: 45 additions & 26 deletions plugin/bufferline.vim
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,23 @@ augroup bufferline
augroup END

function! s:did_load (...)
augroup bufferline_update
au!
au BufNew,BufDelete * call bufferline#update()
au BufWinEnter,BufEnter * call bufferline#update()
au BufWritePost * call bufferline#update()
au TabEnter,TabNewEntered * call bufferline#update()
au SessionLoadPost * call bufferline#update()
au WinEnter,WinLeave * call bufferline#update()
au WinClosed * call bufferline#update()
augroup END

call bufferline#update()
endfunc
call timer_start(100, function('s:did_load'))
augroup bufferline_update
au!
au BufNew * call bufferline#update()
au BufEnter * call bufferline#update()
au BufWipeout * call bufferline#update()
au BufWinEnter * call bufferline#update()
au BufWinLeave * call bufferline#update()
au BufWritePost * call bufferline#update()
au SessionLoadPost * call bufferline#update()
au WinEnter * call bufferline#update()
au WinLeave * call bufferline#update()
au WinClosed * call bufferline#update_async()
augroup END

call bufferline#update()
endfunc
call timer_start(25, function('s:did_load'))


command! -bang BufferNext call s:goto_buffer_relative(+1)
Expand All @@ -43,6 +46,13 @@ command! -bang BufferPick call bufferline#pick_buffer()
command! -bang BufferOrderByDirectory call bufferline#order_by_directory()
command! -bang BufferOrderByLanguage call bufferline#order_by_language()

command! -bang -complete=buffer -nargs=?
\ BufferClose call bufferline#bbye#delete('bdelete', <q-bang>, <q-args>)
command! -bang -complete=buffer -nargs=?
\ BufferDelete call bufferline#bbye#delete('bdelete', <q-bang>, <q-args>)
command! -bang -complete=buffer -nargs=?
\ BufferWipeout call bufferline#bbye#delete('bwipeout', <q-bang>, <q-args>)

"=================
" Section: Options
"=================
Expand All @@ -61,7 +71,6 @@ let bufferline = extend({
"==========================

" Hl groups used for coloring
let s:hl_picking = 'BufferTargetSign'
let s:hl_status = ['Inactive', 'Visible', 'Current']
let s:hl_groups = ['BufferInactive', 'BufferVisible', 'BufferCurrent']

Expand All @@ -87,6 +96,9 @@ endfunc

call s:setup_hl()

" Last value for tabline
let s:last_tabline = ''

" Current buffers in tabline (ordered)
let s:buffers = []

Expand Down Expand Up @@ -135,7 +147,16 @@ let s:empty_bufnr = nvim_create_buf(0, 1)
"========================

function! bufferline#update()
let &tabline = bufferline#render()
let new_value = bufferline#render()
if new_value == s:last_tabline
return
end
let &tabline = new_value
let s:last_tabline = new_value
endfu

function! bufferline#update_async()
call timer_start(1, {->bufferline#update()})
endfu

function! bufferline#render()
Expand Down Expand Up @@ -198,8 +219,8 @@ function! bufferline#render()
let status = s:hl_status[type]
let mod = is_modified ? 'Mod' : ''

let signPrefix = s:hl('Buffer' . status . 'Sign')
let sign = status == 'Inactive' ?
let separatorPrefix = s:hl('Buffer' . status . 'Sign')
let separator = status == 'Inactive' ?
\ g:icons.bufferline_separator_inactive :
\ g:icons.bufferline_separator_active

Expand Down Expand Up @@ -241,7 +262,7 @@ function! bufferline#render()
let padding = repeat(' ', padding_width)
let item =
\ clickable .
\ signPrefix . sign .
\ separatorPrefix . separator .
\ padding .
\ iconPrefix . icon .
\ namePrefix . name .
Expand All @@ -253,9 +274,9 @@ function! bufferline#render()
endfor

if actual_width < available_width
let signPrefix = s:hl('BufferInactiveSign')
let sign = g:icons.bufferline_separator_inactive
let result .= signPrefix . sign
let separatorPrefix = s:hl('BufferInactiveSign')
let separator = g:icons.bufferline_separator_inactive
let result .= separatorPrefix . separator
end

let result .= s:hl('TabLineFill')
Expand Down Expand Up @@ -383,17 +404,15 @@ endfunc
" Needs to be global -_-
function! BufferlineMainClickHandler(minwid, clicks, btn, modifiers) abort
if a:btn =~ 'm'
execute 'bdelete ' . a:minwid
call bufferline#update()
call bufferline#bbye#delete('bdelete', '', a:minwid)
else
execute 'buffer ' . a:minwid
end
endfunction

" Needs to be global -_-
function! BufferlineCloseClickHandler(minwid, clicks, btn, modifiers) abort
execute 'bdelete ' . a:minwid
call bufferline#update()
call bufferline#bbye#delete('bdelete', '', a:minwid)
endfunction

" Buffer movement
Expand Down