physpolyglot

主にPC関連の自分用メモのうち、役立ちそうなものを共有します。

skeletonを使ったauto-insertのC++用テンプレート

2014/2/28 17:24 UUID ver.4の生成が間違っていたので修正。
Universally unique identifier - Wikipedia, the free encyclopedia http://en.wikipedia.org/wiki/Universally_unique_identifier

2014/4/3 18:02 skeleton-h.elでnamespaceが空のときに動作しなかったのを修正。

auto-insertはいままでテンプレートファイルを使っていたのだけど、 skeletonの方が強力かつ柔軟にテンプレートを作れると聞いたのでC++用のテンプレートをこしらえてみた。

ネット上に余り情報がなかったのでメモ。

以下のページを参考にしました。

autoinsert http://www.math.s.chiba-u.ac.jp/~matsu/emacs/emacs21/autoinsert.html EmacsWiki: Skeleton Mode http://www.emacswiki.org/emacs/SkeletonMode

.emacsに以下を加える。

(require 'autoinsert)
(add-hook 'find-file-hooks 'auto-insert)
(setq auto-insert-query nil)
(setq auto-insert-alist nil)

(add-to-list 'load-path "path/to/skeletons/")
(require 'skeleton-h)
(require 'skeleton-cc)

path/to/skeletons/の中には skeleton-h.el, skeleton-cc.elを入れておく。

下は私の場合のskeleton-h.el

(defvar auto-insert-alist)
(setq auto-insert-alist
      (append
       '(
     (("\\.h\\'" . "C/C++ header")
      nil
      '(c++-mode)
      '(setq my:skeleton-author (identity user-full-name))
      '(setq my:skeleton-mail-address (identity user-mail-address))
      '(setq my:skeleton-namespace (read-string "Namespace: " ""))
      '(setq my:skeleton-description (read-string "Short Description: " ""))
      '(setq my:skeleton-inherit (read-string "Inherits from (space separate for multiple inheritance): " ""))
      '(setq my:skeleton-inherit-list (split-string my:skeleton-inherit " " t))
      '(setq my:skeleton-inheritance (cond ((null my:skeleton-inherit-list)
                        "")
                           (t
                        (setq my:skeleton-inheritance-concat "")
                        (dolist (element my:skeleton-inherit-list)
                          (setq my:skeleton-inheritance-concat
                            (concat my:skeleton-inheritance-concat
                                "public " element ", ")))
                        (setq my:skeleton-inheritance-concat
                              (concat " : "
                                  my:skeleton-inheritance-concat))
                        (eval (replace-regexp-in-string ", \\'" "" my:skeleton-inheritance-concat)))))
      '(setq my:skeleton-include (cond ((null my:skeleton-inherit-list)
                        "")
                       (t
                        (setq my:skeleton-include "\n")
                        (dolist (element my:skeleton-inherit-list)
                          (setq my:skeleton-include
                            (concat my:skeleton-include
                                "#include \"" element ".h\"\n")))
                        (eval my:skeleton-include))))
      '(setq my:skeleton-namespace-list (split-string my:skeleton-namespace "::"))
      '(setq my:skeleton-file-name (file-name-nondirectory (buffer-file-name)))
      '(setq my:skeleton-class-name (file-name-sans-extension my:skeleton-file-name))
      '(setq my:skeleton-namespace-class
         (cond ((string= my:skeleton-namespace "")
            my:skeleton-class-name)
               (t
            (concat my:skeleton-namespace "::" my:skeleton-class-name)
            )))
      '(setq my:skeleton-namespace-decl
         (cond ((string= my:skeleton-namespace "")
            ""
            )
               (t
            (setq my:skeleton-namespace-decl-pre "")
            (setq my:skeleton-namespace-decl-post "")
            (setq my:skeleton-namespace-decl-indent "")
            (dolist (namespace-element my:skeleton-namespace-list)
              (setq my:skeleton-namespace-decl-pre
                (concat my:skeleton-namespace-decl-pre
                    my:skeleton-namespace-decl-indent
                    "namespace " namespace-element " {\n"))
              (setq my:skeleton-namespace-decl-post
                (concat "\n"
                    my:skeleton-namespace-decl-indent
                    "}"
                    my:skeleton-namespace-decl-post))
              (setq my:skeleton-namespace-decl-indent
                (concat my:skeleton-namespace-decl-indent "   "))
              )
            (eval (concat my:skeleton-namespace-decl-pre
                      my:skeleton-namespace-decl-indent
                      "class " my:skeleton-class-name ";"
                      my:skeleton-namespace-decl-post))
            )))
      '(random t)
      '(setq my:skeleton-include-guard
         (upcase
          (format "INCLUDE_GUARD_UUID_%04x%04x_%04x_4%03x_%04x_%06x%06x"
              (random (expt 16 4))
              (random (expt 16 4))
              (random (expt 16 4))
              (random (expt 16 3))
              (+ (random (expt 2 14)) (expt 2 5))
              (random (expt 16 6))
              (random (expt 16 6)))))
      "/**" n
      "* @file   " my:skeleton-file-name > n
      "* @brief  " my:skeleton-description > n
      "*" > n
      "* @date   Created       : " (format-time-string "%Y-%m-%d %H:%M:%S") > n
      "*         Last Modified :" > n
      "* @author " my:skeleton-author " <" my:skeleton-mail-address ">" > n
      "*" > n
      "*    (C) " (format-time-string "%Y") " " my:skeleton-author > n
      "*/" > n
      n
      "#ifndef " my:skeleton-include-guard n
      "#define " my:skeleton-include-guard n
      my:skeleton-include n
      my:skeleton-namespace-decl n
      n
      "class " my:skeleton-namespace-class my:skeleton-inheritance " {" n
      "public:" > n
      my:skeleton-class-name "();" n
      "virtual ~" my:skeleton-class-name "();" n
      n
      my:skeleton-class-name "(const " my:skeleton-class-name "& rhs);" n
      my:skeleton-class-name "& operator=(const " my:skeleton-class-name "& rhs);" n
      n
      "protected:" > n
      n
      "private:" > n
      n
      "ClassDef(" my:skeleton-class-name ",1) // " my:skeleton-description n
      "};" > n
      n
      "#endif // " my:skeleton-include-guard n
      '(delete-trailing-whitespace)
      )
     )
     auto-insert-alist))

