Vimで今見ているバッファを「現在日時+好きなファイル名」で保存する


結論

.vimrcに以下を入れて、

function! s:newfile(title)
  execute ":f /path/to/".strftime('%Y-%m-%d-%H-%M-%S').a:title.".txt"
endfunction
nnoremap <Leader>nf :<C-u>call <SID>newfile("_")<Left><Left>

マッピングに設定したコマンド(上の例ではLeaderキー*1を叩いてからnf)を打つと、コマンドラインに入力欄が出るので、そこに好きな語句を記入してエンターすると「現在日時_記入した語句」がファイル名になって保存される。

実演

f:id:note103:20161230104425g:plain

注)ここでは関数定義部分の「/path/to/」を「~/Dropbox/sample/」にしている。

経緯

半年ほど前に書いた以下の記事で、

note103.hateblo.jp

今見ているバッファを現在時刻のファイル名で保存する

というTIPを紹介したのだけど、そのときの方法は以下だった。

:w 版

function! s:wsave()
  execute ":w /path/to/".strftime('%Y-%m-%d-%H-%M-%S').".txt"
endfunction
nnoremap <silent> <Leader><Leader>w :<C-u>call <SID>wsave()<CR>

:f 版

function! s:fsave()
  execute ":f /path/to/".strftime('%Y-%m-%d-%H-%M-%S').".txt"
endfunction
nnoremap <silent> <Leader><Leader>f :<C-u>call <SID>fsave()<CR>

前者はコマンドラインモードにおける「:w」、つまり今見ているバッファはそのまま残しつつ、現在日時を刻印したファイル名で別名保存するもの。
後者は「:f」の形式、つまり今見ているバッファがそのファイル名になる、というもの。

これらの良いところは、ファイル名をわざわざ考えなくても、すぐに一意の(他と重複しない)ファイル名を付けて保存できること。
秒単位で刻印するので、カブることはほとんどない。

デメリットとしては、そのファイルを後から探そうというときに、日時だけのファイル名からでは内容を推測できないので、けっこう面倒なことになる。

よってこれらを使うのは、基本的に「後から見返すことはほとんどないと思うけど、念のため保存しておく」というときだけで、後で読み返す可能性が高いファイルに関しては、その内容を示すキーワードをファイル名に付加できるようにしたいと思っていた。

ただ、そうは思うものの僕の知識ではなかなか良い方法を思いつくことができなくて、しばらくは以下のようなマッピングでしのいでいた。

nnoremap <Leader><Leader>ww :w /path/to/.txt<Left><Left><Left><Left>
nnoremap <Leader><Leader>ff :f /path/to/.txt<Left><Left><Left><Left>
cnoremap <expr> ,df strftime('%Y-%m-%d-%H-%M')

この場合、Leaderを2回叩いてからffを叩くと、コマンドラインに「:f 保存したいディレクトリのフルパス/.txt」という文字列が出てきて、すでに「.txt」の一つ前の位置にカーソルが合っているので、そこに好きなファイル名を入れてすぐに保存できるようになっている。

前回のTIPS記事で示した「簡便に日時を出すマッピング」をコマンドラインモードでも使えるようにしているので(コードの3行目)、まず「,df」と打って日時を入れてから、何らかのキーワードを記入するという流れ。

実演

f:id:note103:20161229193602g:plain

これはこれで必要十分というか、まあ、これでもいいか……という感じになるのだけど、やはり理想は「手で記入するのはキーワードだけ」という状態であって、たとえ「,df」の3文字だけであっても、わざわざ現在日時を自分では打ちたくないというか、そこは人間が打たなくても最初から入っておいてほしい、という気持ちが強かった。

それであらためて粘って見つけたというか、考えたのが冒頭に示した現在の方法。
コード自体はガチャガチャしてちょっと恥ずかしいが、それでもこれなら現在日時は最初から入っていて、カーソルもすでに入力位置にあるので、ほんとに「キーワードだけ打ってエンターすれば確定」という感じになっている。

なお、「ファイル名とかわざわざ考えたくない。ただ一意のファイル名で即保存しておきたいだけ」という場合には、アンダーバーだけ消して(あるいはそれもそのままで)エンターすればこれでも希望は叶うが、それすら面倒という場合には(時々ある)、素直に前回紹介したマッピングを使っている。

ついでに言うと、この一連の方法では格納先のディレクトリがつねに一定なので、後から探すときにもけっこうラクというか便利。

余談

ちなみに以前は、このようなファイル保存&取り出しの用途では、@mattnさんオススメのmemolist.vimを使っていたのだけど、

mattn.kaoriya.net

今はこの手作り感満載な方法のほうが身の丈に合っているように思われ、これだけになっている。

さらにちなみに、memolistで実現できたはずの(使ってはいなかったが)grep機能というか、保存したファイル群からパターンを横断検索する機能としては、agというのを別途で使っていて、これも重宝している。

残る課題

ということで、とりあえず理想形に至ったかのように見える本件ですが、まだこれでも不満はあって、コマンドライン

:call <SNR>14_newfile("_")

なんて文字列が出てくるのはあまり美しくないというか、せめて

newfile("_")

で待機してくれるとか、あるいは対話型っぽく

Input a new filename >>

なんてふうに入力待ち状態になってほしい〜……とも思うので、その辺はもう少し模索を続けるかもしれない。

こういう小さな改善というか、便利さの追求というか、ストレス解消(発散ではなく解消)のための道行きというのは、本人がそれを意識的に望まなければなかなか進まないものなので、今後も自分の中の微弱な不満の声に敏感になって、拾い上げていきたいと思っている。

*1:デフォルトだとたしかバックスラッシュ。