0

I'd like to create an Ultisnip regex trigger that triggers with multi-line. I'm trying the following:

snippet 'hee\nhaa' "multi-line trigger" r
my awesome result$0
endsnippet

but when in my vim I write :

hee
haa<TAB>

It doesn't work. I tried with \r instead of \n, doesn't work neither. Is it possible to do that ?

tried \r expected a multi-line triggering functionnality

In fact, what I would like to do would be easier done by sed, I know. I have a ledger file (hledger.journal) with many entries. I'd like to update them all ; some are easy done because the syntax is always the same, but other may change because it was more complex entries. The "sed" command on the file would change some entries, other not (and I'm not sure I could use easily my "global python function" I wrote for some calculation on the entries I want to do.

And it would become hard to find entries that need to be update. Doing it with ultisnips is kind of a long way to do so, but I'll have an eye at each update to be sure everything went right.

Almost all lines in the ledger entry contains information that enters in the regex match.group() I have to get in order to update the entry, on with I had some !p snip.rv = calculate(match.group(x), match.group(y) ) etc... I'm not sure the pre_expand would allow me to get some match.group from the snip.line-1 or snip.line+2 ... and it seems to become heavy...

I really think Ultisnips with a multi-line regex trigger would be the best way to update my ledger file having a "total control" of it being done well, even if it would be an "endless" procedure.

here an actual (simple !) example of an entry of my actual ledger file

2023-07-16 tfuel reward
    equity:stak_reward:tfuel:2023-07-16  -12 tfuel
    asset:tfuel:Liq:2023-07-16  12 tfuel

there what i would like it to be :

2023-07-16  tfuel reward 
    income:stak_reward:tfuel:2023-07-16  -0.427 eur
    equity:opening_balance:stak_reward:2023-07-16  -0.427 eur
    asset:tfuel:Liq:2023-07-16  12 tfuel @ 0.03555137 eur
    equity:conv

and here is the snippet i tried to write to do that :

snippet '(\d{4}-\d{2}-\d{2}) tfuel reward\n.*equity.*\n.*tfuel' "migrate all tfuel reward" r                                            
${1:`!p snip.rv = match.group(1)`}  tfuel reward                                                                                        
        income:stak_reward:tfuel:$1  -${2:`!p snip.rv = calc_value(match.group(1), 'tfuel', 12)`} eur                                                                                                  
        equity:opening_balance:stak_reward  -$2 eur                                                                                     
        asset:tfuel:Liq:$1  12 tfuel @ `!p snip.rv = get_token_price_in_eur(match.group(1), 'tfuel')` eur
        equity:conv                                                                                                                     
endsnippet

other more complex entries are with variable asset with variable amount so only one "match.group()" isn't enough, and are on different lines of the trigger

Hope my question is "readable" and make sense... Thank you all !

franck
  • 13
  • 5

2 Answers2

0

I'm discovering Ultisnip thanks to you :-)

I had a look at the documentation and I didn't clearly find how the triggering word is compared to the text typed before the cursor. But I suppose it only compares it to the current line. And this would be why your regular expression doesn't match.

I also replaced \r or \n by (\r|\n|\r\n) in order to handle Linux, old Mac and Windows new lines. But this didn't solve the problem either.

Also did the same test with hee.*haa and hee[\s\S]*haa just to see how all that behaves, and it really seems to compare the regex with the current line only.

But if you read the documentation, you can activate the e option, which will let you add an expression that will act like a triggering condition:

snippet haa "multi-line trigger" "re.match('^hee$', snip.buffer[snip.line-1])" be
my awesome result$0
endsnippet

This will work, but unfortunately the "hee" line above will not be replaced by the snippet replacement text. I saw in the documentation that you can use pre_expand to modify the buffer:

pre_expand "del snip.buffer[snip.line-1]"
snippet haa "multi-line trigger" "re.match('^hee$', snip.buffer[snip.line-1])" be
my awesome result$0
endsnippet

I don't know if it's the right way to solve your problem, but it kind of works!

Patrick Janser
  • 3,318
  • 1
  • 16
  • 18
  • Hello Patrick, thank you very much for the answer and the way you found to help me with the multi-line trigger. Unfortunatly, I'm afraid that for my case, it won't be usable (or maybe to much heavy to write). I updated my question (and gong to add a real example in a few minutes) to show the real use-case. Thank you again for your answer, it was really appreciated ! – franck Jul 31 '23 at 20:33
  • Hello @franck! Welcome for my help. It's effectively a bit a shame you didn't explain what was your main problem. I personally wouldn't have used *vim* and *Ultisnip* to do that as it's more a kind of "file processing" problem, and not an "autocomplete" feature. I'm not a *Python* expert but it would probably be better to just write a *Python* script to process and transform your file. I usually write a *PHP* script to process and transform such files. *sed* is certainly a tool for that but I don't find it as clear and easy to write. – Patrick Janser Aug 02 '23 at 06:37
0

I just found a way to do what I need. I do not love this way but it could work before finding a real way to do a multi-line trigger...

Select the whole transaction entry ; do on it :

sed/\n//

and write the trigger for this entry-line.

It just worked for the 'tfuel' simple example I wrote in my question.

franck
  • 13
  • 5
  • I just thought about the fact that [*Perl* can be used for multiline search and replace](https://unix.stackexchange.com/a/26289/50339), which is [also possible with *sed*, but not as easy](https://unix.stackexchange.com/a/26290/50339). – Patrick Janser Aug 02 '23 at 07:33