pixiv insideは移転しました! ≫ https://inside.pixiv.blog/

PHP開発のためのEmacs 2016 (pixiv <3 Emacs)

こんにちは、今年もピクシブ株式会社 Advent Calendar 2016です。

最近は社内にPhpStormを浸透させようと暗躍*1してますうさみ @tadsanです ヾ(〃><)ノ゙ 今年は.emacs Advent Calendar 2016も書いてます!

2014年はEmacsでpixiv-novel-modeを作ったを書きましたが、今回は私がどうやってEmacsで仕事をするのか、そしてどのようにPHP開発環境を効率化するかについて書きます。

ちなみに昨日はkanaによるpixiv開発を支えるVim (タグジャンプ編)なので、Vimをご利用の型はこちらも読んでみてください。

なんとかStormに負けたくない気持ち

今回の内容の要約は、今年3月にPHPの知見などを共有するLT会・PHP BLT #3で発表したので、長い文章を読むのがだるいひとは見といてください。

SSHとTRAMP

pixivの開発環境は現在のところローカルマシンで動かすことが容易ではないため、共用のDebian GNU/Linuxサーバーにログインして作業する必要があります。

EmacsにはTRAMP(Transparent Remote (file) Access, Multiple Protocol)機能があります。これは、リモートサーバーや別ユーザー権限でファイルを透過的に編集するための機能です*2。PC-UNIX(Linux/macOSなど)環境であれば、~/.ssh/configの設定を読んでくれるので、SSH公開鍵でログインできる環境ならば設定は非常に簡単です。ssh hoge-servのようにログインできるサーバならば/ssh:hoge-serv:/または/scp:hoge-serv:/で開くことができます。

私はrecentfを使って履歴からファイルを開くのが好みなのですが、ローカルファイルもリモートファイルもまったく同じように絞り込んで検索できるので、とても捗って便利が強いです。

タグジャンプ

昨日のVimの記事で言及されてたタグジャンプ(クラスやメソッドの定義位置に移動する機能)ですが、私も最近まで同じ問題に悩まされてました。しかし、最近リリースされたEmacs 25.1で既存のタグジャンプの代替として搭載された新機能Xrefは定義の重複があったときには選択できるようになったので、実はあまり困ってません。

f:id:zonu_exe:20161211233855p:plain

私はctags日本語対応版を自分でビルドして、こんなシェル関数でTAGSファイルを出力します。

phptags(){
    ctags -e --php-types=c+i+d+f $(git ls-files '*.php')
}

Emacs Lispパッケージ

Emacs 24.1以降、package.elと呼ばれるパッケージ管理システムが標準機能に取り入れられました。これに更新が活溌なMELPAリポジトリを追加して利用するのが一般的です。

今回紹介するパッケージは基本的にMELPAからインストールできます。まだ利用してなければ、package.el - Emacs JPを参考にして設定してみてください*3

インターフェイス

デフォルトの状態よりもEmacsの各機能を利用しやすくために、補完インターフェイスを設定することは有効です。詳細は君は誰とEmacsる? (補完インターフェイス紹介篇)をお読みください。

php-mode

ことあるごとに紹介してるのですが、php-modeは現在でも更新が続いてますので、「むかしダウンロードしたけど更新してない」ってひとは、最新版を使ってみてください。最近ではPHP 7.1で追加された文法のサポートなども入ってます。

web-mode

web-mode.elはHTMLテンプレートを編集するためのメジャーモードです。pixivで利用するSmartyのほか、数々のテンプレート言語に対応します。

web-modeはPHPにも対応しますが、pixivではPHPをHTMLテンプレートとしては利用することはないため、私はphp-modeを利用します。

