2011年01月に牢獄機械文書群に書いたものを再掲。
ねらいは、
1. 関数 tempname() を使用して ls! でのバッファ欄に痕跡を残さない
2. 行番号を指定して部分的にバックアップも可
3. 保存した日時と保存後のファイル名をログファイルに出力(追記)
let g:logname = "$TEMP/VIM/backup.log" " ログファイル名...変更してください function! Backup2UsbMemory(dir, compress, ...) if a:dir =~ '/$' let l:dirroot = a:dir else let l:dirroot = a:dir .'/' endif let l:dirname = l:dirroot .strftime("%Y/%Y_%m/%d") if isdirectory(l:dirname) == 0 if isdirectory(l:dirroot .strftime("%Y/%Y_%m")) == 0 if isdirectory(l:dirroot .strftime("%Y/")) == 0 call mkdir(l:dirroot .strftime("%Y/")) endif call mkdir(l:dirroot .strftime("%Y/%Y_%m")) endif call mkdir(l:dirname) if expand('%') == '' echo 'Vim only made a directory named "' .l:dirname .'/"' return endif elseif expand('%') == '' echohl ErrorMsg echo 'Error: No file name' echo 'Directory ' .l:dirname ." is already made." echohl None return endif let l:compformat = '' if a:compress == 'gzip' let l:compformat = '.gz' elseif a:compress == 'bzip2' let l:compformat = '.bz2' endif let l:extend = expand("%:e") if l:extend != "" let l:extend = "." .l:extend endif let l:partsign = (len(a:000) > 0) ? "_part" : "" let l:filename = expand("%:t:r") let l:filepath = expand("%:p:h") if l:filepath != getcwd() && l:filepath != "/" let l:filename = substitute(substitute(l:filepath,'\','_','g'),'^\D:.','','g') ."_" .filename endif let l:filenamefull = l:dirname .'/' .l:filename .l:partsign ."_" \ .strftime("%y%m%d_%H%M") .l:extend .l:compformat if filereadable(l:filenamefull) return "filename is already exists." endif let l:tmp = tempname() let l:lnum = (len(a:000) > 0) ? a:1 : '^' let l:end = (len(a:000) > 1) ? a:2 : '$' call writefile(getline(l:lnum, l:end), l:tmp) call system(a:compress ." " .l:tmp) let l:fsize = ArrangeNumber(getfsize(l:tmp .l:compformat)) call rename(l:tmp .l:compformat, l:filenamefull) " add information to logfile let l:inform = \ ["@ " .strftime("%Y-%m-%d %a %H:%M :%S"), "Name: " .l:filenamefull, "Size: " .l:fsize] call AppendBackupLog(l:inform, g:logname) " ---- return '"' .split(l:filenamefull,'/')[-1] .'" Size: ' .l:fsize .' saved' endfunction function! AppendBackupLog(inform, logname) let l:loginform = [] if filereadable(a:logname) let l:loginform = readfile(a:logname) endif call writefile(l:loginform + a:inform, a:logname) endfunction " flag... ''ならログファイル表示, 'promptdel'なら削除ダイアログ, 'del'なら確認せず削除 function! ViewBackupLog(logname, flag) let l:blankmax = 10 if filereadable(a:logname) let l:loginform = readfile(a:logname) else echo "logfile not found." return endif if a:flag =~ "del" if a:flag =~ "promptdel" while 1 let l:answer = input("delete logfile? (y/n):") if l:answer =~ '^y\>' break elseif l:answer =~ '^n\>' return endif endwhile endif call delete(a:logname) echo "deleted." return endif echohl Title echo "--- Backup Log --- " echohl None for l:i in range(0, len(loginform) -1, 3) let l:date = split(l:loginform[l:i])[1] let l:time = split(l:loginform[l:i])[3] let l:filename = split(l:loginform[l:i +1], '/')[-1] let l:fsize = split(l:loginform[l:i +2])[1] echo l:date ." " .l:time .Blank(l:blankmax - len(l:fsize)) .l:fsize ." " .l:filename endfor return endfunction function! ArrangeNumber(num) if a:num < 1 return a:num endif let l:len = strlen(a:num) if l:len <= 3 return a:num endif let l:result = "" let l:modulo = l:len % 3 if l:modulo != 0 let l:result .= a:num[0:(l:modulo -1)] .',' endif for l:i in range(l:modulo, l:len -1, 3) let l:result .= a:num[(l:i):(l:i +2)] .',' endfor return l:result[:-2] endfunction function! Blank(limit) if a:limit < 1 return "" endif let l:blank = "" for l:count in range(a:limit) let l:blank .= " " endfor return l:blank endfunction
ユーザーが実際にいじる関数/変数は以下の3つ。
Backup2UsbMemory() の引数の dir は保存先の親ディレクトリ、compress は圧縮方法をそれぞれ文字列で指定する。
ViewBackupLog() はログファイルの作成、閲覧、削除のための関数。
引数の logname はログファイル名(フルパス)を文字列で指定する。
flag は '' (空文字)ならログをコマンドバッファに表示、'promptdel' ならログファイルの削除(確認あり)、'del' なら確認無しの削除。
g:logname はログファイル名をフルパスで指定。
ログが必要なければ 64, 65行目をコメントアウトしてください。
Backup2UsbMemory() は、ほかに2つ引数を指定することができる。
lnum は保存対象の開始行、end は終了行。lnum と end は省略することができる。省略した場合は、バッファ全体がバックアップ対象になる。
lnum と end は、たとえば以下のように指定できる。
この例だと、カーソル前の文字列 {{{ の一行前から、カーソル後の文字列 }}} までの行をバックアップの対象にする。
( {{{ , }}} は Vim のオプションの foldmethod 値が 'marker' のとき、fold のマーカーとして扱われる。)
グローバル変数(この例だと g:backupdirUsb )にバックアップ用の親ディレクトリを文字列で代入しておいて :command やキーマップを使うと楽。