原文: http://yasnippet.googlecode.com/svn/trunk/doc/snippet-expansion.html (translated on 2010/Dec/21) ⇒ editor's room
〔重要〕 このドキュメントは YASnippet の SVN trunk に対して適用されるものです。 SVN trunk はこちらから取得できます。 他のバージョンに対するドキュメントはこちらで見られます。
YASnippet でスニペットを展開するのには、さまざまなやり方があります:
省略形(スニペットの trigger key)をタイプし、yas/trigger-key
に定義されているキーを押す(デフォルトでは TAB キー)。
この手順はマイナーモード yas/minor-mode
が有効なバッファで利用できます。
コマンド yas/insert-snippet
を実行する(M-x yas/insert-snippet
とタイプするか、キーバインドを使う)。
この手順は yas/minor-mode
が有効であることを必要としません。
有効なスニペットに割り当てられているキーバインドを使う。
この手順もまた yas/minor-mode
が有効でなければなりません。
メニューバーにある "YASnippet" メニューから直接展開する。
hippie-expand を使う。
emacs-lisp コードから展開する。
yas/minor-mode
が有効になると、yas/trigger-key
で与えられるキーバインドが有効になります。
yas/trigger-key
で指定されたキーバインドは、関数 yas/expand
を呼び出します。
これは、カーソル位置の直前にある スニペット省略形(あるいは snippet key とも呼ばれます)を展開しようとします。
デフォルトのキーは TAB ですが、自由に他のキーに設定することができます。
すべてのバッファで YASnippet マイナーモードを有効にするには、yas/global-mode
コマンドを使います。
yas/global-mode
を使っているが、あるバッファでは YASnippet を無効化したい、というときには、そのバッファのモードのフックでバッファローカル変数 yas/dont-active
を設定してください。
yas/trigger-key
の利用とその理解にまつわるトラブルは、YASnippet でもっとも頻繁に話題になっているものです。
FAQ を参照してください。
yas/fallback-behavior
は設定可能な変数で、デフォルトでは 'call-other-command
に割り当てられています。
展開すべきスニペットを yas/expand
が見つけられなかった場合、マイナーモードを一時的に無効にして、yas/trigger-key
に割り当てられている他のコマンドがないか探します。
もし他のコマンドが見つかった場合、その見つかったコマンドが呼ばれます。 たいていの場合、この仕組みはとてもうまく機能します。 スニペットがあったらそれを展開し、そうでなければ trigger key にもともと割り当てられていたコマンドを呼ぶ、というわけです。
また一方で、変数 yas/fallback-behavior
をカスタマイズすることで、この挙動を変えることができます。
この変数の値を 'return-nil
に設定すると、スニペットが見つからなかったときにもともとのコマンドを呼ぶ代わりに nil
を返すようになります。
コマンド M-x yas/insert-snippet
は、現在のメジャーモードにしたがって、スニペットをカーソル位置に挿入しようとします。
このコマンドを実行すると、最初に、snippet key (訳注:スニペット省略形)の入力をうながすプロンプトが表示されます。
同じ snippet key に対して複数のテンプレートがある場合、続けてスニペットテンプレートの選択をうながすプロンプトが表示されます。
ここで表示されるリストには、現在のカーソル位置に挿入可能なスニペットが載っています。
どのスニペットが挿入可能なのかは条件判断システム(後述)にしたがいます。
現在のメジャーモードに対して適用可能なすべてのスニペットを見たいときには、コマンドの前に C-u
を付けてください。
入力をうながすプロンプトを表示するメソッドは、これもまた、yas/prompt-functions
によって制御されています。
"Writing Snippets" の章の # binding:
ディレクティブの節を参照してください。
"the YASnippet Menu" の章を参照してください。
hippie-expand
での展開hippie-expand
と統合したい場合、リスト hippie-expand-try-functions-list
の中に yas/hippie-try-expand
を置くだけです。
ただし、リストの先頭に置いた場合、他の意味も持ってしまうかもしれません。
いずれにしても、あなたの好きな位置に置くことができます。
時には、Emacs-Lisp コードから直接、スニペットを展開したいことがあるかもしれません。
そんなときは yas/expand
の代わりに yas/expand-snippet
を呼ぶようにしてください。
メニューバーから展開するのと同様に、条件判断システムおよび複数候補は展開に影響しなくなります。 実際、YASnippet メニューからの展開は、以下のコードの評価とまったく同じ効果を持っています:
(yas/expand-snippet template)
もっと情報が必要な場合は yas/expand-snippet
の内部ドキュメントを参照してください。
現在のカーソル位置に展開できるスニペットはどれか、を見つけ出すために、YASnippet はかなりのフィルタリングをします。
具体的に言うと、以下のものが関係します:
あなたのファイルシステムのディレクトリ階層構造から読みだされる情報です。
"Organizing Snippets" の章を参照してください。
これらのテーブルは、"html-mode
" や "ruby-mode
" のように、メジャーモードにちなんだ名前を付けられています。
現在のメジャーモードが読み込み済みの snipet table のひとつにマッチした場合、
そのテーブルにあるすべてのスニペットが展開の対象となります。
現在のメジャーモードを確認するためには、M-x describe-variable RET major-mode RET
を使ってください。
展開可能な他のテーブルの親として定義されている snippet table もまた、展開可能とみなされます。 この解釈は再帰的に行われます。つまり、展開可能なテーブルの親の親もまた展開可能とみなされます。
yas/mode-symbol
この変数を使うと、メジャーモードに一致しない名前の snippet table を展開可能とみなすようにすることができます。
この変数に適当なモード名を設定すると(たとえば rinari-minor-mode
とか)、そのモードでしか展開されないスニペットを使うことができます。
もちろん、この設定を条件によって切り替えたいと思うこともあるでしょう(たとえば、あるマイナーモードに入った時にだけ、など)。
そんなときはフックを使うのがよいアイディアです。
;; When entering rinari-minor-mode, consider also the snippets in the
;; snippet table "rails-mode"
(add-hook 'rinari-minor-mode-hook
#'(lambda ()
(setq yas/mode-symbol 'rails-mode)))
yas/buffer-local-condition
この変数を使うと、現在のバッファ内でどのスニペットが展開可能かをより細かい粒度で制御することができます。 たとえば、デフォルトでは、コメントおよび文字列リテラルの中ではスニペットを展開しないようになっています。 詳細については "The condition system" の節を参照してください。
次のシナリオを考えてみてください:
あなたはベテランの Emacs ハッカーです。
あなたは省略表記を好んでいて、yas/trigger-key
に "SPC
" を設定しています。
また一方では、(たとえば python-mode
などで)コメントブロックや文字列の中でタイプした "if
" はスニペットとして展開してほしくありません。
# condition :
ディレクティブ("Writing Snippets" の章を参照)を使っている場合、
if
に対する条件として (not (python-in-string/comment))
を指定するだけで済みます。
しかし、while
や for
などについてはどうでしょう?
すべてのスニペットに対して同じ条件を書くのは本当にうんざりするものです。
そんなわけで、YASnippet はバッファローカル変数 yas/buffer-local-condition
を提供しています。
python-mode-hook
の中で、この変数に (not (python-in-string/comment))
を設定すればよいのです。
次に、ある特定のスニペットだけはコメントの中でも展開できるようにしたいと思ったら、どうしたらよいでしょう? これも実現可能です! でも、話を進めるのを止めて、以下のルールをご覧ください:
もし、yas/buffer-local-condition
を評価して nil になるなら、どのスニペットも展開可能とはみなされません。
もし、評価した結果がコンスセルで、そのコンスセルの car
部がシンボル require-snippet-condition
で、
そのコンスセルの cdr
部がひとつのシンボル(これを requirement
と呼ぶことにしましょう)である場合、
# condition:
ディレクティブを持たないスニペットは、適用可能とはみなされません。
# condition:
ディレクティブの評価結果が nil だった(または評価中にエラーが起きた)スニペットは、展開可能とはみなされません。
スニペットが # condition:
ディレクティブを持っていて、それを評価した値が nil 以外だった場合(その値を result
と呼ぶことにしましょう):
もし requirement
が t
なら、そのスニペットは展開可能である。
もし requirement
が result
と eq
なら(等しいなら)、そのスニペットは展開可能である。
それ以外の場合、そのスニペットは展開可能とはみなされません。
もし、評価した結果がシンボル always
だった場合、# condition:
ディレクティブに関係なく、すべてのスニペットは展開可能とみなされます。
もし、評価した結果が t
または他の non-nil な値だった場合:
もしスニペットが # condition:
ディレクティブを持っていないか、# condition:
ディレクティブを評価すると non-nil だった場合、
そのスニペットは展開可能である。
それ以外の場合、そのスニペットは展開可能とはみなされません。
上で想定しているシナリオでは、yas/buffer-local-condition
を以下のように設定してください:
(add-hook 'python-mode-hook
'(lambda ()
(setq yas/buffer-local-condition
'(if (python-in-string/comment)
'(require-snippet-condition . force-in-comment)
t))))
・・・・また、コメントの中でも展開されてほしいスニペットの # condition:
ディレクティブは、シンボル force-in-comment
に評価されるようにしてください。
こうすると、コメント中では、if
のような他のスニペットは展開されないままで、あなたが展開したいスニペットだけは展開できるようになります。
上のほうで概要を述べたルールは、現在のカーソル位置に展開可能なスニペットを複数返すことがありえます。
複数の候補が見つかったとき、YASnippet はあなたにひとつ選ばせるでしょう。
複数の候補を選択するためのユーザインタフェースは、yas/prompt-functions
でカスタマイズすることができます。
この変数は、スニペットに対する入力プロンプトを表示するメソッドとして、あなたの好きなメソッドを指定するためのものです。
これをカスタマイズするには、M-x customize-variable RET yas/prompt-functions RET
としてください。
別のやり方として、あなたの emacs 設定ファイルに以下のコードを書いてください:
(setq yas/prompt-functions '(yas/x-prompt yas/dropdown-prompt))
現在、YASnippet では、以下のいずれかの方法が利用可能です。
関数 yas/x-prompt
は、候補選択のためのポップアップメニューを表示します。
このメニューはあなたの使っているウインドウシステムのネイティブな部品 (widget) です。
すなわち:
見た目がきれいです。たとえば、gtk をサポートするように Emacs をコンパイルしたなら、このメニューは gtk のテーマにしたがって描画されるでしょう。
このメニューでは Emacs による制御はほとんどできません。たとえば、C-n
や C-p
では操作できません。
この関数はターミナル上では使えません。
昔ながらの emacs の補完メソッドのための関数 yas/completing-prompt
が使えます。
または、これよりずっと見た目のよい yas/ido-prompt
も使えます。
一番いいのは実際に試してみることです。
この機能はターミナル上でも使えます。
dropdown-menu.el
を使う関数 yas/dropdown-prompt
も yas/prompt-functions
リストに書くことができます。
これはウインドウシステム上でもターミナル上でも機能し、カスタマイズ可能で、C-n
や C-p
で操作でき、
q
で quit でき、6番目の候補を選択するのに 6
を押すこともできます。
変数 yas/prompt-functions
のドキュメントを参照してください。
yas/prompt-functions
関数を書いて、それをリスト yas/prompt-functions
に追加することができます。
このリストに含まれている関数は、以下の引数で呼ばれます:
リスト yas/prompt-functions
に含めるすべての関数の返値は、CHOICES に含まれているオブジェクトのどれかでなければなりません。
また、(DISPLAY-FN 引数が渡されたときには)DISPLAY-FN で適切に整形されたものでなければなりません。
入力プロンプトのある特定のスタイルが一時的に使えないとき、その旨を伝えるために「nil を返す関数」を使うことができます。
ユーザが入力プロンプトをキャンセルした場合、(signal 'quit "user quit!")
とすることで quit
シグナルを伝えることができます。
yas/fallback-behavior
yas/expand
がスニペットを展開しなかったとき、どう振る舞えばよいか。
call-other-command
は、一時的に YASnippet を無効にして、yas/trigger-key
に割り当てられている次のコマンドを呼び出すことを意味します。
return-nil
は nil を返す(つまり、何もしない)ことを意味します。
(apply COMMAND .ARGS)
という形式のエントリは、
もし ARGS が non-nil だった場合は ARGS を引数として非対話的に COMMAND を呼び出し、
そうでなければ対話的に COMMAND を呼び出すことを意味します。
yas/choose-keys-first
もし non-nil だった場合、最初に snippet key の入力プロンプトを表示し、次にテンプレートに対するプロンプトを表示します。
そうでなければ、すべての展開可能なスニペット名に対するプロンプトを表示します。
この変数は、yas/insert-snippet
と yas/visit-snippet-file
に影響を与えます。
yas/choose-tables-first
もし non-nil だった場合で、かつ、複数の snippet table が適用可能と判定された場合、snippet table を選択するプロンプトを最初に表示します。
それ以外の場合、すべての適用可能な snippet table を合体したものからユーザがスニペットを選択することになります。
この変数は、yas/insert-snippet
と yas/visit-snippet-file
に影響を与えます。
yas/key-syntaxes
デフォルトの検索の戦略は、きわめて強力です。
たとえば、c-mode
において、bar
と foo_bar
と "#foo_bar"
は、いずれも snippet key として認識されます。
さらに、検索はこの順序で行われます。
つまり、bar
がある展開可能なスニペットへの key であることがわかったとき、そのスニペットが展開されて bar
を置き換えます。
このとき、foo_bar
や "#foo_bar"
を key とするスニペットは、展開可能とはみなされません。
一方で、この戦略は、yas/key-syntaxes
変数によって容易にカスタマイズできます。
設定するのは、構文ルールのリストです。
そのデフォルトの値は ("w" "w_" "w_." "^ ")
です。
これは、以下のものを snippet key が見つかるまで検索する、ということを意味します:
-
" および "?
" はいずれもシンボルの一部となりえます)ただし、Emacs の構文ルールがどのように機能しているのか理解したいと思わないなら、デフォルトの値のままにしておくのがベターでしょう・・・・。