Emacs の auto-insert 用のテンプレートを作って楽をしよう

Emacs で新しいファイル、例えば Hoge.h を作るとき。
お決まりで書かなければいけないものがあると思います

  • include guard(#ifdef __HOGE__ 的な)
    • 何百回も include guard をコピーして書き換えてコピーした気がします
  • license/author などのコメントヘッダ
  • namespace 開く/閉じる
  • class
  • プロジェクト特有の何か(特定のクラスを継承しろとか)


1 から書くのは当然面倒なので、既存のファイルをコピペするのが一般的(?)です。
しかしこれはこれで、書き換え漏れやミスでハマったりそもそも面倒です。
そういうときは Emacs の auto-insert という機能を使って楽をしましょう。


できることは新しいファイルを作成する際に、テンプレートを利用してファイルを自動生成すること。
自分のプロジェクトや環境に合わせて、テンプレートと変数をある程度柔軟に設定できるのが大きなメリットです。

実際にやってみよう

例えば Hoge.h を c-x c-f で新しく作成する場合
下のように簡単に Hoge.h として必要な情報を埋めてファイルを作ることができます。


ファイルを開いて



auto-insert する?と聞かれるので y



できました。

やり方

ほとんど http://ja.green.xrea.jp/emacs/autoinsert-mode
https://sites.google.com/site/ytakenaka/ja/emacs/autoinsert を参考にさせていただいています。
やることは

  • テンプレートをおくディレクトリを決める。
  • .emacs に後述のコードをコピペして auto-insert-directory を自分のテンプレートディレクトリの環境に合わせる。
  • ファイルの種類に応じたテンプレートを用意する

の3つ。

.emacs
(require 'autoinsert)

;; テンプレートのディレクトリ
(setq auto-insert-directory "~/lisp/insert/")

;; 各ファイルによってテンプレートを切り替える
(setq auto-insert-alist
      (nconc '(
               ("\\.cpp$" . ["template.cpp" my-template])
               ("\\.h$"   . ["template.h" my-template])
               ) auto-insert-alist))
(require 'cl)

;; ここが腕の見せ所
(defvar template-replacements-alists
  '(("%file%"             . (lambda () (file-name-nondirectory (buffer-file-name))))
    ("%file-without-ext%" . (lambda () (file-name-sans-extension (file-name-nondirectory (buffer-file-name)))))
    ("%include-guard%"    . (lambda () (format "__SCHEME_%s__" (upcase (file-name-sans-extension (file-name-nondirectory buffer-file-name))))))))

(defun my-template ()
  (time-stamp)
  (mapc #'(lambda(c)
        (progn
          (goto-char (point-min))
          (replace-string (car c) (funcall (cdr c)) nil)))
    template-replacements-alists)
  (goto-char (point-max))
  (message "done."))
(add-hook 'find-file-not-found-hooks 'auto-insert)

template.h

/*
 * %file% - 
 *
 *   Copyright (c) 2008  Higepon(Taro Minowa)  <higepon@users.sourceforge.jp>
 *
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *  $Id: %file% 261 2008-07-25 06:16:44Z higepon $
 */

#ifndef %include-guard%
#define %include-guard%

namespace scheme {

class %file-without-ext%
{
public:
    %file-without-ext%();
    ~%file-without-ext%();

};

}; // namespace scheme

#endif // %include-guard%

template.cpp

/*
 * %file% - 
 *
 *   Copyright (c) 2008  Higepon(Taro Minowa)  <higepon@users.sourceforge.jp>
 *
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *  $Id: %file% 183 2008-07-04 06:19:28Z higepon $
 */

#include "%file-without-ext%.h"

using namespace scheme;

*1

より深く知りたい人へ

template-replacements-alists では %file% => "Hoge.h" のように、テンプレート中で展開してほしいテンプレート変数を定義しています。
ここにオリジナルのテンプレート変数を定義するのが腕の見せ所で、例えば

  • タイムスタンプを入れる
  • より複雑なクラス定義まで生成してしまう
  • ユーザー名を author にする

などができると思います。


もし面白いものを作ったらぜひトラックバックかコメントで教えてください。

*1:デストラクタが virtual じゃないのはあれがあれなのです