yasnippet: como expandir um trecho de uma string e ter os campos reconhecidos?

7

P: como faço yasnippetpara expandir corretamente uma sequência de texto (reconhecendo campos de trecho) do código elisp?

Um snippet muito simples é apenas uma sequência de caracteres com alguns caracteres de controle entrelaçados. Também podemos usar formulários elisp para criar trechos mais ricos, mas não está claro para mim como expandi-los adequadamente.

Aqui está um exemplo simples que captura o problema. Estou criando um org-modesnippet para inserir um esqueleto de link, que parece [[source][description]]. O seguinte snippet simples produz o comportamento desejado de "iniciar no campo de origem e terminar no campo de descrição":

[[$1][$0]]

Podemos misturar o código elisp em trechos (envoltos em `s). Eu teria pensado que o seguinte produziria exatamente o mesmo comportamento da versão mais simples, porque o ifserá simplesmente avaliado [[$1][$0]]como uma string:

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

No entanto, não o faz. Em vez disso, ele age como se os campos $0e $1não fossem campos, finalize o trecho e os pontos aponte após o final ]. Então: como obter o comportamento desejado quando um formulário elisp é avaliado como uma sequência de texto com yasnippetcampos incorporados nessa sequência?

EDIT: conforme solicitado, aqui está o caso de uso específico que inspirou a pergunta. Se a área de transferência do X contiver um link de URL, eu gostaria que ela preenchesse o campo de origem no link organizacional ([[ fonte ] [descrição]]]) e me deixe no campo de destino. Ele usa uma função auxiliar ( dan-xclipboard-link-p) que retorna o URL, se existir, ou então nil. Parece-me que eu deveria ser capaz de fazer algo assim:

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

De fato, com uma versão anterior do yasnippet, uma versão desse código funcionava como eu pretendia.

EDIT 2: Curiosamente, esse trecho funciona quando há um link na área de transferência do X, mas falha quando não (ou seja, ele não reconhece $1como um campo:

[[`(or (dan-xclipboard-link-p) "$1")`][$0]]
Dan
fonte
Que tal (if t (yas-insert-snippet))? Você pode dar uma condicional mais realista para que possamos entender o caso de uso real? Este pode ser um problema XY com soluções mais elegantes.
Vamsi
Não estou vendo como isso yas-insert-snippetse aplica aqui. De qualquer forma, um caso de uso real (que costumava funcionar) está agora em questão.
Dan
@ Dan Não funciona porque o formulário elisp é avaliado quando o está sendo expandido , momento em que o yasnippet já leu o trecho. Eu acho que o que você quer fazer é templatize o próprio modelo, não tenho certeza de que é possível com yasnippet neste ponto do tempo
Iqbal Ansari
@IqbalAnsari Eu tenho uma maneira grosseira de modelar os trechos eles mesmos. Veja minha solução mais longa. Obrigado.
Vamsi

Respostas:

11

SOLUÇÃO CURTA

Se você não se importar com um TABpressionamento de tecla adicional , definir seu snippet como abaixo deve funcionar.

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

O lisp incorporado retorna o URL da área de transferência, se existir, e o define como o texto padrão no campo $1. Você pode digitar no link para alterá-lo ou apenas TAB (yas-next-field)para mover o ponto para $0.

SOLUÇÃO EM DESTAQUE MAIS COMPLETA

Tive a ideia com base no comentário de @ IqbalAnsari depois de escrever a solução mais curta. Você pode usar o predicado de condição para escolher qual snippet expandir. Por exemplo, defina dois trechos com o mesmo gatilho

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

Ambos os trechos têm o mesmo gatilho, mas têm predicados invertidos denotados pelo condition:. Como tal, apenas um dos trechos será expandido, dependendo do valor retornado por (dan-xclipboard-link-p). Dessa forma, você pode posicionar o ponto $0diretamente.

Para responder à pergunta geral, não, não é possível que o yasnippet reconheça campos no elisp, pois analisa blocos elisp incorporados separadamente, sem qualquer preocupação com a sintaxe normal do modelo. Não tenho certeza de como as versões anteriores funcionaram.

Vamsi
fonte
Ótimo, eu estava pensando em algo na mesma linha. Embora eu tivesse preferido a "guia" extra em vez de escrever dois trechos. 1
Iqbal Ansari
Obrigado pelos pensamentos. A propósito, eu sugeria algo semelhante à solução curta e corrigia um erro de digitação com os colchetes para referência futura. Os trechos condicionais são um toque agradável.
Dan