(add-to-list 'auto-mode-alist '("\\.tpl\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))

EditorConfig

EditorConfigは各種テキストエディタに対応した設定ファイルです。これを利用するとプロジェクト固有のインデントルールなどが自動で設定されるので、わざわざ設定することがなくなります。

各エディタの拡張プラグインなどがありますが、Emacsのパッケージとしてもeditorconfig-emacsがあります。

せっかくなので、pixivで使ってる.editorconfigファイルを置いておきますね。単なる設定ファイルなので著作権などはありませんから、勝手にコピペして使ってください。

Magit!

MagitはEmacs上からGitの機能を利用するためのパッケージです。Gitのほとんどの機能をEmacsと統合することができます。Gitの差分から部分ステージングできる機能(git add -p相当)、編集中のバッファのgit blameを表示する機能(M-x magit-blame)、同じくファイルの履歴を表示する機能(M-x magit-logM-x magit-log-buufer-file)などが革命的にべんりです。

TRAMP経由のリモートサーバでも、ローカルファイルと同様に操作できるのは圧倒的なメリットです。デメリットとしては… リモートファイルおよび巨大なリポジトリではちょっと遅いので、打鍵してから数秒待たされることを許容できないひとにはおすすめできません。

magit-find-file

最近のエディタではプロジェクト内のファイル名を検索して開く機能があります。magit-find-file.elはGit管理下のファイルを簡単に絞り込むことができます。

php-eldoc

PHPには「array_maparray_walkの引数が逆!」「implodeexplodeの引数が覚えられない」のように初心者がうんざりする仕様があります。大丈夫、そんなの私も覚えてません。

ElDocは、関数/メソッドの入力中引数を表示するEmacs標準の機能です。sabof/php-eldocはPHPの標準関数の引数に対してElDocを表示してくれます。

f:id:zonu_exe:20161211233942p:plain

phpunit.el

phpunit.elはEmacs上からPHPUnitをEmacs上から利用するためのパッケージです。私もバグ修正やTRAMP対応など開発に参加してます。

phpunit-current-projectでテスト全体(正確にはphpunitを引数なしで起動したときに実行されるテスト)を、phpunit-current-classで現在編集中のテストクラスにあるテストを実行できます。また、phpunit-group@groupが登録されたテストを選択的に実行できます。

composer.el

composer.elはPHPの依存管理性ソフトウェアであるComposerをEmacs上から透過的に利用するためのツールです。M-x composerではComposerの各種サブコマンドを対話的に実行できます。

EmacsからComposerを叩けて嬉しい場面もそんなに多くはありませんが、設定確認のためにM-x composer-find-json-fileで現在作業中のプロジェクトのcomposer.jsonを開けたり、M-x composer-view-lock-filecomposer.lockを読み込み専用モードで開けたりするのは、それなりにべんりなことがあるかもしれません。

Flycheck

Flycheckは編集中のファイルのsyntax checkを実行できるツールです。Emacs標準機能のflymakeよりも高機能・高速で、数多くの言語に対応します。容易に拡張もできるため、後述するように社内独自のコーディングルール違反を検知するlint checker機能を統合できます。

基本的な機能としてはPHPのSyntax Errorをその場で検出できるので、GitHubにpushしてからSyntax Errorに気付く、といったかっこわるいミスを避けられます。

f:id:zonu_exe:20161211234943p:plain

PsySH / psysh.el

PsySHはPHPのREPL/対話シェル実装です。要は、RubyのIRBとかPryとかrails console、Pythonのpythonコマンドを引数なしで実行したときに起動するアレです。

psysh.elはEmacs上からPsySHを起動したり、php-modeやphp-eldocとの連携もできます。

現在のクラス名を入力

pixiv開発を支えるVim (タグジャンプ編)にもある通り、現在pixivのコーディング規約ではクラスの静的メソッドの多用とクラス名の明示が推奨されてますので、編集中のクラス名が一発で入力できますと、大変捗ります。

この機能は現在php-modeに機能追加提案してますが、まだ取り込まれてないのでphp-util.elから、自身の.emacsファイル(~/.emacs.d/init.el)などにコピペすると良いです。

;; php-mode のキーバインドに登録する
(with-eval-after-load 'php-mode
   (define-key php-mode-map (kbd "C-c C--") 'php-util-insert-current-class)
   (define-key php-mode-map (kbd "C-c C-=") 'php-util-insert-current-namespace))

pixiv-dev.el

これはpixiv開発にべんりな設定をまとめたパッケージです。コードはzonuexe/dotfiles/pixiv-dev.elにあります。

f:id:zonu_exe:20161211234022p:plain

M-x pixiv-dev-copy-file-url

これは編集中のファイルのWeb上のURLをコピペするコマンドです。GitLabでもGitHubでもいいのですが、「このファイルのここ見といて」とチームメンバーにリポジトリ内のファイルを共有する際に、わざわざブラウザでファイルの位置を探してから共有するのは明らかに非効率です。

このコマンドがあればファイルパスからWeb上のURLを一発でコピペできるので、時間を大幅に節約できます。現在は完全にURLをべた書きをしてますが汎用化はできそうなので、もっと改善して、そのうちライブラリにしたいですね。

M-x pixiv-dev-shell

開発サーバーでPsySHを起動できます。カレントディレクトリがどこでも起動できるので超べんりです。

M-x pixiv-dev-find-file

リモートサーバー上のpixivのディレクトリから(わざわざカレントディレクトリを移動しなくても)ファイル選択ができます。作ったは良いのですが、あまり使ってません。

pixiv-dev-mode

マイナーモードです。このマイナーモードの機能として、psyshpixiv-dev-shellのために設定したり、プロジェクト専用のFlycheckのチェッカーを定義したりします。

pixiv-lintはファイルに対してコーディング規約のチェックを実行し、以下のようなログを標準出力します。

file:pixiv-lib/TagCounter.php   line:3  col:0-5 level:warn      desc:クラス定義には final を明示すること

これを解釈するチェッカーは以下のように定義できます。 (同じ記述が反復してるので、もっと簡潔に書けないのかなあ……)

(flycheck-define-checker pixiv-dev-lint
  "Lint for pixiv.git"
  :command ("pixiv-lint" source)
  :error-patterns
  ((info line-start "file:" (file-name) "\tline:" line "\tcol:" (+ (or "-" num))
         "\tlevel:info" "\tdesc:" (message) line-end)
   (error line-start "file:" (file-name) "\tline:" line "\tcol:" (+ (or "-" num))
          "\tlevel:error" "\tdesc:" (message) line-end)
   (warning line-start "file:" (file-name) "\tline:" line "\tcol:" (+ (or "-" num))
            "\tlevel:" (+ alnum) "\tdesc:" (message) line-end))
  :modes (php-mode)
  :next-checkers (php))

f:id:zonu_exe:20161211234606p:plain

弱点なのですが、私がまだFlycheckに詳しくなくてリモートサーバーにあるスクリプトを直接利用する方法がわからず、ローカルのPATH環境変数が通った場所にスクリプトをコピーしてくる、みたいなことをやってます。ルール更新のたびにコピーしてくるのもちょっとめんどくさいので、もっと効率化したいところです。

肝腎のlintスクリプトの件についても紹介したいところですが、Emacsの話題からは少し外れるので別の機会に紹介いたします。

まとめ

今回はEmacsで(PHPをはじめとした)コーディングのために便利なパッケージと自作の定義について説明しました。

もしわからないことがあれば、php-users-ja slackemacs-jp slackなどのコミュニティに常駐してますので質問していただければ解決できるかもしれません ヾ(〃><)ノ゙


さて、明日のピクシブ株式会社 Advent Calendar 2016は、弊社随一のJavaScript野郎のgeta6です。

脚注

*1:もともと経費で購入できるのですが、なまじ手慣れたエディタでどうにかできちゃってる人の方が多いのが逆に悩みなのです。

*2:概念について知りたい型は、TRAMP User Manualをお読みください。(2001年頃の訳ですが、TRAMP User Manual(日本語訳)もあります)

*3:もっと詳しく知りたい型は2015年Emacsパッケージ事情をお読みください