原文: http://yasnippet.googlecode.com/svn/trunk/doc/snippet-organization.html (translated on 2010/Dec/21) ⇒ editor's room

Organizing snippets

〔重要〕 このドキュメントは YASnippet の SVN trunk に対して適用されるものです。 SVN trunk はこちらから取得できます。 他のバージョンに対するドキュメントはこちらで見られます。

スニペットの読み込み

スニペットの定義は、ファイルシステム上のファイルの中に格納されます。 よりシンプルな "bundle" バージョンを使っているのでなければ、それらのファイルは、YASnippet が snippet table に読み込めるように配置されています。 トリガーメカニズム(Expanding snippets の章を参照)はこの snippet table を調べ、(望むらくは)あなたの意図するスニペットを展開します。

"normal" バージョンの YASnippet のアーカイブは、それを展開(解凍)した時点で、完全なディレクトリ構成を備えています。 あなたはそれをどこにでも好きなところにコピーして使うことができます。 また、他にもディレクトリを作ったりダウンロードしたりすることができます。

これらのディレクトリ群を適当な場所に置いたら、その場所を yas/root-directory 変数で参照できるようにしてください。 また、それらのディレクトリ群は関数 yas/load-directory で読み込むようにしてください。

;; Develop and keep personal snippets under ~/emacs.d/mysnippets
(setq yas/root-directory "~/emacs.d/mysnippets")

;; Load the snippets
(yas/load-directory yas/root-directory)

ディレクトリ名を yas/load-directory に直接渡さずに yas/root-directory を介すのは、 "~/emacs.d/mysnippets" をスニペットの開発のための場所として使うためです。 yas/root-directory を介すことで、yas/new-snippet などの「Writing Snippets」で記述されているようなコマンド群を使うことができるようになります。

この変数 yas/load-directory は、リストにすることができます。リストにすると、複数の値を格納できます。

;; Develop in ~/emacs.d/mysnippets, but also
;; try out snippets in ~/Downloads/interesting-snippets
(setq yas/root-directory '("~/emacs.d/mysnippets"
                           "~/Downloads/interesting-snippets"))

;; Map `yas/load-directory' to every element
(mapc 'yas/load-directory yas/root-directory)

すぐ上の例では、すべてのディレクトリが読み込まれ、そこにあるスニペットは展開すべきものとみなされます。 それでいながら、開発は依然として最初の要素である "~/emacs.d/mysnippets" で行うことができます。

スニペットを体系的に整理する

yas/root-directory の設定ができたら、そこで指定したディレクトリのサブディレクトリにスニペットを格納することができます。

スニペットの定義はプレインテキストファイルに置かれます。 それらのファイルはサブディレクトリに配置されます。 snippet table にはこれらのディレクトリの名前がつけられます。

snippet table の名前は、あなたがスニペット展開を行わせたい Emacs モードと同じにします。 たとえば、c-mode に対するスニペットは、"c-mode" という名前のサブディレクトリに置きます。 スニペットが置かれたディレクトリを丸ごと無視して、代わりに 「バンドル」を使うこともできます(YASnippet bundle の節を参照)。

ネストした構成

いくつかのモード向けのスニペットを含むディレクトリ階層の抜粋を以下に示します:

$ tree
.
`-- text-mode
    |-- cc-mode
    |   |-- c-mode
    |   |   `-- printf
    |   |-- for
    |   |-- java-mode
    |   |   `-- println
    |   `-- while
    |-- email
    |-- perl-mode
    |   |-- cperl-mode
    |   `-- for
    `-- time

親ディレクトリは、そのサブディレクトリすべての parent table の役割を果たしています。 これは、異なる Emacs メジャーモードがスニペットの定義を共有するための方法のひとつです。 上の例にあるように、c-modejava-mode は同じ親 cc-mode を共有しており、cc-mode 向けに定義されている while スニペットを共有しています。 また、すべてのモードは text-mode に由来する time スニペットを共有しています。

この仕組みは alias (別名)としても使えます。上の例で、cperl-modeperl-mode を親とする空のディレクトリです。

.yas-parents ファイル

a menu sample about a parent table

parent table を設定するもうひとつの(より好ましい)方法は、サブディレクトリのひとつに .yas-parents という名前のプレインテキストファイルを置くことです。 こうすると、ディレクトリがネストして複雑になってしまうのを避けることができます。 .yas-parents ファイルの中には、モード名を空白で区切って書くだけです。 このしくみは、スニペットの階層を柔軟に、読みやすくしてくれます。

$ tree
.
|-- c-mode
|   |-- .yas-parents    # contains "cc-mode text-mode"
|   `-- printf
|-- cc-mode
|   |-- for
|   `-- while
|-- java-mode
|   |-- .yas-parents    # contains "cc-mode text-mode"
|   `-- println
`-- text-mode
    |-- email
    `-- time

