Suggestion for a repeat snippet feature.
MirkoHernandez opened this issue · 8 comments
I'm currently using the following method to repeat snippets: a yas-after-exit-snippet-hook
that uses yas-lookup-snippet
to find the current snippet and expand it. To exit the snippet I use the prefix argument C-u . Maybe something like this could be implemented in yasnippet with better syntax (a #repeat field).
# -*- mode: snippet -*-
# name:parameters
# key: p
# type: command
# --
(yas-expand-snippet "$1 ,"
nil nil
'((yas-after-exit-snippet-hook
(lambda ()
(if (not current-prefix-arg)
(yas-expand-snippet (yas-lookup-snippet "parameters)
(search-backward-regexp ",")
(delete-char 1)
(fixup-whitespace))))))
Could you clarify what "better syntax" you're thinking of?
Just a repeat directive. Maybe a repeat hook (or just a function) could be implemented to run before yas-after-exit-snippet-hook
, repeating the snippet by name a number of times or indefinitely until the prefix argument is used.
# -*- mode: snippet -*-
# name:parameters
# key: p
# repeat: t (or a number)
# --
"$1, "
The left-over comma could be handled with the regular yas-after-exit-snippet-hook
.
The example is just a basic demonstration of the functionality, a more practical one would be a bunch of json fields. Other examples: css rules, html tags like list items, case statements. It is easier to just type without having to write and expand each snippet.
One could have a regular snippet and the repeatable version and use the more convenient one for each use case.
# -*- mode: snippet -*-
# name:json-fields
# key: jf
# repeat: t (or a number)
# --
"$1 ": $2,
That's not very satisfactory.
Yes I agree, but using yas-after-exit-snippet-hook
seems like the right thing to do (cleanup work after exiting the snippet), maybe there is another way I'm not familiar with.
Some alternatives: maybe a directive for yas-after-exit-snippet-hook
, or maybe a different hook that runs on a per snippet basis.
This suggests that instead of having the "repeat" be a property of the
template, maybe we should have a command to repeat a(ny) template.
This seems like a better solution than the initial proposal.
I looked for a "last snippet" variable in the yanippet code and could not find it. I think a possible implementation would be just adding it.
(defvar yas-last-snippet nil)
(make-variable-buffer-local 'yas-last-snippet)
(defun yas-expand-snippet (snippet &optional start end expand-env)
;;; omited code
(let ((content (if (yas--template-p snippet)
(yas--template-content snippet)
snippet)))
(setq yas-last-snippet snippet)
)
(defun my/expand-last-snippet ()
(interactive)
(yas-expand-snippet yas-last-snippet))
[ You can use
defvar-local
instead. ]
Thanks I was not aware of this.
But for the user that requires hitting a key for each repetition,
whereas your current approach requires hitting a key only for the
last repetition.
I don't think that this would be a problem for most snippets. It is probably a bit annoying for simple snippets with one or two fields but would otherwise work fine.
How do you start your repeated template?
In my approach I just use tab (or whatever yas-next-field is), using tab in the last field repeats the snippet.
The problem is how to stop repeating the snippet, I use the prefix argument C-u which is kind of cumbersome, I tried yas-abort-snippet
but it does not work, I believe it uses the exit hook.
Maybe we can provide a new command
yas-expand-repeatedly
?
Great!, I think this probably the best solution, and it would allow snippets already created to be repeatable.
I still think the previous expand-last command is useful for a different use case.