yasnippet:文字列からスニペットを展開し、フィールドを認識させる方法は?


7

Q:yasnippet elispコード内から(スニペットフィールドを認識して)テキスト文字列を正しく展開するにはどうすればよいですか?

非常に単純なスニペットは、いくつかの制御文字が混在した単なる文字列です。elispフォームを使用してよりリッチなスニペットを作成することもできますが、それらを適切に展開する方法がわかりません。

これは問題を捉えた簡単な例です。のorg-modeようなリンクスケルトンを挿入するスニペットを作成しています[[source][description]]。次の簡単なスニペットは、「ソースフィールドで開始し、説明フィールドで終了する」という望ましい動作を生成します。

[[$1][$0]]

elispコードをスニペット( `sでラップ)に混在させることができます。ifは単に[[$1][$0]]文字列として評価されるため、次のコードは単純なバージョンとまったく同じ動作を生成すると考えていました。

`(if t "[[$1][$0]]")`

ただし、そうはしません。代わりに、$0and $1フィールドがフィールドではないかのように機能し、スニペットを終了し、最後のの後にポイントを配置し]ます。それで、elispフォームがyasnippetフィールドに埋め込まれたテキスト文字列に評価されるときに、どのようにして望ましい動作を得るのでしょうか?

編集:要求されたとおり、ここに質問を引き起こした特定のユースケースがあります。XクリップボードにURLリンクが含まれている場合は、組織リンクのソースフィールド([[ source ] [description]])を入力し、リンク先フィールドをそのままにしておきます。dan-xclipboard-link-p存在する場合はURLを返すヘルパー関数()を使用しますnil。私には次のようなことができるはずです:

`(let ((link (dan-xclipboard-link-p)))
   (if link
       (concat "[[" link "][$0]]")
     "[[$1][$0]]"))`

実際、以前のバージョンのyasnippetでは、このコードのバージョンは意図したとおりに機能しました。

編集2:興味深いことに、このスニペットは、Xクリップボードにリンクがある場合は機能しますが、ない場合は失敗します(つまり、$1フィールドとして認識されません)。

[[`(or (dan-xclipboard-link-p) "$1")`][$0]]

いかが(if t (yas-insert-snippet))ですか?実際のユースケースを理解できるように、より現実的な条件を与えることができますか?これは、より洗練されたソリューションでのXY問題である可能性があります。
Vamsi

yas-insert-snippetここでどのように適用されるかはわかりません。とにかく、実際に使用されていたケース(以前は機能していたもの)が問題になっています。
ダン

@Dan 展開時にelispフォームが評価されるため、機能しません。この時点で、yasnippetはすでにスニペットを読み取っています。あなたがしたいことはテンプレート自体をテンプレート化することだと思いますが、現時点でyasnippetでそれが可能かどうかはわかりません
Iqbal Ansari

@IqbalAnsariスニペット自体をテンプレート化する、ある種の粗雑な方法があります。私の長い解決策を参照してください。ありがとう。
Vamsi 2014年

回答:


11

短い解決策

追加のTABキーストロークを気にしない場合は、以下のようにスニペットを定義すると機能します。

 [[${1:`(dan-xclipboard-link-p)`}][$0]]

埋め込みlispは、存在する場合はクリップボードからURLを返し、それをフィールドのデフォルトテキストに設定します$1。リンクを上書きして変更することも、TAB (yas-next-field)ポイントをに移動することもでき$0ます。

より長く完全な機能を備えたソリューション

短い解決策を書いた後、@ IqbalAnsariのコメントに基づいてアイデアを得ました。展開するスニペットを選択するために条件述語を使用できます。たとえば、同じトリガーで2つのスニペットを定義します

スニペット1

  # -*- mode: snippet; require-final-newline: nil -*-
  # name: org-link
  # key: [[
  # binding: direct-keybinding
  # type: snippet
  # condition: (not (dan-xclipboard-link-p))
  # --
  [[$1][$0]]

スニペット2

  # -*- mode: snippet; require-final-newline: nil -*-
  # name: org-link-with-default-paste
  # key: [[
  # binding: direct-keybinding
  # type: snippet
  # condition: (dan-xclipboard-link-p)
  # --
  [[`(dan-xclipboard-link-p)`][$0]]

どちらのスニペットにも同じトリガーがありますが、で示される逆の述語がありcondition:ます。そのため、によって返される値に応じて、スニペットの1つだけが展開され(dan-xclipboard-link-p)ます。このようにして、ポイントを$0直接配置できます。

一般的な質問に答えるために、yasnippetがelisp内のフィールドを認識することはできません。通常のテンプレート構文に関係なく、埋め込まれたelispブロックを個別に解析するためです。以前のバージョンがどのように機能したかはわかりません。


素晴らしい、私は同じ線に沿って何かを考えていました。2つのスニペットを作成するよりも、追加の「タブ」を使用した方がいいでしょう。+1
イクバルアンサリ2014年

考えをありがとう。ちなみに、私は短い解決策に似たものを考え出し、将来の参照のために括弧でタイプミスを修正しました。条件付きスニペットはいい感じです。
ダン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.