"=============================================================================
" FILE: bookmark.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu@gmail.com>
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Variables "{{{
" The version of bookmark file format.
let s:VERSION = '0.1.0'
let s:bookmarks = {}
call unite#util#set_default('g:unite_source_bookmark_directory',
\ unite#get_data_directory() . '/bookmark')
"}}}
function! unite#sources#bookmark#define() abort "{{{
return s:source
endfunction"}}}
function! unite#sources#bookmark#_append(filename) abort "{{{
if !isdirectory(g:unite_source_bookmark_directory)
\ && !unite#util#is_sudo()
call mkdir(g:unite_source_bookmark_directory, 'p')
endif
if a:filename == ''
" Append the current buffer to the bookmark list.
let path = expand('%:p')
let linenr = line('.')
let pattern = '^' . escape(getline('.'), '~"\.^*$[]') . '$'
else
let path = fnamemodify(a:filename, ':p')
let linenr = ''
let pattern = ''
endif
let path = unite#util#substitute_path_separator(path)
let filename = unite#util#substitute_path_separator(
\ a:filename == '' ? expand('%') : a:filename)
if bufexists(filename) && a:filename == ''
" Detect vimfiler and vimshell.
if &filetype ==# 'vimfiler'
let path = getbufvar(bufnr(filename), 'vimfiler').current_dir
elseif &filetype ==# 'vimshell'
let path = getbufvar(bufnr(filename), 'vimshell').current_dir
elseif &filetype ==# 'vinarise'
let path = getbufvar(bufnr(filename), 'vinarise').filename
endif
endif
let path = unite#util#substitute_path_separator(
\ path =~ '^[^:]\+://' ? path :
\ simplify(unite#util#expand(path)))
redraw
echo 'Path: ' . path
let bookmark_name = input(
\ 'Please input bookmark file name (default): ',
\ '', 'customlist,' . s:SID_PREFIX() . 'complete_bookmark_filename')
if bookmark_name == ''
let bookmark_name = 'default'
endif
let entry_name = input('Please input bookmark entry name : ')
let bookmark = s:load(bookmark_name)
call insert(bookmark.files, [entry_name, path, linenr, pattern])
call s:save(bookmark_name, bookmark)
endfunction"}}}
let s:source = {
\ 'name' : 'bookmark',
\ 'description' : 'candidates from bookmark list',
\ 'syntax' : 'uniteSource__Bookmark',
\ 'action_table' : {},
\ 'hooks' : {},
\}
function! s:source.gather_candidates(args, context) abort "{{{
let bookmark_name = s:get_bookmark_name(a:args)
if stridx(bookmark_name, '*') != -1
let bookmarks = map(filter(
\ unite#util#glob(
\ g:unite_source_bookmark_directory . '/' . bookmark_name),
\ 'filereadable(v:val)'),
\ 'fnamemodify(v:val, ":t:r")'
\)
else
let bookmarks = [bookmark_name]
endif
let candidates = []
for bookmark_name in bookmarks
let bookmark = s:load(bookmark_name)
let candidates += map(copy(bookmark.files), "{
\ 'word' : (v:val[0] != '' ? '[' . v:val[0] . '] ' : '') .
\ (fnamemodify(v:val[1], ':~:.') != '' ?
\ fnamemodify(v:val[1], ':~:.') : v:val[1]),
\ 'kind' : (isdirectory(fnamemodify(v:val[1],':p')) ? 'directory' : 'jump_list'),
\ 'source__bookmark_name' : bookmark_name,
\ 'source__bookmark_orig' : v:val,
\ 'action__path' : substitute(v:val[1], '[/\\\\]$', '', ''),
\ 'action__line' : v:val[2],
\ 'action__pattern' : v:val[3],
\ }")
endfor
return candidates
endfunction"}}}
function! s:source.hooks.on_syntax(args, context) abort "{{{
syntax match uniteSource__Bookmark_Name /\[.\{-}\] /
\ contained containedin=uniteSource__Bookmark
highlight default link uniteSource__Bookmark_Name Statement
endfunction"}}}
function! s:source.complete(args, context, arglead, cmdline, cursorpos) abort "{{{
return ['_', '*', 'default'] + map(split(glob(
\ g:unite_source_bookmark_directory . '/' . a:arglead . '*'), '\n'),
\ "fnamemodify(v:val, ':t')")
endfunction"}}}
function! s:source.vimfiler_complete(args, context, arglead, cmdline, cursorpos) abort "{{{
return self.complete(a:args, a:context, a:arglead, a:cmdline, a:cursorpos)
endfunction"}}}
function! s:source.vimfiler_check_filetype(args, context) abort "{{{
return ['directory', s:get_bookmark_name(a:args)]
endfunction"}}}
function! s:source.vimfiler_gather_candidates(args, context) abort "{{{
let exts = unite#util#is_windows() ?
\ escape(substitute($PATHEXT . ';.LNK', ';', '\\|', 'g'), '.') : ''
let candidates = self.gather_candidates(a:args, a:context)
for candidate in candidates
let candidate.vimfiler__is_directory =
\ isdirectory(candidate.action__path)
call unite#sources#file#create_vimfiler_dict(candidate, exts)
let candidate.vimfiler__filename =
\ fnamemodify(candidate.action__path, ':t')
endfor
return candidates
endfunction"}}}
" Actions "{{{
let s:source.action_table.delete = {
\ 'description' : 'delete from bookmark list',
\ 'is_invalidate_cache' : 1,
\ 'is_quit' : 0,
\ 'is_selectable' : 1,
\ }
function! s:source.action_table.delete.func(candidates) abort "{{{
for candidate in a:candidates
let bookmark = get(s:bookmarks, candidate.source__bookmark_name, [])
call filter(bookmark.files, 'v:val !=# ' .
\ string(candidate.source__bookmark_orig))
call s:save(candidate.source__bookmark_name, bookmark)
endfor
endfunction"}}}
let s:source.action_table.unite__new_candidate = {
\ 'description' : 'add new bookmark',
\ 'is_invalidate_cache' : 1,
\ 'is_quit' : 0,
\ }
function! s:source.action_table.unite__new_candidate.func(candidates) abort "{{{
let filename = input('Please input bookmark filename: ', '', 'file')
if filename == ''
redraw
echo 'Canceled.'
return
endif
call unite#sources#bookmark#_append(filename)
endfunction"}}}
"}}}
" Misc
function! s:save(filename, bookmark) abort "{{{
if unite#util#is_sudo()
return
endif
let filename = g:unite_source_bookmark_directory . '/' . a:filename
call writefile([s:VERSION] + map(copy(a:bookmark.files), 'join(v:val, "\t")'),
\ filename)
let a:bookmark.file_mtime = getftime(filename)
endfunction"}}}
function! s:load(filename) abort "{{{
let filename = g:unite_source_bookmark_directory . '/' . a:filename
call s:init_bookmark(a:filename)
let bookmark = s:bookmarks[a:filename]
if filereadable(filename)
\ && bookmark.file_mtime != getftime(filename)
let [ver; bookmark.files] = readfile(filename)
if ver !=# s:VERSION
echohl WarningMsg
echomsg 'Sorry, the version of bookmark file is old. Clears the bookmark list.'
echohl None
let bookmark.files = []
return
endif
let bookmark.files = map(bookmark.files, 'split(v:val, "\t", 1)')
for files in bookmark.files
let files[1] = unite#util#substitute_path_separator(
\ unite#util#expand(files[1]))
endfor
let bookmark.file_mtime = getftime(filename)
endif
return bookmark
endfunction"}}}
function! s:init_bookmark(filename) abort "{{{
if !has_key(s:bookmarks, a:filename)
" file_mtime: the last modified time of the bookmark file.
" files: [ [ name, full_path, linenr, search pattern ], ... ]
let s:bookmarks[a:filename] = { 'file_mtime' : 0, 'files' : [] }
endif
endfunction"}}}
function! s:complete_bookmark_filename(arglead, cmdline, cursorpos) abort "{{{
return sort(filter(map(split(glob(g:unite_source_bookmark_directory . '/*'), '\n'),
\ 'fnamemodify(v:val, ":t")'), 'stridx(v:val, a:arglead) == 0'))
endfunction"}}}
function! s:SID_PREFIX() abort
return matchstr(expand('<sfile>'), '<SNR>\d\+_\zeSID_PREFIX$')
endfunction
function! s:get_bookmark_name(args) abort "{{{
let bookmark_name = get(a:args, 0, '')
if bookmark_name =~ '/$'
let bookmark_name = bookmark_name[: -2]
endif
if bookmark_name == ''
let bookmark_name = 'default'
endif
if bookmark_name == '_'
let bookmark_name = '*'
endif
return bookmark_name
endfunction"}}}
let &cpo = s:save_cpo
unlet s:save_cpo
" vim: foldmethod=marker