"=============================================================================
" FILE: exrename.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu@gmail.com>
" EDITOR: Alisue <lambdalisue@hashnote.net>
"
" 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:PREFIX = unite#util#is_windows() ? '[exrename]' : '*exrename*'
function! s:void(exrename) abort
endfunction
let s:VOID = function('s:void')
function! unite#exrename#create_buffer(candidates, ...) abort "{{{
let options = extend({
\ 'cwd': getcwd(),
\ 'bufnr': bufnr('%'),
\ 'buffer_name': '',
\ 'post_rename_callback': s:VOID,
\}, get(a:000, 0, {}))
if options.cwd !~# '/$'
" current working directory MUST end with a trailing slash
let options.cwd .= '/'
endif
if options.buffer_name ==# ''
let options.buffer_name = s:PREFIX
else
let options.buffer_name = s:PREFIX . ' - ' . options.buffer_name
endif
vsplit
redraw
execute 'edit' fnameescape(options.buffer_name)
setlocal buftype=acwrite
setlocal noswapfile
setfiletype unite_exrename
let b:exrename = options
call unite#util#lcd(b:exrename.cwd)
nnoremap <buffer><silent> q :<C-u>call <SID>exit(bufnr('%'))<CR>
augroup unite-exrename
autocmd! * <buffer>
autocmd BufHidden <buffer> call s:exit(expand('<abuf>'))
autocmd BufWriteCmd <buffer> call s:do_rename()
autocmd CursorMoved,CursorMovedI <buffer> call s:check_lines()
augroup END
" Clean up the screen.
silent % delete _
silent! syntax clear uniteExrenameOriginal
" validate candidates and register
let unique_filenames = []
let b:exrename.candidates = []
let b:exrename.filenames = []
let cnt = 1
for candidate in a:candidates
" make sure that the 'action__path' is absolute path
if !s:is_absolute(candidate.action__path)
let candidate.action__path = b:exrename.cwd . candidate.action__path
endif
" make sure that the 'action__path' exists
if !filewritable(candidate.action__path)
\ && !isdirectory(candidate.action__path)
redraw
echo candidate.action__path "does not exist. Skip."
continue
endif
" make sure that the 'action__path' is unique
if index(unique_filenames, candidate.action__path) != -1
redraw
echo candidate.action__path "is duplicated. Skip."
continue
endif
" create filename
let filename = candidate.action__path
if stridx(filename, b:exrename.cwd) == 0
let filename = filename[len(b:exrename.cwd) :]
endif
" directory should end with a trailing slash (to distinguish easily)
if get(candidate, 'vimfiler__is_directory',
\ get(candidate, 'kind', '') == 'directory')
let filename .= '/'
endif
execute 'syntax match uniteExrenameOriginal'
\ '/'.printf('^\%%%dl%s$', cnt,
\ escape(unite#util#escape_pattern(filename), '/')).'/'
" register
call add(unique_filenames, candidate.action__path)
call add(b:exrename.candidates, candidate)
call add(b:exrename.filenames, filename)
let cnt += 1
endfor
" write filenames
call setline(1, b:exrename.filenames)
setlocal nomodified
endfunction"}}}
function! s:is_absolute(path) abort "{{{
return a:path =~# '^\%(\a\a\+:\)\|^\%(\a:\|/\)'
endfunction "}}}
function! s:do_rename() abort "{{{
if line('$') != len(b:exrename.filenames)
echohl Error | echo 'Invalid rename buffer!' | echohl None
return
endif
" Rename files.
let linenr = 1
let max = line('$')
while linenr <= max
let filename = b:exrename.filenames[linenr - 1]
redraw
echo printf('(%'.len(max).'d/%d): %s -> %s',
\ linenr, max, filename, getline(linenr))
if filename !=# getline(linenr)
let old_file = b:exrename.candidates[linenr - 1].action__path
let new_file = unite#util#expand(getline(linenr))
if new_file !~ '^\%(\a\a\+:\)\|^\%(\a:\|/\)'
let new_file = b:exrename.cwd . new_file
endif
if unite#kinds#file#do_rename(old_file, new_file)
" Rename error
continue
endif
" update b:exrename
let b:exrename.filenames[linenr - 1] = getline(linenr)
let b:exrename.candidates[linenr - 1].action__path = new_file
endif
let linenr += 1
endwhile
redraw
echo 'Rename done!'
setlocal nomodified
if b:exrename.post_rename_callback != s:VOID
call b:exrename.post_rename_callback(b:exrename)
endif
endfunction"}}}
function! s:exit(bufnr) abort "{{{
if !bufexists(a:bufnr)
return
endif
" Switch buffer.
if winnr('$') != 1
close
else
call s:custom_alternate_buffer()
endif
silent execute 'bdelete!' a:bufnr
endfunction "}}}
function! s:check_lines() abort "{{{
if !exists('b:exrename')
return
endif
if line('$') != len(b:exrename.filenames)
echohl Error | echo 'Invalid rename buffer!' | echohl None
return
endif
endfunction "}}}
function! s:custom_alternate_buffer() abort "{{{
if bufnr('%') != bufnr('#') && buflisted(bufnr('#'))
buffer #
endif
let cnt = 0
let pos = 1
let current = 0
while pos <= bufnr('$')
if buflisted(pos)
if pos == bufnr('%')
let current = cnt
endif
let cnt += 1
endif
let pos += 1
endwhile
if current > cnt / 2
bprevious
else
bnext
endif
endfunction "}}}
" vim: foldmethod=marker