ultisnips icon indicating copy to clipboard operation
ultisnips copied to clipboard

a bunch of weird behavior when using `expand_anon` in snippet actions

Open ces42 opened this issue 2 years ago • 2 comments

I just came across a lot of unexpected behavior when using snip.expand_anon in snippet actions, so I am documenting it here. Possibly related to #1433.

1: post_expand with empty snipppet - first tabstop ignored

Snippet file:

post_expand "snip.expand_anon('1:$1;2:$2;')"
snippet aa "description"
endsnippet

Expected behavior: This should be equivalent to the snippet 1:$1;2:$2: Actual behavior: The first tabstop is ignored vim jumps directly to the second one

2: post_expand with nonempty snippet - first tabstop ignored and snippet gets split

Snippet file:

post_expand "snip.expand_anon('1:$1;2:$2;')"
snippet aa "description"
XXYY
endsnippet

Expected behavior: This should be equivalent to the snippet XXYY1:$1;2:$2: Actual behavior: After pressing <tab> I get XX1:;2:|;YY, where | marks the cursor position.

The splitting of the main snippet always seems to occur in the middle of the snippet.

3: post_jump with empty snippet - cursor position is off by one

Snippet file:

post_jump "snip.expand_anon('1:$1;2:$2;')"
snippet aa "description"
endsnippet

Expected behavior: This should be equivalent to the snippet 1:$1;2:$2: Actual behavior: After pressing <tab> I get 1|:;2:; i.e. the cursor is one character to the left of where it should be. The second tabstop works fine

If the snippet is nonempty, expand_anon in post_jump works as expected.


  • Operating System: Ubuntu 21.10
  • Vim Version: neovim 0.6.1 and vim 8.2
  • UltiSnips Version: current master (commit e98466f)
  • Python inside Vim: 3.9.7

ces42 avatar Jan 30 '22 23:01 ces42

I have seen quite a few issues with Anon myself, a lot relates to how the timing of when empties its empty buffer and issue movement autocommands I believe (without a lot of data) which easily messes up UltiSnips. Using Neovim will probably not help your case (and remains unsupported unless somebody steps up to properly support NeoVim) as it throws other variables into the mix.

I have not verified any of these issues, but easily believe they might be there. Having these fixed + test cases would be a very welcomed contribution. It is unlikely that I will be able to work on deep issues like these in UltiSnips anytime soon.

SirVer avatar Feb 01 '22 20:02 SirVer

I have a snippet post jump to call snip.expand_ana that runs into cyclic issue. The snippet is to convert (....)\ into \frac{TabStop}{....}

context "math()"
priority 1000
post_jump "convert_to_tapstop(snip)"
snippet '(^.*\))(\/|\\)' "() Fraction" wr
`!p
if not snip.c:
	stripped = match.group(1)
	depth = 0
	i = len(stripped) - 1
	print(stripped)
	while True:
		# find the outermost pairing parentheses.
		if stripped[i] == ')': depth += 1
		if stripped[i] == '(': depth -= 1
		if depth == 0: break;  
		i -= 1
	assert i>=0
	assert i<=len(stripped) - 1
	numerator = stripped[i+1:-1]
	denominator = "$1"
	if match.group(2) == '\\':
		numerator, denominator = denominator, numerator
	snip.rv = stripped[0:i] + "\\frac{" + numerator + "}" + "{" + denominator + "}"
`$0
endsnippet
def convert_to_tapstop(snip):
  anon_snippet_body = ""
  start = snip.snippet_start[0]
  end = snip.snippet_end[0]
  for i in range(start, end + 1):
    anon_snippet_body += snip.buffer[i]
    anon_snippet_body += "" if i == end else "\n"
  for i in range(start, end):
    del snip.buffer[start]
  snip.buffer[start] = ''
  snip.expand_anon(anon_snippet_body)

the function math() provided by Vimtex determines if we are in a math environment (e.g. \[...\])

Now in the example:

\[
asd (asd)\TAB
\]

and instead of writing TAB I press Tab key there. The first activation is good (got the desired result: asd \frac{STOP-HERE}{asd}). Then I undo by 'u' in normal mode, then enter insert mode and press Tab again, I got a message from UltiSnips:

The snippets content did not converge: Check for Cyclic dependencies or random strings in your snippet. You can use 'if not snip.c' to make sure to only expand random output once.

and results in texts,

Nx[asd \frac{$1}{asasd \frac{$1}{asd}]asd \frac{$1}{asasd \frac{$1}{asd}asd \frac{$1}{asd}asd \frac{}{asd}

Here Nx[....] means repeat .... N times.

I tried logout some information but found nothing. I logged the variable anon_snippet_body which is snip.buffer[snip.line], snip.snippet_start[0]=snip.snippet_end[0]=snip.line here. It seems that the convert_to_tapstop is only trigger once, with anon_snippet_body=asd \frac{$1}{asd}

Have no idea what is going on here.

huweiATgithub avatar Sep 12 '22 19:09 huweiATgithub