From c6eaa6c507a962c7ae30c8403d7bd8a003ca1248 Mon Sep 17 00:00:00 2001 From: Leonid Borisenko Date: Fri, 6 Mar 2015 07:09:47 +0300 Subject: [PATCH 1/4] Add Unite filter for representing bufsurf history. Given list of buffer candidates (say, created with stock Unite buffer source) this filter (sorter_bufsurf) sorts the list to match with bufsurf history. Usage example: " .vimrc call unite#custom#profile('bufsurf', 'filters', ['sorter_bufsurf']) call unite#custom#profile('bufsurf', \'context', {'buffer_name': 'BufSurf'}) " invoke Unite command in normal mode of editing session :Unite -profile-name=bufsurf buffer --- autoload/unite/filters/sorter_bufsurf.vim | 94 +++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 autoload/unite/filters/sorter_bufsurf.vim diff --git a/autoload/unite/filters/sorter_bufsurf.vim b/autoload/unite/filters/sorter_bufsurf.vim new file mode 100644 index 0000000..a167c3f --- /dev/null +++ b/autoload/unite/filters/sorter_bufsurf.vim @@ -0,0 +1,94 @@ +" sorter_bufsurf.vim +" +" MIT license applies, see LICENSE for licensing details. + +let s:save_cpo = &cpo +set cpo&vim + +function! unite#filters#sorter_bufsurf#define() "{{{ + return s:sorter +endfunction"}}} + +let s:sorter = { + \ 'name': 'sorter_bufsurf', + \ 'description': 'sorts buffers to match with bufsurf history', + \} + +" bufsurf filter implementation. +" +" Filter expects candidate containing key `action__buffer_nr` (any other +" candidates are filtered out). Filter converts `w:history` variable +" mantained by bufsurf into list of matching candidates (matched by +" value of `candidate.action__buffer_nr`). Any buffer from `w:history` +" missing in candidates list is filtered out. +" +" Filter also preselects current buffer in resulting list (if selection +" wasn't explicitly set by user through `:Unite` option) according to variable +" `w:history_index` maintained by bufsurf. +function! s:sorter.filter(candidates, context) "{{{ + let l:window = winnr('#') + let l:history = getwinvar(l:window, 'history', []) + let l:history_index = getwinvar(l:window, 'history_index') + let l:history_buffers = + \ s:history_buffers(l:history, a:candidates, l:history_index) + call s:preselect_current_buffer(l:history_buffers, a:context) + " Get only those buffers from history that existed in candidates. + return filter(map(l:history_buffers, 'v:val[0]'), 'v:val isnot 0') +endfunction"}}} + +" Convert `w:history` variable into list of tuples consisting of buffer +" candidate and flag showing whether `w:history_index` points to this buffer. +function! s:history_buffers(history, candidates, history_index) "{{{ + " Make dictionary where number of buffer is mapped to candidate from + " candidates list. + let l:numbered_buffers = {} + for l:candidate in a:candidates + " If it doesn't have `action__buffer_nr`, it's not a buffer candidate (or, + " at least, it's not a candidate from stock buffer source). + if has_key(l:candidate, 'action__buffer_nr') + let l:numbered_buffers[candidate.action__buffer_nr] = candidate + endif + endfor + " Map `w:history` element to + " `[matching_buffer_candidate_or_zero, element_is_the_current_buffer]`. + return map( + \ copy(a:history), + \ '[get(l:numbered_buffers, v:val), (v:key == a:history_index)]') +endfunction"}}} + +" Set `context.select` to index of current buffer. +function! s:preselect_current_buffer(history_buffers, context) "{{{ + " Context passed in arguments could be either a reference to real context or + " a reference to its' copy. We need to change real context, so take + " a guaranteed reference to it. + let l:ctx = unite#get_context() + " If `context.select` is set to 0 or positive number, it was probably + " already explicitly set by user through `-select` Unite option, so default + " behavior should be skipped. + if l:ctx.select >= 0 | return | endif + " Try to find current buffer amongst candidates and preselect it by setting + " `context` value. + let l:ctx.select = 0 + for [l:_, l:is_current_buffer] in a:history_buffers + unlet! l:_ " because it could be of different types + if !l:is_current_buffer + let l:ctx.select += 1 + continue + endif + " When Unite is invoked with `-no-split` option, it shows up as a buffer + " in current window and this Unite buffer is put in `w:history`. However, + " this buffer isn't included in candidates returned by stock buffer + " source. Here this situation is handled by selecting previous buffer in + " history. + while (l:ctx.select > -1) && (a:history_buffers[l:ctx.select][0] is 0) + let l:ctx.select -= 1 + endwhile + " Selection is set, so return early. + return + endfor +endfunction"}}} + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim: foldmethod=marker From e78b5d551650d3a3628000f843565c7c7496ccfc Mon Sep 17 00:00:00 2001 From: Leonid Borisenko Date: Fri, 6 Mar 2015 09:58:33 +0300 Subject: [PATCH 2/4] Add Unite bufsurf source to show bufsurf history. Unite should find it automatically. Usage: `:Unite bufsurf` --- autoload/unite/sources/bufsurf.vim | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 autoload/unite/sources/bufsurf.vim diff --git a/autoload/unite/sources/bufsurf.vim b/autoload/unite/sources/bufsurf.vim new file mode 100644 index 0000000..1b41db4 --- /dev/null +++ b/autoload/unite/sources/bufsurf.vim @@ -0,0 +1,21 @@ +" bufsurf.vim +" +" MIT license applies, see LICENSE for licensing details. + +let s:save_cpo = &cpo +set cpo&vim + +function! unite#sources#bufsurf#define() + return s:source +endfunction + +" Basically, just stock Unite buffer source with changed sorter. +let s:source = deepcopy(unite#get_all_sources('buffer')) +let s:source.name = 'bufsurf' +let s:source.description = 'candidates from bufsurf history' +let s:source.sorters = ['sorter_bufsurf'] + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim: foldmethod=marker From 9b0c3b4cfb5f9d2affa4759b6f93c56306034c08 Mon Sep 17 00:00:00 2001 From: Leonid Borisenko Date: Fri, 6 Mar 2015 10:10:40 +0300 Subject: [PATCH 3/4] Document Unite source usage. --- README | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README b/README index 9a90d02..be7bf1f 100644 --- a/README +++ b/README @@ -21,3 +21,13 @@ then :bp(revious) in the last buffer (B) would open up buffer A, where C is preferable. This plugin supplies the user with the commands :BufSurfForward and :BufSurfBack to navigate buffers forwards and backwards according to the navigation history. + +Plugin also provides Unite [1] source for displaying bufsurf history for last +accessed window as a list of buffer candidates. Usage: `:Unite bufsurf`. +This source is actually a thin wrapper over stock Unite buffer source made +with using sorter_bufsurf filter. Filter accesses bufsurf history (list of +buffers' numbers) and converts it into buffers list consisting of matching +candidates got from list of candidates passed to filter, also preselecting +current buffer in Unite UI (by default). + +[1] https://github.com/Shougo/unite.vim From 6bc1e2a1bb2df9b9eb3aa661579586cd18deaeeb Mon Sep 17 00:00:00 2001 From: Leonid Borisenko Date: Fri, 6 Mar 2015 17:31:22 +0300 Subject: [PATCH 4/4] Add Unite source documentation in Vim help file. --- doc/bufsurf.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/bufsurf.txt b/doc/bufsurf.txt index 2bf0893..a6b9add 100644 --- a/doc/bufsurf.txt +++ b/doc/bufsurf.txt @@ -94,6 +94,23 @@ The following is a list of all available options: Indicates whether BufSurf (warning) messages should be displayed. +UNITE SOURCE *bufsurf-unite-source-bufsurf* + +bufsurs provides |unite| source for displaying bufsurf history for last +accessed window as a list of buffer candidates. Usage example: +> + :Unite bufsurf +< + + + *bufsurf-unite-filter-sorter_bufsurf* +bufsurf's Unite source is actually a thin wrapper over stock Unite buffer +source made with using sorter_bufsurf Unite filter (also provided by bufsurf). +Filter accesses bufsurf history (list of buffers' numbers) and converts it +into buffers list consisting of matching candidates got from list of +candidates passed to filter. Filter also preselects current buffer in Unite UI +(by default). + LICENSE *bufsurf-license*