VimでのSCSSの構文強調を最新版のSassに対応させる

SassのSCSSを書いていて@function@eachが構文強調されないことにイラッとすることが増えてきたのでサクッと書いた。確認した範囲では大体うまくいっているような気がする。気が向いたらリポジトリ作る。

Download: ~/.vim/after/syntax/scss.vim

置く場所は必ず~/.vim/after/syntax/scss.vimで。vim-css3-syntaxを使ってない人は最初の方のruntime!で始まる行を全て削除するかコメント・アウトしないとエラる。after/syntax以下のシンタックス・プラグインも二重ロードのチェック必要だったかどうか思い出せないので、必要そうだったら後で追加する。

フルスクラッチで書いたわけではなく、デフォルトのランタイムに入っているsyntax/sass.vimsyntax/scss.vimを踏襲して書いた感じ。なのでSass関連の別プラグインを使っている人はうまく動かないと思う。最近追加された新機能で見逃しているものとかおかしくなるところとか見つけたらGistのコメントかなんかで報告してくれると嬉しい。

Git配下のファイルかどうかでCtrlPを切り替える

CtrlP (ctrlp.vim)では上位ディレクトリを辿って.gitとかがあったらそこを基準に起動するようにデフォルトではなっている。でもちょっと考えれば分かる通り、深い階層でかつGit配下ではない場合に非常に重い。ので設定でアクティブなバッファーのファイルのディレクトリを基準にしたりとかしてた。けどやはりGit配下の場合はやっぱりそれを考慮して欲しいので、Git配下かどうかを調べて適宜切り替える関数を書いて使い始めた。

system()でシェルのコマンドを呼ぶとその終了コードがv:shell_errorに格納されるので、それを利用した。

nnoremap <Leader>f :call <SID>CallCtrlPBasedOnGitStatus()<Return>

function! s:CallCtrlPBasedOnGitStatus()
  let s:git_status = system("git status")

  if v:shell_error == 128
    execute "CtrlPCurFile"
  else
    execute "CtrlPRoot"
  endif
endfunction

Git配下じゃない場合のgit statusの終了コードは128固定だと思うんだけどどうなんですかね!?

Vimでちょっと実行してバッファーに吐く

Vimでちょっとシェルのコマンドを実行してその結果をバッファーに持っておきたい時には"=レジスターとputを使ってやれば良いことがわかった。Windowsだとちょっと便利な気がする。他にもっと良い方法がありそうだけど、なんとなく面白いのでこれ使うことにした。

