yasnippet: Wie kann man ein Snippet aus einer Zeichenfolge erweitern und die Felder erkennen lassen?

7

F: Wie kann ich yasnippeteine Textzeichenfolge innerhalb des Elisp-Codes korrekt erweitern (Snippet-Felder erkennen)?

Ein sehr einfaches Snippet ist nur eine Zeichenfolge, in der sich einige Steuerzeichen vermischen. Wir können auch Elisp-Formulare verwenden, um umfangreichere Snippets zu erstellen, aber mir ist nicht klar, wie ich sie angemessen erweitern kann.

Hier ist ein einfaches Beispiel, das das Problem erfasst. Ich erstelle ein org-modeSnippet, um ein Link-Skelett einzufügen, das aussieht [[source][description]]. Das folgende einfache Snippet erzeugt das gewünschte Verhalten von "Start im Quellfeld, Ende im Beschreibungsfeld":

[[$1][$0]]

Wir können Elisp-Code in Snippets (in `s eingeschlossen) mischen. Ich hätte gedacht, dass das Folgende genau das gleiche Verhalten wie die einfachere Version erzeugen würde, da das ifeinfach [[$1][$0]]als String ausgewertet wird :

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

Dies ist jedoch nicht der Fall. Stattdessen verhält es sich so, als wären die Felder $0und $1keine Felder, beendet das Snippet und platziert einen Punkt nach dem Finale ]. Also: Wie erhält man das gewünschte Verhalten, wenn ein elisp-Formular zu einer Textzeichenfolge mit yasnippetin diese Zeichenfolge eingebetteten Feldern ausgewertet wird ?

BEARBEITEN: Wie gewünscht, hier ist der spezielle Anwendungsfall, der die Frage inspiriert hat. Wenn die X-Zwischenablage einen URL-Link enthält, möchte ich, dass das Quellfeld im Organisationslink ([[ Quelle ] [Beschreibung]] ausgefüllt und im Zielfeld belassen wird. Es verwendet eine Hilfsfunktion ( dan-xclipboard-link-p), die die URL zurückgibt, falls vorhanden, oder sonst nil. Es scheint mir, dass ich in der Lage sein sollte, so etwas zu tun:

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

Tatsächlich funktionierte mit einer früheren Version von yasnippet eine Version dieses Codes so, wie ich es beabsichtigt hatte.

EDIT 2: Interessanterweise funktioniert dieses Snippet, wenn sich ein Link in der X-Zwischenablage befindet, schlägt jedoch fehl, wenn dies nicht der Fall ist (dh es wird nicht $1als Feld erkannt :

[[`(or (dan-xclipboard-link-p) "$1")`][$0]]
Dan
quelle
Wie wäre es (if t (yas-insert-snippet))? Können Sie eine realistischere Bedingung angeben, damit wir den tatsächlichen Anwendungsfall verstehen können? Dies könnte ein XY-Problem mit eleganteren Lösungen sein.
Vamsi
Ich sehe nicht, wie yas-insert-snippetdas hier zutrifft. Auf jeden Fall kommt jetzt ein tatsächlicher Anwendungsfall (der früher funktioniert hat) in Frage.
Dan
@ Dan es nicht funktioniert , weil die elisp Form ausgewertet wird , wenn das wird erweitert , an welchem Punkt yasnippet bereits das Snippet gelesen hat. Ich denke, was Sie tun möchten, ist die Vorlage selbst zu templatisieren, nicht sicher, ob dies mit yasnippet zu diesem Zeitpunkt möglich ist
Iqbal Ansari
@IqbalAnsari Ich habe eine grobe Art, die Schnipsel selbst zu templatisieren. Siehe meine längere Lösung. Vielen Dank.
Vamsi

Antworten:

11

KURZE LÖSUNG

Wenn Ihnen ein zusätzlicher TABTastendruck nichts ausmacht , sollte die Definition Ihres Snippets wie folgt funktionieren.

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

Das eingebettete Lisp gibt die URL aus der Zwischenablage zurück, falls vorhanden, und legt sie als Standardtext im Feld fest $1. Sie können über den Link tippen, um ihn zu ändern oder nur TAB (yas-next-field)um einen Punkt zu verschieben $0.

LÄNGERE VOLLSTÄNDIGE LÖSUNG

Ich kam auf die Idee, die auf dem Kommentar von @ IqbalAnsari basiert, nachdem ich die kürzere Lösung geschrieben hatte. Sie können das Bedingungsprädikat verwenden, um auszuwählen, welches Snippet erweitert werden soll. Definieren Sie beispielsweise zwei Snippets mit demselben Trigger

SNIPPET 1

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

SNIPPET 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]]

Beide Snippets haben den gleichen Trigger, aber invertierte Prädikate, die mit dem gekennzeichnet sind condition:. Daher wird nur eines der Snippets in Abhängigkeit von dem von zurückgegebenen Wert erweitert (dan-xclipboard-link-p). Auf diese Weise können Sie den Punkt $0direkt positionieren .

Um die allgemeine Frage zu beantworten: Nein, es ist yasnippet nicht möglich, Felder innerhalb von elisp zu erkennen, da eingebettete elisp-Blöcke separat analysiert werden, ohne dass die normale Vorlagensyntax berücksichtigt wird. Ich bin mir jedoch nicht sicher, wie die vorherigen Versionen funktioniert haben.

Vamsi
quelle
Großartig, ich dachte an etwas in die gleiche Richtung. Obwohl ich den zusätzlichen "Tab" dem Schreiben von zwei Schnipsel vorgezogen hätte. +1
Iqbal Ansari
Danke für die Gedanken. Übrigens, ich hatte mir etwas Ähnliches wie die kurze Lösung ausgedacht und einen Tippfehler mit den Klammern behoben, damit ich später darauf zurückgreifen kann. Die bedingten Schnipsel sind eine nette Geste.
Dan