Kakoune: Regex negate not working when \h is used

Created on 27 Sep 2020  Â·  9Comments  Â·  Source: mawww/kakoune

Steps

  1. Insert " .a" (there are some spaces, insert without quote)
  2. alt-k ^\h*[^.] <ret>

Outcome

It was selected.

Expected

It should not be selected.

However, if \h in not used, it works. Workaround, s [^h].* <ret> and then only use ^ instead of ^\h*.

bug

All 9 comments

The report mentions a-k, is it a typo? The negation primitive is a-K, with a capital K, and your reproducer works as expected with it.

No, I mean negation as in [^.] in the regex, not a-k.

I think this works as expected. In your example [^.] matches a space character, that's why the selection is kept.
\h* will consume as many spaces as possible, but will consume fewer if the regex doesn't match otherwise.

(assuming your selection before step 2 starts with a space, and a dot at the beginning of a line)

I mean as in [^.] should fail when matching the period since it negate that out, using it directly works but not with ^\h*.

I think we're talking about two different things; it's easier with precise commands:

$ echo ' .' | kak -f '<a-k>^\h*[^.]<ret>'
 .
$ echo ' .' | kak -f '<a-k>^\h*[^.]$<ret>'
error while applying keys to buffer '*stdin*': no selections remaining
 .

The first one works fine, because the <a-k> regex does not need to match the enitre selection, only a substring.

The first one works fine, because the regex does not need to match the enitre selection, only a substring.

Ah, I didn't know about that. I though tit needs to match the entire selection.

Okay, I was actually matching the whole string but I thought echo ' .' | kak -f '<a-k>^\h*[^.]<ret>' should fail since it did not match the [^.] part which I think it should, weird that it does not, I still don't get why.

What I was trying out was:

$ echo ' + 1' | kak -f '<a-k>^\h*[^.+-].*[^\h].*[^,<semicolon>]$<ret>'
 + 1

But I guess I have some issues with the regex.
Then I created one with a more complex kak script.

try %< execute-keys -draft k <a-x> s [^\h].+ <ret> <a-K> \A[-+*/&|^})<gt><lt>] <ret> <a-K> [,<semicolon>](\h*/[/*].*|)$ <ret> j <a-gt> >

Nevermind, I guess I can just keep the s rather than using <a-k>.

Thanks for clarifying.

...since it did not match the [^.] part which I think it should, weird that it does not, I still don't get why.

The trick is that * is greedy, but not completely greedy. It'll back off if it means finding a match that would otherwise fail. For example:

$ echo aaab | grep -o 'a*[^x]'
aaab

a* matches "aaa" and [^x] matches "b", just as you'd expect.

$ echo aaax | grep -o 'a*[^x]'
aaa

First, a* tries to match "aaa", but then [^x] would have to match "x", and that's clearly not going to work. So a* steps back by one and tries again — this time, a* matches "aa", [^x] matches "a", and we have a successful match.

weird that it does not, I still don't get why.

I presume because of interactive use: <a-k>foo is easier to type than <a-k>.*foo.*, also this way it is similar to use to s.

Perl has possessive quantifiers like x*+ that are completely greedy. I believe they are seldomly actually useful, maybe as optimization.

Oh, I forgot about it, [^.] matches the previous character which .* should match. Thanks for the explanation @Screwtapello @krobelus

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dpc picture dpc  Â·  4Comments

lenormf picture lenormf  Â·  3Comments

fennewald picture fennewald  Â·  3Comments

alexherbo2 picture alexherbo2  Â·  3Comments

hwmack picture hwmack  Â·  4Comments