(((This is a bug)) since the first day) I join Notepad++



  • Please use Ctrl+B to detect what is wrong.

    Correct:
    ( (Here is a bug) since the ( (first day) ) I joined Notepad++ ( ( (and found ( (and reported
    for version 7.6) ), but it gets no corrections) for version 7.8) ) and (I could not find my post any more) ).

    Errors:
    ((Here is a bug) since the ((first day)) I joined Notepad++ (((and found ((and reported
    for version 7.6)), but it gets no corrections) for version 7.8)) and (I could not find my post any more)).

    My temporary solution is adding a space between any contiguous ‘(’ or ‘)’.





  • @Alan-Kilborn Thank you.



  • @W-TX Even though on the first day I used Notepad++ I found the Control+b bug, it is the most efficient text editor, second to none!



  • Hello, @w-tx, @alan-kilborn and All,

    The default CTRL + B behavior is

    • If caret is, either, right before or right after a starting parenthesis ( a Ctrl + B action moves the caret right before its matched ending parenthesis )

    • If caret is, either, right before or right after an ending parenthesis ) a Ctrl + B action moves the caret right before its matched starting parenthesis (

    Anyone easily understands that, in case of jointed parentheses ((, or )) or, even, )( there’s a problem because Ctrl + B operates, both, if you place the caret before of after a parenthesis :-((

    Logically, the correct behaviour should be :

    • If caret is, either, right after a starting parenthesis ( a Ctrl + B action moves the caret right before its matched ending parenthesis )

    • If caret is, either, right before an ending parenthesis ) a Ctrl + B action moves the caret right after its matched starting parenthesis (


    Now, I found a work-around to get a logical behavior ;-)) As you know, regular expressions are my beloved hobby ;-)). So, using a resursive regex construction solves the wrong behavior of Ctrl + B, in case of consecutive parentheses !

    First, I’m going to explain the regex. This surely will seem a bit tricky to some people but don’t panic ! In the second part of this post, I will discuss of some very practical combinations with the regex and some keyboard actions to simulate the correct Ctrl + B behaviour ;-))


    The magic search regex is :

    (?x) \( ( [^()]+ | (?0) )* \)

    What’s that means :

    • First, the (?x) in-line modifier forces the regex engine to ignore any space character and new-line chars in the regex and, incidentally, to add comments

    • Then, the part \( looks for a literal starting parenthesis (, because of the escaped form

    • Similarly, at the end, the \) part searches for a literal ending parenthesis ), for the same reason

    • Between this two parentheses, the part ( [^()]+ | (?0) )* represents a group, possibly empty, due to the * quantifier, which may be repeated as many as possible, containing two alternatives :

      • The part [^()]+ which grasps any non-null range of characters, different from parentheses ( and )

      • The part (?0) which is a recursive call to the entire regex pattern


    How this recursion process works ?

    
    Let suppose, the MAIN part of the regex ( SPACES are supposed to be IGNORED )
    
    - The regex   \(  (  [^()]+  |  (?0) )*  \)   is SIMILAR to  :
                  ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯
                                 \______________ =(?0)
                                   _____________|_______________
    - the regex   \(  (  [^()]+  | \(  (  [^()]+  |  (?0) )*  \) )*  \)  which is, itself, SIMILAR to :
                                   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯
                                                  \_______________ = (?0)
                                                     _____________|_______________
    - the regex   \(  (  [^()]+  | \(  (  [^()]+  |  \(  (  [^()]+  |  (?0) )*  \)  )*  \) )*  \)  which is, itself, SIMILAR to :
    
    and so on ...
    
    

    Now, we can still improve our regex, by using :

    • A non-capturing group, as we don’t need group1 contents

    • A possessive quantifier, in order that the range of allowed characters will be treated as an atomic range of chars, where backtracking is forbidden. We can do that because, in PCRE regexes, any recursion call is treated in an atomic way, anyway !

    So our magic final regex is :

    (?x) \( (?: [^()]++ | (?0) )* \)


    In order to assign a shortcut to our regex, here are two macros, which you’ll have to insert in the <Macros>....</Macros> section of you active shortcuts.xml configuration file. They allow search of well-balanced blocks of parentheses in downwards ( ALT + B shortcut ) and backward direction ( Alt + Shift + B shortcut ) with the wrap-around behavior

            <Macro name="Regex_Forward" Ctrl="no" Alt="yes" Shift="no" Key="66">      <!-- ALT + B shortcut               --> 
                <Action type="3" message="1700" wParam="0" lParam="0"   sParam="" />
                <Action type="3" message="1601" wParam="0" lParam="0"   sParam="(?x) \(  (?:  [^()]++  |  (?0)  )*  \)" />
                <Action type="3" message="1625" wParam="0" lParam="2"   sParam="" />  <!-- REGULAR expression search mode -->
                <Action type="3" message="1702" wParam="0" lParam="768" sParam="" />  <!-- DOWNWARD search                -->
                <Action type="3" message="1701" wParam="0" lParam="1"   sParam="" />  <!-- Hit on the FIND NEXT button    -->
            </Macro>
            <Macro name="Regex_Backward" Ctrl="no" Alt="yes" Shift="yes" Key="66">      <!-- ALT + SHIFT + B shortcut     --> 
                <Action type="3" message="1700" wParam="0" lParam="0"   sParam="" />  <!-- INITIALIZATION                 -->
                <Action type="3" message="1601" wParam="0" lParam="0"   sParam="(?x) \(  (?:  [^()]++  |  (?0)  )*  \)" />
                <Action type="3" message="1625" wParam="0" lParam="2"   sParam="" />  <!-- REGULAR expression search mode -->
                <Action type="3" message="1702" wParam="0" lParam="256" sParam="" />  <!-- BACKWARD search                -->
                <Action type="3" message="1701" wParam="0" lParam="1"   sParam="" />  <!-- Hit on the FIND NEXT button    -->
            </Macro>
    

    If, for testing, you don’t want to use a macro, here is an alternate method :

    • Open the Find dialog

    • Type in the regex (?x) \( (?: [^()]++ | (?0) )* \), in the Find what: zone

    • Untick the Backward option, if necessary

    • Select the Regular expression search mode

    • Hit the Find Next button

    • Whatever the result, close the Find dialog with the ESC key

    • Open one of your code files, containing some parentheses

    => Now, from caret position :

    • Any hit on the F3 shortcut, will select the next well-balanced block of parentheses

    • Any hit on the Shift + F3 shortcut, will select the previous well-balanced block of parentheses


    Practical example :

    Let’s assume the simple text, below. Note that I wrote it in a single line for readability, but this text could be displayed in several lines, either !

    123(456(()7890)12(345((678)((901)2(34567)890(12345)678)90123456((7890(12345)67))8901)2345))6789
           ><                                             ><            ><
           3rd                                            2nd           1st
    
    • Move the caret to the "1st" position, so between the 0 digit and the (

    • Hit the F3 key :

    => The (12345) block, with its parentheses, is selected. As you can see, this operation is similar to the Ctrl + Alt +B ( Select All Between Matching Braces ).

    • At this point, you may, either :

      • Hit the Ctrl + C shortcut, if you need to copy that well-balanced block of parentheses somewhere else

      • Hit the Right arrow key to suppress selection and place the caret right after the ending )

      • Hit the Left arrow key to suppress selection and place the caret right before the starting (

      • You may, instead, hit the CTRL + B shortcut for the similar above operation !


    Now, let’s try some searches, in both directions :

    • Move the caret to the "2nd" position, so between the ) and the 9 digit

      • Hit the F3 key

    => You’ll notice that the regex finds the next largest well-balanced block, which is ((7890(12345)67))

    • Hit the Shift + F3 shortcut to search in backward direction

    => The inner block (7890(12345)67) is selected, as expected

    • Hit, again, the Shift + F3 shortcut

    => The inner block (12345) is then selected

    • Hit, again, the Shift + F3 shortcut

    This time, as no more inner block exists, it jumps back to previous largest block ((901)2(34567)890(12345)678)

    At this point, 3 possibilities :

    • If you hit the F3 key

    => you’ll get the ((7890(12345)67)) block again

    • If you’ll hit, successively, on the right then the left key and, finally, the Shift + F3 shortcut

    => The closest inner block, near the end of present block, is selected (12345)

    • If you’ll hit, successively, on the left then the right key and, finally, the F3 shortcut

    => The closest inner block, near the start of present block, is selected (901)

    After a while , I’m quite sure you’ll get acquainted, very quickly, to this regex behaviour !

    • Now, move the caret to the "3rd" position, so between the two starting parentheses ((

    • Hit the F3 key

    => As expected, it selects the empty block ()

    • Hit the F3 key again,

    => This time, the regex selects the penultimate largest block of my example, so the well-balanced block :

    (345((678)((901)2(34567)890(12345)678)90123456((7890(12345)67))8901)2345)


    To end with, may be you could also give it a try to :

    • The regex \((?:[^()]++|(?0))*\K\) which only matches the ending matched parenthesis )

    • The regex \((?:[^()]++|(?0))*\)\K which matches the zero-length position, right after the ending matched parenthesis )

    Best Regards,

    guy038

    P.S. :

    Of course, this recursive regex can be used with an other couple of delimiters, which could be, for instance :

    • { and } => The recursive regex would be (?x) \{ (?: [^{}]++ | (?0) )* \}

    • [ and ] => The recursive regex would be (?x) [ (?: [^][]++ | (?0) )* ]

    • < and > => The recursive regex would be (?x) < (?: [^<>]++ | (?0) )* >



  • This is the patch I prepared for myself 4 (or more) years ago.
    Initially I tried to contribute it into Notepad++ main repository but after giving up I started maintaining my own build. Still using it based on ver 6.7.8.2.



  • Managed to dig the ticket I posted on sourceforge.



  • @gstavi said in (((This is a bug)) since the first day) I join Notepad++:

    Managed to dig the ticket I posted on sourceforge.

    In the linked ticket, @donho said:

    The current behaviour is preferable comparing with the one you suggested.

    He is perhaps unique in liking the behavior! :-( Of course, deciding you like the behavior is much easier than doing something to change it. :-)


Log in to reply