Two consecutive "go to matching brace" commands have to return us to the original position. After we moved to the matching brace, we still should see the same brace pair highlighted. All Scintilla-based editors have the problem. Scintilla doesn't necessarily return us to the initial position after the subsequent matching brace jumps. After the first jump Scintilla often highlights nearby brace pair. It is so because Scintilla attempts to place the cursor following to outside or inside braces logic. However, when the cursor is between two braces, Scintilla highlights only the first, left brace. I will provide with two examples. (bold+italic parenthesis indicate the highlighted braces. The exclamation sign indicates the cursor position. ) First example: ( )( ) Place the cursor after the last brace: ( )_**( )!**_ do twice "go to matching brace" and we see the cursor before the fist brace. **_!( )_**( ) Second example: (((( f1+1 )^f2)+( f3+1 ))^f4) Place the cursor after the second brace. (**_(!_**(( f1+1 )^f2)+( f3+1 )**_)_**^f4) do twice "go to matching brace" and we see where the cursor is . (((( f1+1 )^f2)+**_!(_** f3+1 **_)_**)^f4) People who are used to work with other editors are confused. As a workaround, I made a LUA script that goes to matching brace and always keeps the same braces highlighted. (https://github.com/dyura/LUA-scripts-for-text-editors/blob/master/Geany/GoTo...) At the same time, I think that this problem should be solved at the project level.
As you have identified that the issue is common to all Scintilla based editors did you raise it as an issue with Scintilla?
I quickly browsed sources. I might be wrong saying that such a behavior is Scintilla's work. It might be in editors, not in the library. Just Geany may have copied this logic from Scite, a demo editor. But, it doesn't matter which module provides the matching logic. This inside-braces/outside-braces logic was designed for a control on the quick selection. Let's activate "extra selection" plugin and use "Select to matching brace". In the example "[text]" we can quickly select either the text inside braces or the text including these braces. On one hand, it is good, on another hand, it has a side effect that I mentioned above. A few years ago, I did discuss this problem on Scite forum. The option to control the quick selection is important for users. Then, I came up with an idea of LUA script for alternative brace matching in case of complex expressions. I recently introduced Geany to few colleagues, and people were confused with matching. Because brace matching is one of Geany core functionality, it is possible to create another function in Geany for alternative matching. LUA is not ideal for it.
If the cursor is between two brace characters there has to be a choice to highlight the preceding pair or the following pair. Geany chooses the preceding pair. The goto logic is consistent with the highlight logic.
This simple logic will always behave as you observed in the OP, whilst personally I would have chosen the following pair, the same sorts of things will happen if the choice was the following brace.
This inside-braces/outside-braces logic was designed for a control on the quick selection
I think its designed so the cursor comes back to the original position, if it was originally before the brace it ends up back before and if it was originally after the brace it ends up back after it, but without having to have any record of the state anywhere. This is consistent with the use-case of finding the other end of a code block then returning to editing where you left off.
I don't know the history of the feature, but its called "brace" matching, so it likely was originally only {} which do not occur adjacent to one another in normal coding idioms, and the problems have come after it expanded to other forms of brackets which can occur adjacent to each other.
If you wish to propose an alternative logic, please describe it so it can be discussed, simply providing code (especially Lua code in a C/C++ project) and expecting contributors to decode its logic just makes your proposal harder to consider.
The behaviour of the extra select plugin is for that plugins maintainer to decide, if you want to change that, please raise an issue on the plugins repository, not all plugin maintainers watch here.
The statement "The cursor is between two brace characters " is inaccurate. The text cursor is an underscore, a solid rectangle, or a vertical line. When two braces are in a row, the caret can be either at the first brace or at the second brace position. The statement "In between two braces" makes sense only when we use vertical line cursor. Then it looks like the bar is touching the brace from the left or from the right. Without vertical line it is really unclear why the position after the brace is related to the brace, but the position prior to brace is not related. Editors that attempt to simulate outside/inside brace logic move the caret either to matching brace position or to the position next to matching brace. However, this logic causes this ambiguity that cannot be correctly resolved. Other editors evaluate a brace only at the caret position. Then everything is obvious, and matching brace doesn't have any issue. My suggestion is to check the brace existence only at the caret position, cancelling arguable inside/outside brace logic. As I understand the change should affect only brace highlighting and brace matching . I might miss some functionality that I never used before. I attached two patched functions: delay_match_brace and goto_matching_brace as a proof of concept. [goto_matching_brace-function.txt](https://github.com/geany/geany/files/2784477/goto_matching_brace-function.tx...) [delay_match_brace-functon.txt](https://github.com/geany/geany/files/2784479/delay_match_brace-functon.txt)
The statement "In between two braces" makes sense only when we use vertical line cursor.
Yes I was referring to the vertical bar cursor because its the default cursor. Scintilla (and therefore Geany) operations are designed based on that cursor which is between characters. It is possible that behaviour that makes sense relative to a cursor between characters makes less sense for alternative cursors "on" a character but they are not the default.
Then it looks like the bar is touching the brace from the left or from the right.
Exact positioning depends on the font, since consecutive glyphs leave no space between them, Scintilla must "steal" some pixels from the glyph, so its likely that the cursor will look closer to one character or the other.
Without vertical line it is really unclear why the position after the brace is related to the brace, but the position prior to brace is not related.
As above, Geany operation is based on the default vertical bar cursor, so both the character before it and the character after it are equally relevant.
If only one is a brace, that is the one that is highlighted and used by goto. That is a useful feature, the cursor does not need to be moved if its the "wrong" side of the brace and its unlikely that removing that feature as you have done will be acceptable. The goto placement is such that another goto makes the cursor return to the original location.
If both the character before and the one after the cursor are braces the one that is before the cursor is highlighted and used for goto, which is a simple and consistent rule.
Then I believe we can implement the logic used in MS Visual Studio editor and in Visual Studio Code. If only one is a brace, the highlighting logic will remain as currently: to point a brace the cursor bar can be either before or after the brace. If we have several braces in a row, the highlighting should be based on the brace position. ( It could be based on after-brace position, too. But, I believe the brace position is more straightforward and more consistent for users. I am not talking about OVERWRITE mode when the cursor is underline). The goto placement should move the caret to matching brace position. If the cursor is after a single brace, double goto will not return to the initial position, however, it will always return to the same brace, that is most important. Changes should be done in editor_highlight_braces and goto_matching_brace. I attached these two functions. I also attached three screenshots demonstrating the highlighting logic. [editor_highlight_braces-functon.txt](https://github.com/geany/geany/files/2834062/editor_highlight_braces-functon...) [goto_matching_brace-function.txt](https://github.com/geany/geany/files/2834063/goto_matching_brace-function.tx...)
![screenshot from 2019-02-03 12-59-39](https://user-images.githubusercontent.com/39743460/52307100-aea61100-2967-11...) ![screenshot from 2019-02-03 12-59-53](https://user-images.githubusercontent.com/39743460/52307101-aea61100-2967-11...) ![screenshot from 2019-02-03 13-00-12](https://user-images.githubusercontent.com/39743460/52307102-aea61100-2967-11...)
any thoughts on my suggestion?
I repeat what I said above, if the cursor does not _always_ return to the original place after two gotos then it is an unacceptable change as far as I'm concerned.
if the cursor does not always return to the original place after two gotos then it is an unacceptable change as far as I'm concerned.
I am not certain about the meaning of "the original place". If you mean the original brace than the proposed approach always returns to the same brace after two gotos. If you mean the original column position, I am afraid there is no straightforward way to do it. Let's take a matching pair: brace 1 and brace 2. When the cursor is on the "wrong" side of the brace 1, where should "goto" place the cursor? I believe it should be the correct ("not wrong") side of the matching brace 2. Otherwise we have the same problem when two gotoes return to the wrong brace. Now, the cursor is on the "not wrong" side of the brace 2. We do another goto. As I understand, you suggest to place the cursor to the the "wrong" side of the brace 1 to return to the original column position. Then we need to keep track of user actions. If there are two consecutive goes we should move to the "wrong" side, if there is another sequence of operations, we will move to "not wrong" side. Is it what you suggest?
First of all to be clear, braces are `{` and `}` and in most languages they enclose blocks of code/data and in their common formatting they do not occur consecutively. Because braces often enclose large blocks of code/data, goto matching brace is very useful since the matching brace is often off screen, so its highlighting is not visible. Since braces do not commonly occur consecutively, the current Geany algorithm works correctly without saved state[0] and returns the cursor to its original position after two "goto matching brace" commands.
The issue comes when expanding the algorithm to include non-brace brackets eg `()[]<>` since these can commonly occur consecutively and the OP behaviour of highlighting the wrong target bracket may occur. However non-brace brackets also commonly do not enclose as much code as braces do[1] and so the highlighted matching bracket is visible, making goto less useful for non-brace brackets and its issues with consecutive pairs therefore less important.
It is inappropriate to break the useful behaviour of the important use-case to correct behaviour in the less important use-case.
[0] Technically the state information is being saved in the resulting position of the cursor after goto, but I mean there is no separate state information saved elsewhere to return the cursor to its original position.
[1] except in Lisp :)
First of all, I apologize for the word "brace" applied to "parenthesis". I was aware about the difference, but, I kept Genay's terminology: _"Goto matching brace - Ctrl-B. If the cursor is ahead or behind a brace, then it is moved to the brace which belongs to the current one. If this keyboard shortcut is pressed again, the cursor is moved back to the first brace."_ I will comment on the sentence **_"If this keyboard shortcut is pressed again, the cursor is moved back to the first brace."_** later.
"Since braces do not commonly occur consecutively, the current Geany algorithm works correctly without saved state[0] and returns the cursor to its original position after two "goto matching brace" commands."
In general I agree with it. Although there is unformatted javascript code with nested anonymous functions when curly brackets widely occur consecutively, and bracket matching is useful. (BTW, many languages do not curly brackets, but parentheses are part of almost every language. )
"However non-brace brackets also commonly do not enclose as much code as braces do"
Here I disagree. Not only in Lisp. :) Just two common cases: 1) The corporate systems of many financial, insurance and telecommunications corporations have complex business rules. Initially, developers rarely invested in the elegance of the code. In addition, when changing business rules, developers often try to minimize changes in very old code. Thus, the Boolean expressions in the “IF” statements become horrible and easily take up a lot of screens. 2) Very often, SQL scripts have several-screen expressions. SQL formatting is always problematic because the canonical formatting by using tools easily turns several-screen statement into dozens of screens, that is impractical. Consecutive occurrence of parentheses is very common.
"and so the highlighted matching bracket is visible, making goto less useful for non-brace brackets"
I disagree and agree at the same time. When I looked again at "matching" implementations in other GUI editors, I noticed that the highlighted brackets are really perfectly visible. The problem is that Geany doesn't highlight brackets, but only colors them. Like SciTE, Geany, use blue color, which is not very contrasted. Notepad++ is doing slightly better, it colors in red, but even red color cannot be compared with the highlighted symbol. It's almost impossible to find a colored bracket on multiple screens the help of software. That's why I hit double "goto" on a regular basis. Jumping to wrong brackets affected my performance. A few years ago, I wrote a simple LUA script for SciTe. I recently moved it to Geany's LUA. Why did I start this topic if my simple script is great for my needs? Only two reasons: 1) Personally I would also "have chosen the following pair". This behavior cannot be changed by LUA. ( Maybe a plugin could do it). 2) I definitely prefer to get the right functionality out-of-the-box than than download any additional fix later.
"It is inappropriate to break the useful behavior of the important use-case to correct behavior in the less important use-case."
I am confused a little by the meaning of the "breaking the useful behavior" expression. If you mean support of incorrect behavior in a dubiously less important usage scenario, in order to save on an extra key press when the starting position was on the “wrong” side, then I have no arguments. However, I still believe that the original idea of the current behavior was not to preserve the unimportant side of the bracket, but to control the quick selection of the enclosed text: include brackets or not include brackets. At least this goal really makes sense. However, this is not critical for performance, and it can be easily achieved by applying two different commands instead of a combination when one command performs an action differently according to the position of the cursor, but in “less important” cases the command does wrong. Also, I do not see much sense in logic when the sequence “goto + goto” moves the cursor to one side of the bracket, and “goto + left arrow + right arrow + goto” moves to the other side.
Finally, I would suggest something else. Geany has a very detailed manual. I would suggest removing the sentence **"If this keyboard shortcut is pressed again, the cursor is moved back to the first brace."** or indicating when it will do it, and when will not. Users should not be misinformed. Right? :)
To make it clear, I am not saying do not improve the goto brace feature, it is acknowledged that there are circumstances where it behaves less than optimally.
You give specific examples where it fails, thats fine, its acknowledged it is imperfect, but until you show that those examples exceed the entire Linux Kernal source plus GNU source plus the rest of the C code base and much of the Java code base and much of the Javascript code base and [other brace equipped languages] then those cases are unlikely to be the majority of Geany users.
This is not to downplay the pain you feel if it is less useful in code you commonly edit, just to say it would appear that it is useful in many more cases than where it is problematic.
Therefore I am saying when improving goto brace, do not break existing useful functionality, by which I mean when goto brace is used twice on code braces in many common cases it returns the cursor to the original position. This may mean you need a more complex algorithm than that you proposed thats all, for example it may need to remember its original position.
This useful behaviour was kept even when "braces" was extended to "all brackets" even though it causes issues with those.
Geany, use blue color, which is not very contrasted.
Its configured in the colour scheme, so you can look at other [colour schemes](https://github.com/geany/geany-themes), or make your own, or just configure the default it in your personal configuration (Menu->Tools->Configuration files->filetypes.common [named_styles] brace_good).
I would suggest removing the sentence "If this keyboard shortcut is pressed again, the cursor is moved back to the first brace." or indicating when it will do it, and when will not. Users should not be misinformed. Right? :)
Since your next algorithm will make this true in even more cases, it doesn't need to be removed :grin:
In the meantime, a pull request to say "If this keyboard shortcut is pressed again, in most cases the cursor is moved back to the first brace." would be accepted. And probably a note that it works on other bracket types but less perfectly could be added, since they are actually not even mentioned at all. It would appear that "brace" was extended to "all brackets" without updating the manual :frowning_face: .
Brace via bracket. Honestly, I don’t understand why linguistics has gain such an importance in this discussion. But, just out of my curiosity I did a quick search. Being sure that Geany inherited "braces" from Scintilla, I checked there: _"Brace highlighting": ... The brace characters handled are '(', ')', '[', ']', '{', '}', '<', and '>'._ Well, maybe Neil Hodgson is stronger in C++ than in linguistics. Next, I checked with VIM: _"Moving to matching braces" : "...To jump to a matching opening or closing parenthesis, square bracket or a curly brace: ([{}])"_ Finally, I looked at old emacs info: _"The following commands move over groupings delimited by parentheses (or whatever else serves as delimiters in the language you are working with). "_ I was surprised: parentheses!! It turns out that emacs was not designed for C! Maybe for LISP? However, it is enough with linguistics. (Just,
And probably a note that it works on other bracket types but less perfectly
means that the logic is based on the brace shape and not on the brace order only, that is incorrect. I guess it was a problem with quick writing. )
This may mean you need a more complex algorithm than that you proposed thats all, for example it may need to remember its original position.
I don't think that Geany needs to reinvent the wheel. I am a supporter of the strict logic based on the column position of the matching braces. The "goto" should not be ambiguous. Any sophisticated ambiguous placement will be good in simple cases, but in other cases it will cause an unexpected placement if Geany does not prompt users to select the option they want. However, any prompt for the brace/bracket matching would be insane. I disagree with any sophistication.
A real highlighting instead of coloring would be really helpful anyway. But my motivation to use Geany for my daily routine is no longer so high. The reason I recently started using Geany as my main editor was very prosaic. Geany tracked the file's timestamp, when others just checked on focus switching and on file saving. I was interested in this. (You may remember my discussion about the infobar, unmodifiable buffer, and the missing RO indicator. By the way, the info infobar + a popup modal message will be enough. There is no need to switch to read-only mode while people type. Let users decide what they need.) When working with an atypical environment, when even C sources, called Pro*C, and Java sources contain embedded SQL, my first weapon is often “grep”. But Geany does not support the message window history. The history of the search results is necessary for my work, when additional monitoring of timestamps is desirable, but not necessary. Finally, I switched back to more typical editors. Unfortunately, it is very unlikely that I will find time for any pull request. I am not sure that I can provide more information. If someone will come back to this topic in the future, my second draft is pretty accurate. Just selecting between matches was not updated. I believe this issue could be closed, but, being not familiar with this project rules, I don't know what to do with the label "waiting for information".
Closed #1998.
@dyura there is a bug here, as the label says, so it shouldn't be closed.
To summarise the TL;DR for future bug fixers:
1. If the vertical bar cursor is between a bracket and a non-bracket, the bracket is selected for highlighting irrespective of which side the cursor is on, if the cursor is between two bracket characters the one before the cursor is chosen to be highlighted.
2. The `goto matching brace` goes to the bracket matching the highlighted one. This is particularly useful for braces `{}` in C class languages where they enclose blocks of code and the matching brace is commonly off screen. It is less useful for non-brace brackets where they commonly enclose less, and the matching highlighted bracket is therefore visible on screen without goto, so goto is less needed for non-brace brackets in those languages.
3. If the cursor was originally outside the bracket, goto places it outside the matching bracket and if it was inside it is placed inside the matching bracket. This provides a useful feature that two `goto matching brace` commands will return the cursor to the original position.
The combination of 1. and 3. causes a bug when the target position is inside the matching brace because of 3. but also happens to be between two consecutive brackets. In this case the bracket after the cursor is the intended matching one, but 1. causes the bracket before to be highlighted, so highlighting the wrong "matching" bracket and also meaning the next goto will go to the wrong place.
As noted in 2. the most useful use-case for goto is in braces enclosing code, and there the common code layout rules of placing braces on lines by themselves means the bug rarely manifests in this use-case.
So the challenge is to fix the bug in the less commonly useful use-case without breaking the useful feature of returning to the original position in the commonly useful use-case.
It is likely (IMHO) that the return feature will need to be implemented with some internal state instead of recording the previous position in which side of the target the cursor is placed, but someone may find a better solution.
Reopened #1998.
github-comments@lists.geany.org