Auto-close brackets in Geany

    If you used the Geany source code editor, you probably came across a poorly predictable behavior of the standard auto-closing of brackets and quotes. If not used - I recommend you try.

    Geany is a great editor, but throughout its history, auto-closing worked like this:

    func())
    

    or so:

    func()
    {
        }}
    

    It is time to put an end to the manual arrangement of brackets. Meet the new auto-close mode in Geany:

    image

    Preamble


    Geany has a “native” mode of auto-completion and auto-closing (not to be confused: auto-completion is for functions and methods, and auto-closing is for pair brackets and quotes). It would seem that the essence of the algorithm is simple: we track the click of one character and insert the corresponding pair. However, there is a whole pile of pitfalls, diving into which you can fill a lot of cones.

    Problem 1 : people are used to notepad. Many automatically put both the opening bracket and the closing one immediately, the result is not long in coming:

    f())
    f();)
    f() {}}
    f("abc"");
    

    Have you decided to remove the bracket with the backspace? Receive:

    f()) -> f))
    

    This auto-close mode only provides a disservice, so it’s easier to turn it off right away.

    Problem 2 : in different languages, brackets and quotation marks make sense. For example, in C ++, curly braces usually define the boundaries of a block, and in Bash, this can simply be part of a variable. Geany is a multilingual editor, and it would not hurt to take into account the features of each language separately.

    Problem 3 : in many editors, when a piece of text is selected and a bracket / quotation mark is pressed, the selected text “wraps” in this character. In Geany, this text is simply deleted.

    Problem 4: perhaps you never suspected this, but in Geany, while holding Shift, the selection switches to Multiline Selection mode. Needless to say, auto-closing in this mode is not supported in any way. And it’s quite difficult to implement, since block allocation captures “virtual” spaces:


    And the editor also has a clipboard, an undo / redo clip, hot keys and all this somehow should work together ...

    Decision


    Since such problems are not at all confronted with a 21st century notebook, it was decided to implement auto-closure as an addition to Geany . Fortunately, the API makes it easy to do this. It is said - done, by a willful decision, the plug-in was included in the geany-plugins project and will be available as an alternative auto-close mode in the next version of Geany (for this it will be enough to put a tick in the plug-in menu).

    What does he know at the moment? And he can quite a lot:

    • Of course, the completion of the characters {}, [], (), "", '', <>, ``
    • turn on / off auto-completion inside lines and comments
    • smart termination: the pair bracket is automatically deleted, double closing is suppressed
    • puts the selected text in brackets, keeping the selection
    • Functions are automatically completed: sin(|);and structures / classes:struct {|};
    • by pressing Tab, the cursor jumps to a paired character (as in Eclipse)
    • by pressing Shift + BackSpace the pair bracket is deleted, and for curly braces the indent is removed (as in the screenshot at the beginning of the article)

    Among other things, the features of different languages ​​are taken into account: for C-like ones, for example, just select a piece of text and press {so that a new block appears; for Bash, backquote auto-closing is enabled; for HTML characters <> are completed, etc. Auto-indentation is also greatly improved for C-like languages.

    How does it work?


    Geany is based on Scintilla, which provides a fairly diverse API in terms of working with the text buffer. The idea is as simple as usual: we track keystrokes and, depending on the circumstances, respond to the environment. But there it was: Scintilla had a fatal flaw, due to which the API allows you to track all keystrokes, except for backspace. A trifle? And how do you order to track the event of the removal of a character?

    As a result, I had to spit and build a megakostyl event processing, bypassing the Scintilla API and using pure GLib. The complexity of this crutch is that you need to correctly handle the opening and closing of a document (and there may be many tabs) so that you do not inadvertently hook several handlers to one event or even hook it in the wrong place. For example, a typical bug in the Addons plugin is that the handler is attached to the main window. Now plugin events are triggered everywhere - even in the terminal. In general, if someday you have to write a plugin for Geany, and the standard Scintilla API is not enough, you can always find a stable crutch implementation in the Autoclose plugin .

    The rest is a boring series of switches and conditions. From interesting - check for validity of the pointer to the document - doc. On this nuance, many plugins died: the developers unknowingly check the argument of the function like all normal people:

    if(NULL == doc)
        return; //error!
    

    Geany's problem is that the doc, strictly speaking, may not be NULL, but if you try to access it, it will be defaulted. How so? It turns out that inside Geany is actively practicing reusing pointers. If the stars fail and at the time of verification the document is closed, its pointer may become incorrect or even point to a completely different document. To avoid collisions, you need to check the document with the DOC_VALID macro.

    It should be noted that Geany himself steps on his rake: a mysterious segfault, fortunetelling on an assembler dump and the result is checking the doc for NULL in the most important document loading function.

    How to install?


    At the moment, the add-on is in the git head, that is, it has not yet been released along with the Geany release. The plugin will appear only in version 1.24, but it can be used now in one of the following ways:
    - download the experimental Geany 1.24 yet to be released from the so-called "night builds" - everything is already there: nightly.geany.org
    - download the plugin separately and try to assemble it under the old version
    - try to take the autoclose library from night builds and slip it into 1.23, but there are no guarantees

    Attention! The second method is only for extreme sportsmen.
    - you need to download geany-plugins sources from gita: github.com/scriptum/geany-plugins
    - download geany-plugins sources for version 1.23: www.geany.org/Download/Releases
    - copy the autoclose plugin to version 1.23 and try to build the plugin inside source code 1.23 It

    will not be collected right away , since you need to register a plug-in in all autotools scripts that are scattered in a not very obvious way.

    Do not be afraid of using the nightly assembly: all the edits in Geany are thoroughly tested and verified, moreover, a large number of bugs and leaks were fixed in 1.24, a lot of useful features were added, I would say that it is much more stable than the “stable” 1.23. After installation, you will need to enable the Autoclose plugin in the plugins menu and into the battle.

    What's next?


    The plugin has been decided to leave the plugin for now. After the baptism of fire by release, it will migrate to Geany (Autoclose will remain a plugin, but will be part of Geany itself, not the geany-plugins project), after which the old functionality will most likely be removed directly from the editor. He does not solve the problem of autocompletion, this is a topic for a separate (and rather large) work, there are rumors in the IRC that they are trying to screw clang to Geany, but shhh ... :)

    In the meantime, during the period of pre-release languor, I suggest readers to report bugs or express wishes. In particular, there is no support for languages ​​of which I have very vague ideas.

    Also popular now: