Embedded anonymous triggers

Asked by Júlio Hoffimann Mendes

I'm trying to launch anonymous triggers according to some keywords. Specifically, i'm trying to insert license headers with the appropriate comment symbol. This is the code:

global !p
gplv3 = \
r"""Copyright (c) ${3:`date +%Y`} ${2:COMPANY}

This file is part of ${1:SOMElib}.

$1 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

$1 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with $1. If not, see <http://www.gnu.org/licenses/>.

Created: `date +'%d %b %Y'`
Author: Júlio Hoffimann
"""
endglobal

snippet "lic (\w+)" "Licence header (generic)" br
`!p

license = {
'gpl' : gplv3
}[match.group(1)]

trigger_output = vim.eval("UltiSnips_Anon(\""+license+"\")")`
# TODO: filter trigger_output to insert the comment symbol
snip.rv = trigger_output
endsnippet

When i type `lic gpl` and press <TAB> the trigger is correctly launched, but the tabstops are missed. Do you have a better approach for what i'm trying to achieve? Is it possible to explicitly launch a trigger from within another? Any way to accomplish primitive piping?

Thanks, this plugin is amazing.

Question information

Language:
English Edit question
Status:
Solved
For:
UltiSnips Edit question
Assignee:
No assignee Edit question
Solved by:
Júlio Hoffimann Mendes
Solved:
Last query:
Last reply:
Revision history for this message
SirVer (sirver) said :
#1

No, sorry. There's currently no way to dynamically add new tabstops (or any text object) to a snippet. Two approaches were discussed however: either giving a possibility to call a function which returns a string which is then parsed and launched as snippet (that should work for your use case) OR giving a way to dynamically add new text that is parsed and inserted into the current snipper at one place from inside a python snippet. This seems significantly more flexible but harder to implement as well.

No work has been started on any implementation. Patches are welcome :-)

Revision history for this message
Júlio Hoffimann Mendes (julio-hoffimann) said :
#2

If i understood correctly, we only lack the ability to create and launch snippets on the fly. This feature would take UltiSnips to another level (and solve my use case). Although we can do that with anonymous triggers as i showed, it has immediate evaluation (vim.eval()) which isn't always desired.

In my mind, this would be accomplished by allowing the user to instantiate multiple `snip' objects and operate on them doing copies of states or any other needed transformation (composition, concatenation, etc.).

What are the first places i have to look at to produce some patches? I don't know if'll be able to help in the short time though, no previous experience with Vim plugin development.

Revision history for this message
SirVer (sirver) said :
#3

I would suggest starting out by defining the syntax how the user is exposed to the new features you plan to add. So, think about a few snippets that would benefit from this and write them using a syntax that feels natural to you. I am currently considering the following scenarios , some of which can maybe be folded into each other.

1) launching a snippet that is autogenerated from context/from a string (your use case). This could be generalized in conceptually separating ultisnips into a launcher part (that acts on triggers, but can launch arbitrary commands. Similar to imap, but without delays and the full power of ultisnips trigger system) and a snippet engine that only compiles and inserts snippets.

2) Do arbitrary transformation on an existing snippet. For example, I could imagine "installing" a function that gets the chance to add in new snippets. so if i create the snippet blah, it would for example generate BLAH automatically. Or if I generate "class" it would generate the short forms "c","cl","cla","clas" for convenience as well.

3) Add new tabstops from within snippets. For the moment I would only consider python blocks. It would be useful to have something like this:

snip blah
hello `!p
new_tabstop = Tabstop("default_text") # note that our current internal representation in _tabstop.py needs a lot of params to really work.
mirror = Mirror(new_tabstop)
cool_transformation = lambda t: t.upper()
snip.rv = "ts: " + new_tabstop + ", mirror: " + mirror + ", trans: " + trans` world
endsnippet

it should work as follows
blah<tab>text -> hello ts: text, mirror: text, trans: TEXT

Note that I do not wish to fiddle with parsing inside the codeblock.

About the implementation:
Currently, the text between snippet and endsnippet is saved as is. In Snippet.launch(), the text is prepended with the correct amount of whitespace in each line. This data is given to SnippetInstance() where it is Parsed and therefore converted into valid text objects.

Revision history for this message
Júlio Hoffimann Mendes (julio-hoffimann) said :
#4

I think the first scenario is the way to go. When i have time, i'll check the source to see if i can contribute with something. Thanks again.