.yas-make-groups ファイル

a menu sample about grouping snippets

各モードのディレクトリのひとつに .yas-make-groups という名前の空のプレインテキストファイル(訳注:矛盾してますね・・・【空の Excel ファイルというものが存在すると考えると、矛盾しない気もします。 2010/12/24 IKKI】)を置くと、 これらのサブディレクトリは「スニペットのグループ」とみなされます。 これにより、The YASnippet Menu をとてもわかりやすく整理することができます(右の画像のように)。

同じことをするためのもうひとつの方法は、# group: ディレクティブをスニペット定義の中に書くことです。 Writing Snippets の章を参照してください。

$ tree ruby-mode/
ruby-mode/
|-- .yas-make-groups
|-- collections
|   |-- each
|   `-- ...
|-- control structure
|   |-- forin
|   `-- ...
|-- definitions
|   `-- ...
`-- general
    `-- ...

ファイル名をそのまま使う

通常、ファイル名はスニペット展開の省略形として使われます。(「省略形」は "snippet key" または "snippet trigger" とも呼ばれます ‥‥ Expanding Snippets の章を参照)

また一方で、変数 yas/ignore-filenames-as-triggers を non-nil に設定するか、または.yas-ignore-filename-triggers という名前の空のファイルを置くか、どちらかをすると、 ずっと説明的なファイル名を使えるようになります。 ひとつのモードに対するたくさんのスニペットが同じ trigger key を共有しているような場合にこの仕組みは役に立ちます。

$ tree rails-mode/
rails-mode/
|-- .yas-make-groups
|-- .yas-ignore-filename-triggers
|-- Insert ERb's <% __ %> or <%= __ %>.yasnippet
|-- asserts
|   |-- assert(var = assigns(%3Avar)).yasnippet
|   |-- assert_difference.yasnippet
|   |-- assert_no_difference.yasnippet
|   |-- assert_redirected_to (nested path plural).yasnippet
|   |-- assert_redirected_to (nested path).yasnippet
|   |-- assert_redirected_to (path plural).yasnippet
|   |-- assert_redirected_to (path).yasnippet
|   |-- assert_rjs.yasnippet
|   `-- assert_select.yasnippet

スニペットのバンドル

YASnippet 向けのスニペットを定義するもっとも便利な方法は、そのスニペットを使いたいモードに基づいてディレクトリ階層中にスニペット定義を置いて、 yas/load-directory でそれらを読み込むことです。

しかし、たくさんのスニペットがある場合、この方法だと Emacs の起動スピードが遅くなるかもしれません。 ひとつの Emacs-lisp ファイルの中で特定のモードに対するスニペットをたくさん定義するためには、yas/define-snippets を使うことができます。

このやり方はメンテナンスが大変なので、もっといい方法があります。 ディレクトリ階層の中でスニペットを定義しておいて、 そのスニペットを変更したら M-x yas/compile-bundle を呼んでスニペット定義をバンドルファイルにコンパイルする、というやり方です。

リリースされているバンドルファイルは、yas/compile-bundle によって生成されています。 これらのバンドルは、スニペットを定義するために yas/define-snippets を使っています。 これにより、スニペットを読み込む際の I/O および構文解析のオーバヘッドを回避することができます。

もっと言ってしまうと、生成されたバンドルファイルは独立したファイルであり、yasnippet.el に依存していません。 リリースされているバンドルファイルは、すべてこのやり方で生成されています。

これらの機能に関する内部ドキュメントとしては以下をご覧ください:

カスタム可能な変数

yas/root-directory

各メジャーモードに対するスニペットを格納しているルートディレクトリ。

この変数を .emacs で定義する場合、複数のルートディレクトリを指定するために、文字列のリストとすることもできます。 リストにした場合、その最初の要素は常にユーザ作成スニペット用のディレクトリとなります。 それ以外の要素は、yas/reload-all での全スニペットの再読み込みの対象となります。

yas/ignore-filenames-as-triggers

nil で無い場合、ファイル名から trigger key を生成しません。

このことは、# key: ディレクティブの書かれていないスニペットは trigger key を持たない、ということを意味します。