AndrewRadev/sideways.vim

Unmatched single quotes make SidewaysArgumentTextobjI jump to unrelated line

idbrii opened this issue · 3 comments

Similar to #24.

If I type some text and use Sideways to add quotes, it fails when the text has an unmatched quote (single or double) and later in the file there's a matching quote.

With file test.cs:

public class Modifier
{
    public static bool Test()
    {
        Debug.Log(this unmatched quote ' breaks surrounding text with quotes, this);
        return true;
    }

    // because of this unmatched quote '

}

omap i, <Plug>SidewaysArgumentTextobjI
0
/this unmatched
normal nsi,"

I guess it's interpreting ' breaks surrounding text with quotes, this); as a string that continues past the end of the line. My syntax highlighting (nickspoons/vim-cs) doesn't, but maybe sideways has its own way to determine what's a string?

Initially found on 01bcf0f, but also reproduced on 9dd871e.

I suppose an argument against fixing this would be even more egregious cases of invalid code:

        Debug.Log(this unmatched quote ' is bad, but commas are worse, this);

But as a user, it makes sense that the only up to the first comma is quoted. Jumping several lines down when ' is not a multi-line string delimiter doesn't make sense.

Regardless, I accept this is an edge case. I understand if you want to close as wontfix : )

As you've guessed, sideways generally expects the code to be valid in order for it to work. There's some permissiveness, like def foo(one, two will work regardless of the lack of a closing bracket, because it's an end of the line, and there's no delimiter after two. But there's no way I can see to get it to work with invalid code.

The "parser" is not particularly smart. I figure the best I can do is rely on Vim to jump from opening to closing bracket, and consider delimiters -- that works well with nested lists as well. But figuring out what to do in your example case seems impossible to me. I assume even Vim would syntax-highlight the rest of the line as a string?

The annoying thing in this case is probably the jumping -- if it didn't do anything, it'd probably be better than doing the wrong thing. I've had similar annoyances with other situations. But I can't think of a way to avoid it -- the multiline functionality is quite useful, and there are valid cases where quoted strings can be multiline (like in Rust):

call_function(
  one,
  r#"
    two
    three
  "#,
  four
)

I wonder if it would make sense to maintain a pair of "multiline_brackets" and one for "single_line_brackets" -- brackets like ([{ would be of the first type, and '" of the second, for most languages. In that case, I guess it would at least not do the jump, and simply terminate if it can't find a matching ' or " on the current line (except for a select few languages like rust). There's probably a lot of language where multiline strings are possible, so I'll probably miss quite a few of them, but it might be a reasonable general case. What do you think?

There's probably a lot of language where multiline strings are possible, so I'll probably miss quite a few of them, but it might be a reasonable general case

In my experience, multiline strings are usually not delimited with ' or ", but with additional characters: rust's #","#; python's """, lua's [[,]], C#'s @",". So if multiline_brackets allows for each "bracket" to have multiple characters, then that sounds like a good solution. We'd also need to know the method of escaping the end of string character (C# uses "" but I'd guess most others use \ before the close character).