"============================================================================= " FILE: exrename.vim " AUTHOR: Shougo Matsushita " EDITOR: Alisue " License: MIT license "============================================================================= let s:PREFIX = has('win32') ? '[exrename]' : '*exrename*' function! tree#exrename#create_buffer(candidates, ...) abort let options = extend({ \ 'cwd': getcwd(), \ 'bufnr': bufnr('%'), \ 'buffer_name': '', \ 'post_rename_callback': v:null, \}, 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 tree_exrename syntax match treeExrenameModified '^.*$' highlight def link treeExrenameModified Todo highlight def link treeExrenameOriginal Normal let b:exrename = options call tree#util#cd(b:exrename.cwd) nnoremap q :call exit(bufnr('%')) augroup tree-exrename autocmd! * autocmd BufHidden call s:exit(expand('')) autocmd BufWriteCmd call s:do_rename() autocmd CursorMoved,CursorMovedI call s:check_lines() augroup END " Clean up the screen. silent % delete _ silent! syntax clear treeExrenameOriginal " 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 isdirectory(candidate.action__path) let filename .= '/' endif execute 'syntax match treeExrenameOriginal' \ '/'.printf('^\%%%dl%s$', cnt, \ escape(s: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 let [undolevels, &undolevels] = [&undolevels, -1] try call setline(1, b:exrename.filenames) finally let &undolevels = undolevels endtry setlocal nomodified endfunction function! s:escape_pattern(str) abort return escape(a:str, '~"\.^$[]*') 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 = expand(getline(linenr)) if new_file !~# '^\%(\a\a\+:\)\|^\%(\a:\|/\)' let new_file = b:exrename.cwd . new_file endif if 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 != v:null 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