Emacsのphp-modeでalignする

追記 2011-08-14

その2githubにあげてます。https://github.com/tetsujin/emacs-php-align

前回のエントリphp-modeではM-x alignが使えなかったので、perlのalignを無理やりphp-modeに当ててみましたが、所々やっぱり不具合があるのでElisp全然わからんなりに初めて書いてみました。*1

.emacsに追加すればたぶん動くと思います。Emacs 22.0.99, 21.3.1で動作は確認しました。

(require 'align)
(add-to-list 'align-rules-list
             '(php-assignment
               (regexp . "[^-=!^&*+<>/.| \t\n]\\(\\s-*[.-=!^&*+<>/|]*\\)=>?\\(\\s-*\\)\\([^= \t\n]\\|$\\)")
               (justify .t)
               (tab-stop . nil)
               (modes . '(php-mode))))
(add-to-list 'align-dq-string-modes 'php-mode)
(add-to-list 'align-sq-string-modes 'php-mode)
(add-to-list 'align-open-comment-modes 'php-mode)
(setq align-region-separate (concat "\\(^\\s-*$\\)\\|"
                                    "\\([({}\\(/\*\\)]$\\)\\|"
                                    "\\(^\\s-*[)}\\(\*/\\)][,;]?$\\)\\|"
                                    "\\(^\\s-*\\(}\\|for\\|while\\|if\\|else\\|"
                                    "switch\\|case\\|break\\|continue\\|do\\)[ ;]\\)"
                                    ))

;; php-mode
(add-hook 'php-mode-user-hook
          '(lambda ()
             (define-key c-mode-base-map "\C-ca" 'align-current) ; これが便利
             ))

色々考慮していたらかなりごちゃごちゃになりましたが、

↓みたいな色々な代入が混じっててもalignしてくれます。

<?php
$a = 1000;
$a += 1000;
$str = "fugafuga";
$string .= $str;
$obj = new stdClass();
$object =& new stdClass();
$array = array();
$array[] = 100000;
?>
<?php
$a        = 1000;
$a       += 1000;
$str      = "fugafuga";
$string  .= $str;
$obj      = new stdClass();
$object   =& new stdClass();
$array    = array();
$array[]  = 100000;
?>

align-current対応

setqしてるalign-region-separateてのがM-x align-currentで見るセクションの区切り判定なのですが、セクションの区切りを デフォルトの空行や{}だけじゃなく、arrayの中や、if,for等の構文も区切りに入れているので、リージョン選択しなくてもある程度構文をみて自動的にalignしてくれます。

適当ですがこんなコードがあったとしたら、カーソルがifの中ならif { 〜 }内を、elseの中なら else { 〜 } の中を、arrayの中ならその中をM-x align-currentでalignしてくれます。

<?php
if ($a == 10) {
    $foo = 1000;
    $barbaz = 1;
} else {
    $foo = 1000000;
    $barbaz = 1000;
}
$array = array(
    'k' => 'v',
    'key' => 'value',
);
?>
<?php
if ($a == 10) {
    $foo    = 1000;
    $barbaz = 1;
} else {
    $foo    = 1000000;
    $barbaz = 1000;
}
$array = array(
    'k'   => 'v',
    'key' => 'value',
);
?>

自分はこのalign-currentをC-caに割り当てたので、いちいちリージョン選択しなくても、alignしたいあたりにカーソルを持って行ってC-caと押せば勝手にalignしてくれるようにしました。かなり便利!

PEAR標準規約をそれなりに守っていればそれなりに動くとは思いますが、不具合があればゴメンナサイ。適当に改変するなりコメントくれるなりお願いします。
まあ駄目なときは素直にリージョン選択してM-x alignするということで。

*1:どんだけ需要があるかしりませんが…。