P: ¿cómo puedo yasnippet
expandir una cadena de texto correctamente (reconociendo los campos de fragmentos) desde el código elisp?
Un fragmento muy simple es solo una cadena de caracteres con algunos caracteres de control entremezclados. También podemos usar formularios elisp para crear fragmentos más ricos, pero no tengo claro cómo expandirlos adecuadamente.
Aquí hay un ejemplo simple que captura el problema. Estoy creando un org-mode
fragmento para insertar un esqueleto de enlace, que se ve así [[source][description]]
. El siguiente fragmento simple produce el comportamiento deseado de "comenzar en el campo de origen, terminar en el campo de descripción":
[[$1][$0]]
Podemos mezclar el código elisp en fragmentos (envueltos en `s). Pensé que lo siguiente produciría exactamente el mismo comportamiento que la versión más simple, porque if
simplemente se evaluará [[$1][$0]]
como una cadena:
`(if t "[[$1][$0]]")`
Sin embargo, no lo hace. En cambio, actúa como si los campos $0
y $1
no fueran campos, finaliza el fragmento y coloca el punto después de la final ]
. Entonces: ¿cómo se obtiene el comportamiento deseado cuando un formulario elisp se evalúa como una cadena de texto con yasnippet
campos incrustados en esa cadena?
EDITAR: según lo solicitado, aquí está el caso de uso particular que inspiró la pregunta. Si el portapapeles X contiene un enlace de URL, me gustaría que llene el campo de origen en el enlace de la organización ([[ fuente ] [descripción]]) y me deje en el campo de destino. Utiliza una función auxiliar ( dan-xclipboard-link-p
) que devuelve la url si existe, o si no nil
. Me parece que debería poder hacer algo como esto:
`(let ((link (dan-xclipboard-link-p)))
(if link
(concat "[[" link "][$0]]")
"[[$1][$0]]"))`
De hecho, con una versión anterior de yasnippet, una versión de este código funcionó como lo pretendía.
EDITAR 2: Curiosamente, este fragmento funciona cuando hay un enlace en el portapapeles X, pero falla cuando no (es decir, no se reconoce $1
como un campo:
[[`(or (dan-xclipboard-link-p) "$1")`][$0]]
(if t (yas-insert-snippet))
? ¿Puedes dar un condicional más realista para que podamos entender el caso de uso real? Esto podría ser un problema XY con soluciones más elegantes.yas-insert-snippet
aplica aquí. En cualquier caso, un caso de uso real (que solía funcionar) ahora está en la pregunta.Respuestas:
SOLUCIÓN CORTA
Si no le importa una
TAB
pulsación de tecla adicional , debería definir su fragmento como se muestra a continuación.El lisp incrustado devuelve la url del portapapeles si existe y lo establece como el texto predeterminado en el campo
$1
. Puede escribir sobre el enlace para cambiarlo o simplementeTAB (yas-next-field)
para mover el punto$0
.SOLUCIÓN DESTACADA COMPLETA MÁS LARGA
Tengo la idea basada en el comentario de @ IqbalAnsari después de escribir la solución más corta. Puede usar el predicado de condición para elegir qué fragmento expandir. Por ejemplo, defina dos fragmentos con el mismo activador
SNIPPET 1
SNIPPET 2
Ambos fragmentos tienen el mismo desencadenador, pero tienen predicados invertidos denotados por
condition:
. Como tal, solo uno de los fragmentos se expandirá según el valor devuelto por(dan-xclipboard-link-p)
. De esta manera puede posicionar el punto$0
directamente.Para responder a la pregunta general, no, no es posible que yasnippet reconozca los campos dentro de elisp, ya que analiza los bloques de elisp incrustados por separado sin preocuparse por la sintaxis de plantilla normal. Sin embargo, no estoy seguro de cómo funcionaban las versiones anteriores.
fuente