(provide 'skeleton-h)

M-x find-filehoge.hを開くと 対話的にnamespace、Short Description、継承元クラスが聞かれ、それを元に下のようなファイルが作られます。
名前空間がネストしている場合もちゃんと考慮してくれるので気軽にネストさせられます!

インクルードガードはファイル移動するときのことも考えてUUIDを使うようにしました。
今まではファイル名を基にしたものにしててクラス名を変更するたびにインクルードガードも書き換えるという馬鹿らしいことをしていた……。

/**
 * @file   hoge.h
 * @brief  description
 *
 * @date   Created       : 2014-02-28 16:23:00
 *         Last Modified :
 * @author MY_NAME <my@mail.address.jp>
 *
 *    (C) 2014 MY_NAME
 */

#ifndef INCLUDE_GUARD_UUID_D81B10FF_8B30_468C_A29B_E0417A87F2E6
#define INCLUDE_GUARD_UUID_D81B10FF_8B30_468C_A29B_E0417A87F2E6

#include "TObject.h"

namespace art {
   class hoge;
}

class art::hoge : public TObject {
public:
   hoge();
   virtual ~hoge();

   hoge(const hoge& rhs);
   hoge& operator=(const hoge& rhs);

protected:

private:

   ClassDef(hoge,1) // description
};

#endif // INCLUDE_GUARD_UUID_D81B10FF_8B30_468C_A29B_E0417A87F2E6