Emacs Lisp を仕事で使ってみた
先日、仕事で開発している製品の CSS のインデント幅を 4 から 2 に変更する必要がありました。 Unix ラブで最小主義の僕は、この場合は sed で処理するのがベストだろうと思い、以下のコマンドを叩きました。
% sed -e 's/^ / /g' *.css
しかし問題がありました。
test.css:
/*
Comments
*/
.hoge {
background-color: blue;
}
上記のような CSS を変換すると、コメントのインデントまで変換されてしまうのです。
test.css 変換後:
/*
Comments
*/
.hoge {
background-color: blue;
}
どうしようかあれこれ考えてたら、開発部長が一言。
「 Emacs Lisp で書けばいいじゃないですか」
なるほど。必要な要件は以下のような感じなので確かにベストチョイスかもしれません。
- インデント幅をそろえる
- コメントをいじるとまずい
早速 Emacs で次のようなコードを書いてみます。
(with-current-buffer (find-file-noselect "test.css") ; test.css で
(let ((pos (point-min)))
(goto-char pos) ; 最初から
(while (setq pos (re-search-forward "^[\t\s]+" (point-max) t)) ; 行頭がスペースかタブで初まるものに対して
(if (not (eq (get-text-property pos 'face) 'font-lock-comment-face)) ; コメント内ではない場合に
(indent-for-tab-command))))) ; インデントする
これを eval すると test.css が開かれてインデントが実行されます。
test.css 変換後:
/*
Comments
*/
.hoge {
background-color: blue;
}
うまくいっているようです。このコードを利用してそのまま Emacs 上で変換を行ってもいいのですが、コマンドラインから再利用できるようにするためにスクリプト化しておきます。スクリプト化に関しては「Software Design 2月号」の Elisp 特集が大変参考になりました。
indent-css.el:
(require 'cl)
(require 'css-mode)
(setq cssm-indent-function #'cssm-c-style-indenter)
(setq cssm-indent-level 2) ; インデント幅は 2
(dolist (file command-line-args-left) ; それぞれコマンドライン引数に対して
(with-current-buffer (find-file-noselect file) ; ファイルを開き
(font-lock-fontify-buffer) ; コメント判断のために font-lock をかける
(let ((pos (point-min)))
(goto-char pos) ; 最初から
(while (setq pos (re-search-forward "^[\t\s]+" (point-max) t)) ; 行頭がスペースかタブで初まるものに対して
(if (not (eq (get-text-property pos 'face) 'font-lock-comment-face)) ; コメント内ではない場合に
(indent-for-tab-command)))) ; インデントする
(save-buffer))) ; その結果を保存する
変換を実行するには以下のコマンドを実行します。
% emacs --script indent-css.el *.css
css-mode に問題があって -moz-opacity などの処理でおかしくなっていましたが、大半は意図した通りちゃんと動いてくれました。
シェルと Emacs の、この見事な調和に芸術性を感じない人はおそらくいないはずです。
処理結果を (save-buffer) するだけで保存できることに気付いたときは感動で死にそうになりました。なんと直感的なのでしょう!
テキスト処理に awk や perl を使う時代は終わりました。これからは Emacs Lisp の時代です。なんといってもエディタなのですから。
- Category(s)
- emacs
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/matsuyama/use-emacs-lisp-for-work/tbping
特別な理由がないのなら、インデント幅は統一したほうが良い様な気がします。
indent-region
でできるともっと楽ですね。
$ sed '/\/\*.*\*\//{p;d};/\/\*/,/\*\//{p;d};s/^ / /' *.css
とか?