zokugun / vscode-explicit-folding

Customize your Folding for Visual Studio Code
MIT License
99 stars 14 forks source link

"end"/"endRegex" are matched even if there's no corresponding "begin"/"beginRegex" in text, preventing other patterns from matching #20

Closed HolyBlackCat closed 4 years ago

HolyBlackCat commented 4 years ago

Here's a rather obscure bug I've found. It's hard to summarize it in the title, so I'll demonstrate with code.

This is my config:

{
    "begin": "begin",
    "end": ")end",
},
{
    "begin": "(",
    "end": ")",
},

And here's the text I test it on:

(

)end

)

The folding starts on ( as expected, but ends on ) rather than on )end. It seems it happens because "end": ")end", matches before "end": ")",, and even though there's no begin in the text, it still blocks "end": ")", from matching.

In this case, it can be fixed by writing the rules in reverse order, but my actual case is more complex and I can't do that.

daiyam commented 4 years ago

@HolyBlackCat For each language, an big regex is build from all the expected foldings. So the markers can't have any conflict between them. Even if you inverse the config, it won't correctly fold the following code:

begin

)end

What are you trying to do? What is you actual case?

HolyBlackCat commented 4 years ago

Even if you inverse the config, it won't correctly fold the following code:

Oops. Yes, didn't notice that.

What are you trying to do? What is you actual case?

I'm trying to fold C++. It's rather complicated, but I'll try to explain.

Let's say I want to fold two things: parentheses (...) and so-called raw strings (which were the reason for #14). But there's a catch: there are also regular strings "...", and inside of those parentheses and everything else must be ignored. (There are also braces and other stuff, but let's ignore them for now.)

Here's the config I ended up with:

{ // (1) Raw strings
    "beginRegex": "(?:L|u8|u|U|)R\"([^\\s\\(\\)\\\\]{0,16})\\(",
    "endRegex": "\\)\\1\"",
    "nested": false,
    "foldLastLine": false,
},
{ // (2) "..." (not actually folded, since the end marker will always be on the same
    // line as the begin marker; merely forces the contents of quotes to be ignored)
    "beginRegex": "\"(?:[^\"\\\\]|\\.)*(?=\")",
    "endRegex": "\"",
    "nested": false,
},
{ // (3) (...)
    "begin": "(",
    "end": ")",
    "foldLastLine": false,
},

This config mostly works as intended. Here's what I test it on:

<1>
(  folding starts here
123
)  folding ends here

<2>
"("
this is not folded
")"

<3>
R"123(  folding starts here
foo
)"  this doesn't end folding
bar
)123"  folding ends here

this is the part the doesn't work:
<4>
(  folding should start here, but it doesn't
    123
    ()""  folding starts here, but it shouldn't
    456
)  folding ends here

Only the last test case gives an incorrect result. I understand what's going on, but have no idea how to fix it.

I tried reordering the rules. If I order them as (3) (1) (2), then test case <3> fails for a similar reason.

daiyam commented 4 years ago

I need to change how to handle "nested": false. It should only look for the end marker of the active rule. Then, there won't be any conflicting regex between the rules 1 and 3. Your details were helpful.

daiyam commented 4 years ago

@HolyBlackCat I've updated the extension to make the improvement I've said.

daiyam commented 3 years ago

@HolyBlackCat Hi, I have any updated version of the extension which might have an impact on your rules (nested). I have used the unit tests (https://github.com/zokugun/vscode-explicit-folding/tree/master/test/fixtures/cpp) but I may not have all the tests for your cases. The new version is fixing the regexes that so that ^ is really the beginning of a line.

Can you test it ?

Here the steps to test it:

Or uninstall the extension and install explicit-folding-0.11.0.vsix (remove .zip) by dropping the file in the list of extensions.