:new | put =system(\"ls\")

lsの結果が上に分割されて開く。引用符はエスケープ必須。nofileな感じにしたりとかしておいた方が色々と楽そうなので、ラップする関数とコマンド作った方が良さそう。

Vimでセッションの自動保存と復帰

セッション復帰を確認するダイアログ(アイコン……)

VimLeavemksessionを発動させるセッションの自動保存は結構前からやっていたけど、自動復帰はやってなかった(必要な時だけ:sourceしてた)のでちょろっと書いた。ライフ・チェンジング……という程ではなかった。でもまぁそこそこ必要そう。

augroup SessionAutocommands
  autocmd!

  autocmd VimEnter * nested call <SID>RestoreSessionWithConfirm()
  autocmd VimLeave * execute 'SaveSession'
augroup END

command! RestoreSession :source ~/.vim/.session
command! SaveSession    :mksession! ~/.vim/.session

" Restore session with confirm
function! s:RestoreSessionWithConfirm()
  let msg = 'Do you want to restore previous session?'

  if !argc() && confirm(msg, "&Yes\n&No", 1, 'Question') == 1
    execute 'RestoreSession'
  endif
endfunction

最初autocmdnestedフラグの存在を知らなくて、セッション復活で開かれたファイルのシンタックス・ハイライトがされないという壁にあたったけどヘルプ読んだらちゃんと書いてありました。autocmdで発動させたコマンドで開かれたりしたバッファーではBufRead等が発動しないので、自然filetypeの設定等それらのイベントに依存する処理が行われないということだった。

セッション保存/復活は「ちょっとここで保存したい」とか「起動時にキャンセルしたけどやっぱ復帰したい」とか思った時にあると便利そうなので、別にコマンドとして定義しておいた。セッションの自動保存/復帰以上の機能を求める場合(ワークスペースの切り替え的に使ったりとか)ならセッション管理プラグインを探した(作った)方が良さそう。

確認するための関数では確認と同時にargc()でVim起動時に引数でファイルが指定されているかどうかをチェックしているので、ファイルを渡して起動した時はセッション復活の確認はされない。

pathogenプラグインで特定のVimプラグインを無効にする方法

他の多機能Vimプラグイン・マネージャーと違って、pathogenプラグインではプラグインの管理はGitに任せっきりなため特定のVimプラグインを一時的に無効にするとかそういうの面倒くさい……と思ってたんですけどちゃんとそのための機能が用意されていました。無効にしたいプラグインのディレクトリ名の最後にチルダ(~)を付けるだけ!

他にもg:pathogen_disabledというグローバルな配列変数に完全一致でプラグインのディレクトリ名を列記しても可能だった。

let g:pathogen_disabled = ['foo', 'bar', 'buz']

メンテナンス性を考慮するとcalladd()呼んだ方が良さそう。

let g:pathogen_disabled = []
call add(g:pathogen_disabled, 'foo')
call add(g:pathogen_disabled, 'bar')
call add(g:pathogen_disabled, 'buz')

手軽さならリネームで、一元管理したいならグローバル変数でって感じですかね。

Bashmarks

ちょっと前からBashにブックマーク機能を持たせるシェルスクリプト、Bashmarksを使ってます。bookmarkでカレント・ディレクトリをブックマークして、いつでもgoで移動できるようになるというただそれだけのものですけど、結構便利に使ってます。補完もあるのでブックマーク名忘れても安心です!

インストールは適当な場所に保存して、~/.bashrcsourceするだけです。

source ~/bin/bashmarks.sh

ブックマークするのはbookmarkコマンドです。

$ bookmark foo

これでカレント・ディレクトリがfooという名前でブックマークされます。入力のしやすさを考慮して小文字でブックマークすると良さそうです。

$ go foo

とするといつでも移動できるようになります。

$ bookmarksshow

でブックマークの一覧が参照できますが、goコマンドには補完機能があるので

$ go <Tab><Tab>

でも一覧が参照できます。

ブックマークを管理する機能はありませんが、ブックマークを保存しているファイル(~/.bookmarks)は以下のようなシンプルなものなのでエディタで編集すれば良いでしょう。

/c/Users/Kyo/Dropbox|dropbox
/c/Users/Kyo/Dropbox/Dotfiles/vim/bundle|bundle
/d/Downloads|downloads

このように「パス|ブックマーク名」で一行が構成されています(パスがキモいのはMSYSだからです)。


僕みたいなターミナルのライトユーザー(主にGitをちょろっと使うだけの人とか)にはオススメな気がします。

たった一行で人生が変わった.vimrcでの設定とその意味

僕はVimを使うまでは秀丸エディタを長いこと使用していました。両者の間に設定の項目数やキーバインドに割り当てられる機能に大きな差があるとも思わなかったので、使い始めた当初は「そんな言うほど高機能でもないよなー」とか思っていました。しかし色々なプラグインを試したり、様々な設定を.vimrcに書いているうちに、Vim(やEmacs)がその他エディタと決定的に違うのは設定の豊富さではなく、設定の自由さがもたらすアプローチの多様性なのではないかと考えるようになりました。というわけでそういう設定の自由さを最初に実感した話をVim Advent Calendar 2011の6日目のエントリーとして書かせてもらいます。


昨今のWebサイトではCMSなどを利用することが多く、共通のHTMLコードはテンプレートとして作成されます。その場合そのテンプレートの利用されるパスが様々な場所や階層になりうるので、例えばJavaScriptファイルのインクルードを行う場合、以下のようにスラッシュで始まる相対URLを利用することが多いでしょう。

<script src="/js/foo.js"></script>

しかしこのようなURLを利用していると何かと便利なgfでカーソル下のファイル(この場合はfoo.js)を(多くの場合)開くことが出来ません。ローカル(やリモート)のファイルシステム上のパス構成をURL構成とマッチするように整えてやれば開くことができるようになりますが、それは面倒でしょう。それを解決するのが以下の一行です。

autocmd FileType html setlocal includeexpr=substitute(v:fname,'^\\/','','') | setlocal path+=;/

こう~/.vimrcに書いておくだけでgfで開くことができるようになります。includeexprでファイル名の先頭のスラッシュを削り、path;/を追加して上流を探すようにすることにより、大体うまく開くことが可能になるわけです。pathによってgf:findなどでファイルを探すパスを細かく設定できます。値の;/については、

:h file-searching

を参照するのが良いでしょう。


この一行の設定がもたらすものにはさほど意味はありません(僕にとっては大きなものでしたが)。単にgfでファイルを開くことができるようにするだけでなく、仮想的なパス構成を扱えるようにするプラグインもありますし、OS側でWebプロジェクトのディレクトリを仮想ドライブとしてマウントしてやったりするなどでもこの小さな問題は解決することができるでしょう。しかしこの程度の設定でも大体うまくいきます。つまりVimではやりたいことをやりたいようにできるということです。

設定の書き方もこのようにパイプでコマンドを繋げて無理やり一行にまとめたりすることもできますし、関数として定義してそれを呼び出してやってもいいでしょう。もちろんVimの作法に従ってafterディレクトリで設定を記述するのが良いですが、設定を集中させることによって環境の移動に強くなったりというメリットも出てきます。こういったアプローチの多様性がVimが愛されている理由のひとつであることは間違いないでしょう。

Once a vimmer, always a vimmer.

僕もきっとそうだと思います。

Gitで無視するファイル

.gitignoreで通常指定しますが、それ以外にもユーザーごとにグローバルな無視設定ファイルを設定することもできます。ここまでは知っていたんですが、リポジトリの.gitignoreには追加したくないけど特定のファイルを無視したいというケースにぶち当たってちょっと困りました。gitignoreのマニュアルを読んだ所、そういう場合は.git/info/excludeを編集すれば良いみたいですね。

つまり、

よくある無視ファイルパターン(.DS_Storeなど)
core.excludesfileで指定したファイルで設定する。
プロジェクト・メンバーで共有したい無視ファイルパターン
.gitignoreで設定する。
諸事情により自分だけが必要になる無視ファイルパターン
.git/info/excludeで設定する。

ということでしょうか。

vim-css3-syntaxのハイライト不具合について

vim-css3-syntaxでハイライトがうまくいかないことがある報告を結構初期に受けていたんですが、うまく再現できずに放置してる感じでした。昨日さらに報告を受けたのでやっぱりかなりの確率で起きるんだなーと調べ始めた所、どうやら:syntax keywordが常に:syntax matchより優先されるという仕様に絡む問題だったようです。

まだちゃんと追いきれていないのですが、多くの場合はハイフン(-)をキーワードとして認識するように設定すると単語の境界が変わるので解決できます(僕はそうしていたので再現出来なかった)。ビルトインのシンタックス・ファイルはこの設定を考慮していないと思うので、別の不具合のトリガーになる危険性もあるためどうしてもこのプラグインを使いたいという人だけ設定してみてください。

設定は、

setlocal iskeyword+=-

~/.vim/after/ftplugin/css.vimに書いたり、~/.vimrc/で、

autocmd FileType css setlocal iskeyword+=-

と自動コマンドを使ったりすればOKです。

ビルトインのsyntax/css.vimを拡張する形で書いている限り避けることが出来なさそうな問題なので、ちゃんとした解決のためには一から完全なCSS3シンタックスを書き直すしかなさそうです。ファイルタイプ・プラグインでiskeywordを拡張して、正規表現を使わずにがしがしキーワード書けるようにしちゃえば簡単そうですが……。作法とかよくわからないので大幅に変えることに躊躇しています。

Vimプラグイン: CtrlP

正規表現で絞込みが出来るという謳い文句にひかれてCtrlP (ctrlp.vim)という開いているバッファやカレント・ディレクトリのファイル、最近開いたファイル(MRU)をサクっと開けるFuzzyFinder系のプラグインを入れてみました。同系統のものとしてUniteを使っていたのですが、主に使うのはファイル・ブラウザとMRUだったのでこれでも良さそうな気もしたので。ちょっと使った感じではなかなか好感触で、しばらくメインで使ってみる気になりました。

一覧メニューはハイライトされたりするわけではないのでそっけない感じです。絞り込みを開始するとマッチした部分がハイライトされます。下から上に一覧が出るのはコマンド・ライン・ウィンドウから近くて良いですね。<C-t>でタブで開けたり、選択したファイルを開く時にExコマンドを実行できたり、複数のファイルをマークして行って一気に開くことが出来たり、ファイル・ブラウザとして必要そうな機能は大体揃っているような気がします。

謳い文句の正規表現はまぁアレですね。Vimの正規表現が覚えられないという致命的な弱点を持つ僕には無意味でした……。普通に絞込みでも速くて便利だったのでよしとします。

カレント・ディレクトリのファイルの参照はUniteのfile_recと同じ再帰探索を普通にやってるみたいなのでちょっと重いです。ここらへんはUniteの方が良く出来てるなーと思いますね。

MRUはデフォルトの150ならそれほどでもないですが、500程にすると開くのが気持ち遅いかなという感じです。MRUの記録でつっかかるとかそういう感じはないです。

キーマップを始め細かく設定できるようになっていますが、いまいちデフォルトがどうなっているのかがわからない……。とりあえず.vimrcで以下のように設定しておきました。

let g:ctrlp_jump_to_buffer      = 2
let g:ctrlp_working_path_mode   = 2
let g:ctrlp_clear_cache_on_exit = 0
let g:ctrlp_mruf_max            = 500

nnoremap <Leader>f :CtrlP<CR>
nnoremap <Leader>b :CtrlPBuffer<CR>
nnoremap <Leader>m :CtrlPMRUFiles<CR>

あと.gvimrc

let g:ctrlp_max_height = &lines

として目一杯に一覧が出るようにも。


Command-Tの対抗って感じですかね?僕のようにMRUとファイル参照メインの人には向いているんじゃないかと思います。あとMRU系のだけ探しているけどUniteはごつすぎてちょっと……とかいう人にも良さそうです。

追記

設定を少し変えたので追記しておきます。

let g:ctrlp_by_filename         = 1 " フルパスではなくファイル名のみで絞込み
let g:ctrlp_jump_to_buffer      = 2 " タブで開かれていた場合はそのタブに切り替える
let g:ctrlp_clear_cache_on_exit = 0 " 終了時キャッシュをクリアしない
let g:ctrlp_mruf_max            = 500 " MRUの最大記録数
let g:ctrlp_highlight_match     = [1, 'IncSearch'] " 絞り込みで一致した部分のハイライト
let g:ctrlp_open_new_file       = 1 " 新規ファイル作成時にタブで開く
let g:ctrlp_open_multi          = '10t' " 複数ファイルを開く時にタブで最大10まで開く

新規ファイル作成の挙動はUniteのが良かった感じです。