echasnovski / mini.nvim

Library of 40+ independent Lua modules improving overall Neovim (version 0.8 and higher) experience with minimal effort
MIT License
4.45k stars 171 forks source link

Unexpected behavior when deleting quotes from a string #968

Closed TommyCox closed 2 weeks ago

TommyCox commented 3 weeks ago

Contributing guidelines

Module(s)

mini.surround

Description

Came across strange behavior in the following edge case: trying to delete quotes around a string while cursor is on the quote character and another string exists nearby.

Example: print("first" .. "second")

mini.surround deletes the selected quote on the string, but deletes the quote from the nearby string instead of the matching quote on the original string (effectively merging the strings into one).

Tested vim-surround which behaves more intuitively:

Compared with mini.surround which displays similar but inverted behavior:

Neovim version

0.10.0

Steps to reproduce

  1. Install LazyVim.
  2. Enable mini.surround in Extras.
  3. Create new file.
  4. Type the following lua example: print("first" .. "second")
  5. Place cursor on ending quote of first or beginning quote of second.
  6. Use normal-mode mapping gsd" to delete quotes.

Expected behavior

Quotes on currently selected string are deleted. print("first" .. "second") -> print(first .. "second") print("first" .. "second") -> print("first" .. second)

Actual behavior

Strings are merged by deleting one quote from each. print("first" .. "second") -> print("first .. second")

TommyCox commented 3 weeks ago

I'm guessing this happens because the second and third quote characters in the example are effectively overlap zones covered by two different regions:

I haven't looked to see exactly how the search algorithm is implemented, but does it handle overlapping regions? I looked through the config documentation to see if this behavior was intentional and/or configurable, but I didn't see anything about priority when handling overlaps.

I'm not sure if there's a more general algorithm for the expected behavior, but at least for strings this might be solved by prioritizing text-objects when an overlap exists.

echasnovski commented 2 weeks ago

Thanks for the issue!

It is not exactly the case of choosing inside or around string here, as 'mini.surround' knows nothing about what "string" is. It is indeed a more general case of preferring between two overlapping regions.

In case of overlapping regions, the one with the smallest width is preferred. So with cursor on second ":

This is the behavior for all default (fallback) identifiers, which " is a part of in 'mini.surround'. It was previously documented, but somewhat convoluted: default identifiers use x.-x pattern which prefer smallest width. But now it is more explicitly documented. Thanks for mentioning this!