Author Topic: Events  (Read 19415 times)

Offline Alpha

  • Developer
  • Lives here!
  • *****
  • Posts: 1513
Events
« on: November 05, 2011, 04:42:56 pm »
I have been trying to add a function to Code::Blocks that will retrieve the currently selected text when the user presses a key (for example, 'a').  Inside cbEditor::CreateEditor(), I have tried wxEVT_SCI_CHARADDED, however, the function is called after the charecter is inserted, so the selected text will already have been deleted.  I also tried wxEVT_SCI_KEY and EVT_KEY_DOWN, but they were never called (should they have been, and I incorrectly implemented it?).

Could someone kindly let me know if sdk\cbEditor.cpp is even the correct file to be working in, and point me to the correct event to use (and maybe give an example code snippit in case I am doing this completely wrong)?

Thank you.

Offline Alpha

  • Developer
  • Lives here!
  • *****
  • Posts: 1513
Re: Events
« Reply #1 on: November 08, 2011, 01:00:11 am »
Hmm... I guess I did not exactly give any indication of what I am trying to do.

In Code::Blocks, a feature I would like to use is an extension to brace completion: if a section of code is selected when one of the following is keys is pressed:
( ) [ ] < > "
the selected text will be surrounded by (instead of being replaced by) the corresponding symbols.  When { or } are pressed, the line(s) the selected text is (are) on will be indented, and braces added on the lines before and after the indented section.

This did not seem to be extremely difficult to do (but still useful, at least to me), however, as I mentioned above, I am having the difficulty of registering the correct event.  If someone could enlighten me, I am sure that I could complete this modification (and I would be very grateful, as I have spent multiple hours reading event documentation to no avail).

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 13413
    • Travis build status
Re: Events
« Reply #2 on: November 08, 2011, 01:41:17 am »
Why don't you do it as a menu command? And an advanced version, showing a dialog to enter a value.
For example I want to be able to wrap strings in wxT("...."), _("...."),
so if I type in the dialog wxT, or _ the plugin will wrap it automatically.

But I guess, that you need to interrupt the event before wxScintilla has processed it, not after.
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5916
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Events
« Reply #3 on: November 08, 2011, 01:59:11 am »
You can have a look at the file "sdk\cbstyledtextctrl.cpp"
Especially the function:
Code
void cbStyledTextCtrl::OnKeyDown(wxKeyEvent& event)
{
    switch (event.GetKeyCode())
    {
        case WXK_TAB:
        {
            if (m_tabSmartJump && !(event.ControlDown() || event.ShiftDown() || event.AltDown()))
            {
                if (!AutoCompActive() && m_bracePosition != wxSCI_INVALID_POSITION)
                {
                    m_lastPosition = GetCurrentPos();
                    GotoPos(m_bracePosition);

                    // Need judge if it's the final brace
                    HighlightRightBrace();
                    if (!m_tabSmartJump && CallTipActive())
                        CallTipCancel();
                    return;
                }
            }
        }
        break;

        case WXK_BACK:
        {
            if (m_tabSmartJump)
            {
                if (!(event.ControlDown() || event.ShiftDown() || event.AltDown()))
                {
                    const int pos = GetCurrentPos();
                    const int index = s_leftBrace.Find((wxChar)GetCharAt(pos - 1));
                    if (index != wxNOT_FOUND && (wxChar)GetCharAt(pos) == s_rightBrace.GetChar(index))
                    {
                        CharRight();
                        DeleteBack();
                    }
                }
                else if (m_lastPosition != wxSCI_INVALID_POSITION && event.ControlDown())
                {
                    GotoPos(m_lastPosition);
                    m_lastPosition = wxSCI_INVALID_POSITION;
                    return;
                }
            }
        }
        break;

        case WXK_RETURN:
        case WXK_ESCAPE:
        {
            if (m_tabSmartJump)
                m_tabSmartJump = false;
        }
        break;
    }

    event.Skip();
}
Here, the "tab smart jump" was implemented, that is mostly the same place you can implement your feature. Right?
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline thomas

  • Administrator
  • Lives here!
  • *****
  • Posts: 3979
Re: Events
« Reply #4 on: November 08, 2011, 09:22:18 am »
This is a feature I've wished I had had many times in the past. Actually it's something I still wish I had, about 20 times per day :)

One just needs to be very careful that it works the way people expect, and that's where it gets complicated.

Most people will expect that if they have a text selected and press a key such as {, then the selection will be erased and replaced with a single character. That's how it works in pretty much every editor, anywhere.

vi probably has a key for such a thing, and if vi doesn't, then emacs probably does (they have a keys for every crap, just I can't remember any of them). Might be worthwile to look there, and use that combination, so it's "somewhat standards compliant".
« Last Edit: November 08, 2011, 09:26:03 am by thomas »
"We should forget about small efficiencies, say about 97% of the time: Premature quotation is the root of public humiliation."

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2778
Re: Events
« Reply #5 on: November 08, 2011, 02:30:13 pm »
There's a lot of code here that might help you intercept/insert keys and characters.

KeyMacs
http://forums.codeblocks.org/index.php/topic,9980.msg70445.html#msg70445

Offline Alpha

  • Developer
  • Lives here!
  • *****
  • Posts: 1513
Re: Events
« Reply #6 on: November 08, 2011, 11:26:54 pm »
Thank you everyone for your responses :).

... And an advanced version, showing a dialog to enter a value.
For example I want to be able to wrap strings in wxT("...."), _("...."),
so if I type in the dialog wxT, or _ the plugin will wrap it automatically.
This sounds like an additional feature that would be quite useful.  Would you suggest I try to add this dialog to the core application, or as a plugin?

You can have a look at the file "sdk\cbstyledtextctrl.cpp"
...
Here, the "tab smart jump" was implemented, that is mostly the same place you can implement your feature. Right?
Yes, I think this is exactly what I was looking for.

Most people will expect that if they have a text selected and press a key such as {, then the selection will be erased and replaced with a single character. That's how it works in pretty much every editor, anywhere.

vi probably has a key for such a thing, and if vi doesn't, then emacs probably does (they have a keys for every crap, just I can't remember any of them). Might be worthwile to look there, and use that combination, so it's "somewhat standards compliant".
I know that I would find it most efficient to have this bound to the actual key, however others (I assume) would prefer it as a shortcut, or not at all.  It is in my plan to have some sort of setting to choose between these - and I will do some reading on vi and emacs to find out what their key combination(s) is (are).

There's a lot of code here that might help you intercept/insert keys and characters.

KeyMacs
http://forums.codeblocks.org/index.php/topic,9980.msg70445.html#msg70445
Thanks, I will take a look at that.

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 13413
    • Travis build status
Re: Events
« Reply #7 on: November 08, 2011, 11:40:05 pm »
This sounds like an additional feature that would be quite useful.  Would you suggest I try to add this dialog to the core application, or as a plugin?
Your priority should be this:
0. script <--biggest priority here
1. plugin
2. core
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline smallB

  • Almost regular
  • **
  • Posts: 193
Re: Events
« Reply #8 on: November 09, 2011, 09:54:25 am »
@Alpha I think it's great idea. Something like Alt + Bracket_Type would disambiguate situation.
« Last Edit: November 09, 2011, 12:00:49 pm by smallB »

Offline Alpha

  • Developer
  • Lives here!
  • *****
  • Posts: 1513
Re: Events
« Reply #9 on: November 10, 2011, 12:35:58 am »
Alt + Bracket_Type sounds like another good option; I will try it as well.

This sounds like an additional feature that would be quite useful.  Would you suggest I try to add this dialog to the core application, or as a plugin?
Your priority should be this:
0. script <--biggest priority here
1. plugin
2. core
OK; I probably will not work on this until I have completed the original modification though.

As a note, I do not know if I will have any time to work on this before the weekend (although, I am feeling a bit of pressure now that I know a bunch of other people like it :)).

Offline daniloz

  • Regular
  • ***
  • Posts: 268
Re: Events
« Reply #10 on: November 10, 2011, 08:08:31 am »
Alt + Bracket_Type sounds like another good option; I will try it as well.

Please make it configurable, since I have a swiss german keyboard and the "[" and "{" brackets are obtained via Alt_Gr + ü/ä, so I'm not sure if Alt + Alt_Gr + ü/ä would work. I'm afraid not...

Offline Jenna

  • Administrator
  • Lives here!
  • *****
  • Posts: 7255
Re: Events
« Reply #11 on: November 10, 2011, 10:46:15 am »
Most likely not and the same is for many other languages I guess.
German layout uses AltGr+8  for "[" and AltGr+7 for "{".

Offline smallB

  • Almost regular
  • **
  • Posts: 193
Re: Events
« Reply #12 on: November 10, 2011, 12:08:37 pm »
Yes, that definitely should be configurable. But "full configurability" should be a part of every feature not just this one. I as I user should be able to configure IDE (look and behavior) in a way that will suits me best.
That's why I so much love C++ - almost unconstrained freedom!

Offline Ceniza

  • Developer
  • Lives here!
  • *****
  • Posts: 1441
    • CenizaSOFT
Re: Events
« Reply #13 on: November 10, 2011, 12:12:33 pm »
Visual Assist X has something like this, and it can be quite handy. It also allows you to comment/uncomment by selecting something and typing either / or *. Make it a setting, so there's no need to also press an extra key.

Offline smallB

  • Almost regular
  • **
  • Posts: 193
Re: Events
« Reply #14 on: November 10, 2011, 12:53:29 pm »
Cannot wait to use it! :shock:

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 13413
    • Travis build status
Re: Events
« Reply #15 on: November 10, 2011, 10:57:27 pm »
It also allows you to comment/uncomment by selecting something and typing either / or *.
This is pretty annoying feature. 50% of the time it was deleting my selection.
The C::B solution is definitely better here:
Ctrl+Shift+x = comment the seletion
Ctrl+Shift+c = uncomment the selection
Works 100% of the time and it is pretty predictable.

But "full configurability" should be a part of every feature not just this one.
This is definitely the wrong philosophy. Features should just work. Because it makes life easier.
We as developers should strive for this. Making it configurable is the easiest thing, most of the time, but not the best.
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline smallB

  • Almost regular
  • **
  • Posts: 193
Re: Events
« Reply #16 on: November 11, 2011, 07:58:02 am »
@Obfuscated I strongly disagree with you on that one. Providing configurability of a feature allows every one to set it in a way that work best for them - in the spirit "What's good for you it doesn't mean it is good for me, and what you think is pretty to me seems awful". What you're saying is that there is one and correct/best way to suit everyone's needs and I'm saying that this isn't true and bad design practice.Just look around you, on most popular, successful software and think about it. The best way is to let everyone set the feature so it works the way suits the particular individual best, not the designer.
And at the end just to prove that what I'm saying is correct: you're saying something like:
"This is pretty annoying feature. 50% of the time it was deleting my selection." - It is not annoying to me. I love it. If I want to delete something I press either spacebar or backspace.
So you see, what's annoying for a one person may be of great help and usefulness for the other. There is no One Size Fits All. This approach is bad, and it doesn't work.

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 13413
    • Travis build status
Re: Events
« Reply #17 on: November 11, 2011, 10:17:02 am »
But you've not understood what I've said.
There are plenty of approaches to implement a feature.
Some of the approaches, like the auto-commenting feature of V-Assists aren't robust and annoys some people.
The strive should be for non-annoying implementations of the features, like the manual commenting/uncommenting in C::B.

And I don't like to have to setup my C::B for 30 minutes every time I install new OS.
Most of the things I do is disable this, this, this and this.
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline smallB

  • Almost regular
  • **
  • Posts: 193
Re: Events
« Reply #18 on: November 11, 2011, 10:55:31 am »

The strive should be for non-annoying implementations of the features, like the manual commenting/uncommenting in C::B.

But that's my point exactly - just because you think it is annoying or it indeed annoys you - fair enough - everyone has their own preferences, and likings, and here is the crux - everyone's preferences should be respected - not just yours. Because it is not annoying to me and I really like it. So what I'm saying is that everyone, you, me and other users should be able to set this feature the way suits them best. So it also means that you should be able to disable this if it does annoy you. It wouldn't be fair on you to not allow you to disable this, right? So why do you think it's fair on others not to be able to enable this? It's two way street. And that's good.
« Last Edit: November 11, 2011, 11:04:04 am by smallB »

Offline smallB

  • Almost regular
  • **
  • Posts: 193
Re: Events
« Reply #19 on: November 11, 2011, 10:56:27 am »
And I don't like to have to setup my C::B for 30 minutes every time I install new OS.
Most of the things I do is disable this, this, this and this.

I don't think anyone likes it. But, but, but, but:
1. You can always export cb's settings and after installing new OS you can simply import them ;).
2. How would you feel about it if you were robed from the privilege of disabling this, this and this? Because designer decided that disabling this is so annoying and it shouldn't be allowed. Would you agree with his approach/way of thinking?
3. There should be (and I'm going to add it as a my suggestion) option which would allow to choose (again you see? it should allow, to accommodate user like you - minimalist) how cb is set up.
What I mean by this is that there should be some kind of levels defined (which could also be edited) so for example user like you would pick:
Expert
someone else would pick:
Intermediate
and I would pick:
Novice
where everything would be set up as to ease my work as much as possible with this IDE. Default compiler, safest settings in it, every possible help when working with editor etc. etc etc.
But again, all this should be configurable so I with time with change my novice profile, and let's say remove some settings from compiler - or add them, but it still be my Novice profile.
« Last Edit: November 11, 2011, 11:10:59 am by smallB »

Offline Alpha

  • Developer
  • Lives here!
  • *****
  • Posts: 1513
Re: Events
« Reply #20 on: November 11, 2011, 10:31:57 pm »
Here is an initial patch to show functionality.  It currently has no settings; pressing any of:
' " ( ) [ ] < > { }
will trigger it (the final position of the caret is determined by the direction of the brace).

Currently, the altered text is deselected after activating.  Does anyone like the idea of leaving " selected (but not the others) so that, for example, a user can select something and type:
"(wxT
to wrap it like:
wxT("sample text")

When creating a string with ", would it be expected behavior to escape any double quotes in between, or should I leave it as it currently is?

Because of the way wxWidgets implements the EVT_KEY_DOWN event, I am fairly certain it will not function properly on other keyboard layouts.  I am working on a method of portablizing this.

When I get to creating the option of choosing between using keyboard shortcuts or the current method of activation (and, of course, disabling it completely), is there of set of six shortcuts (it could be fewer if only certain features are wanted) available that works on all keyboard layouts?

Code
Index: src/sdk/cbstyledtextctrl.cpp
===================================================================
--- src/sdk/cbstyledtextctrl.cpp (revision 7568)
+++ src/sdk/cbstyledtextctrl.cpp (working copy)
@@ -123,6 +123,148 @@
 
 void cbStyledTextCtrl::OnKeyDown(wxKeyEvent& event)
 {
+    wxString selectedText = GetSelectedText();
+    if (selectedText != wxEmptyString && !(event.AltDown() || event.ControlDown()))
+    {
+        switch (event.GetKeyCode())
+        {
+            case _T('\''):  // ' "
+            {
+                BeginUndoAction();
+                DeleteBack();
+                if (event.ShiftDown())
+                {
+                    InsertText(GetCurrentPos(), wxT("\"") + selectedText + wxT("\""));
+                }
+                else
+                {
+                    InsertText(GetCurrentPos(), wxT("'") + selectedText + wxT("'"));
+                }
+                SetEmptySelection(GetCurrentPos() + selectedText.Length() + 2);
+                EndUndoAction();
+                return;
+            }
+#ifdef __WXMSW__
+            case _T('9'):   // ( for wxMSW
+            {
+                if (!event.ShiftDown())
+                {
+                    break;
+                }
+            }
+#else
+            case _T('('):   // ( for wxGTK
+#endif
+            {
+                BeginUndoAction();
+                DeleteBack();
+                InsertText(GetCurrentPos(), wxT("(") + selectedText + wxT(")"));
+                EndUndoAction();
+                return;
+            }
+#ifdef __WXMSW__
+            case _T('0'):   // ) for wxMSW
+            {
+                if (!event.ShiftDown())
+                {
+                    break;
+                }
+            }
+#else
+            case _T(')'):   // ) for wxGTK
+#endif
+            {
+                BeginUndoAction();
+                DeleteBack();
+                InsertText(GetCurrentPos(), wxT("(") + selectedText + wxT(")"));
+                SetEmptySelection(GetCurrentPos() + selectedText.Length() + 2);
+                EndUndoAction();
+                return;
+            }
+            case _T(','):   // <
+            {
+                if (!event.ShiftDown())
+                {
+                    break;
+                }
+                BeginUndoAction();
+                DeleteBack();
+                InsertText(GetCurrentPos(), wxT("<") + selectedText + wxT(">"));
+                EndUndoAction();
+                return;
+            }
+            case _T('.'):   // >
+            {
+                if (!event.ShiftDown())
+                {
+                    break;
+                }
+                BeginUndoAction();
+                DeleteBack();
+                InsertText(GetCurrentPos(), wxT("<") + selectedText + wxT(">"));
+                SetEmptySelection(GetCurrentPos() + selectedText.Length() + 2);
+                EndUndoAction();
+                return;
+            }
+            case _T('['):   // [ {
+            {
+                BeginUndoAction();
+                if (event.ShiftDown())
+                {
+                    int startLine = LineFromPosition(GetSelectionStart());
+                    int endLine = LineFromPosition(GetSelectionEnd());
+                    if(startLine == endLine)
+                    {
+                        Home();
+                    }
+                    Tab();
+                    SetEmptySelection(GetLineEndPosition(endLine));
+                    NewLine();
+                    BackTab();
+                    InsertText(GetCurrentPos(), wxT("}"));
+                    SetEmptySelection(GetLineEndPosition(startLine - 1));
+                    NewLine();
+                    InsertText(GetCurrentPos(), wxT("{"));
+                }
+                else
+                {
+                    DeleteBack();
+                    InsertText(GetCurrentPos(), wxT("[") + selectedText + wxT("]"));
+                }
+                EndUndoAction();
+                return;
+            }
+            case _T(']'):   // ] }
+            {
+                BeginUndoAction();
+                if (event.ShiftDown())
+                {
+                    int startLine = LineFromPosition(GetSelectionStart());
+                    int endLine = LineFromPosition(GetSelectionEnd());
+                    if(startLine == endLine)
+                    {
+                        Home();
+                    }
+                    Tab();
+                    SetEmptySelection(GetLineEndPosition(startLine - 1));
+                    NewLine();
+                    InsertText(GetCurrentPos(), wxT("{"));
+                    SetEmptySelection(GetLineEndPosition(endLine + 1));
+                    NewLine();
+                    BackTab();
+                    InsertText(GetCurrentPos(), wxT("}"));
+                }
+                else
+                {
+                    DeleteBack();
+                    InsertText(GetCurrentPos(), wxT("[") + selectedText + wxT("]"));
+                    SetEmptySelection(GetCurrentPos() + selectedText.Length() + 2);
+                }
+                EndUndoAction();
+                return;
+            }
+        }
+    }
     switch (event.GetKeyCode())
     {
         case WXK_TAB:


Awaiting reports of functionality (or failure)...
« Last Edit: November 12, 2011, 12:17:22 am by Alpha »

Offline Alpha

  • Developer
  • Lives here!
  • *****
  • Posts: 1513
Re: Events
« Reply #21 on: November 12, 2011, 12:39:14 am »
Changes in this patch:
  • Works regardless of keyboard layout (I think)
  • Undo is now two steps; the first step will revert it to what would normally happen (without this patch's modification)
  • When creating a string, the relevant symbols are escaped
  • Strings remain selected

Code
Index: src/sdk/cbeditor.cpp
===================================================================
--- src/sdk/cbeditor.cpp (revision 7582)
+++ src/sdk/cbeditor.cpp (working copy)
@@ -3022,6 +3022,134 @@
     static int autoUnIndentValue = -1;
     static int autoUnIndentLine = -1;
 
+    if (!control->GetLastSelectedText().IsEmpty())
+    {
+        wxString selectedText = control->GetLastSelectedText();
+        switch (ch)
+        {
+            case _T('\''):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                selectedText.Replace(wxT("\\'"), wxT("'"));
+                selectedText.Replace(wxT("'"), wxT("\\'"));
+                control->InsertText(pos - 1, wxT("'") + selectedText + wxT("'"));
+                control->SetEmptySelection(pos + selectedText.Length() + 1);
+                control->EndUndoAction();
+                return;
+            }
+            case _T('"'):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                selectedText.Replace(wxT("\\\""), wxT("\""));
+                selectedText.Replace(wxT("\""), wxT("\\\""));
+                control->InsertText(pos - 1, wxT("\"") + selectedText + wxT("\""));
+                control->SetCurrentPos(pos + selectedText.Length() + 1);
+                control->EndUndoAction();
+                return;
+            }
+            case _T('('):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                control->InsertText(pos - 1, wxT("(") + selectedText + wxT(")"));
+                control->EndUndoAction();
+                return;
+            }
+            case _T(')'):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                control->InsertText(pos - 1, wxT("(") + selectedText + wxT(")"));
+                control->SetEmptySelection(pos + selectedText.Length() + 1);
+                control->EndUndoAction();
+                return;
+            }
+            case _T('['):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                control->InsertText(pos - 1, wxT("[") + selectedText + wxT("]"));
+                control->EndUndoAction();
+                return;
+            }
+            case _T(']'):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                control->InsertText(pos - 1, wxT("[") + selectedText + wxT("]"));
+                control->SetEmptySelection(pos + selectedText.Length() + 1);
+                control->EndUndoAction();
+                return;
+            }
+            case _T('<'):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                control->InsertText(pos - 1, wxT("<") + selectedText + wxT(">"));
+                control->EndUndoAction();
+                return;
+            }
+            case _T('>'):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                control->InsertText(pos - 1, wxT("<") + selectedText + wxT(">"));
+                control->SetEmptySelection(pos + selectedText.Length() + 1);
+                control->EndUndoAction();
+                return;
+            }
+            case _T('{'):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                control->InsertText(pos - 1, selectedText);
+                control->SetSelectionVoid(pos - 1, pos + selectedText.Length() - 1);
+                int startLine = control->LineFromPosition(control->GetSelectionStart());
+                int endLine = control->LineFromPosition(control->GetSelectionEnd());
+                if(startLine == endLine)
+                {
+                    control->Home();
+                }
+                control->Tab();
+                control->SetEmptySelection(control->GetLineEndPosition(endLine));
+                control->NewLine();
+                control->BackTab();
+                control->InsertText(control->GetCurrentPos(), wxT("}"));
+                control->SetEmptySelection(control->GetLineEndPosition(startLine - 1));
+                control->NewLine();
+                control->InsertText(control->GetCurrentPos(), wxT("{"));
+                control->EndUndoAction();
+                return;
+            }
+            case _T('}'):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                control->InsertText(pos - 1, selectedText);
+                control->SetSelectionVoid(pos - 1, pos + selectedText.Length() - 1);
+                int startLine = control->LineFromPosition(control->GetSelectionStart());
+                int endLine = control->LineFromPosition(control->GetSelectionEnd());
+                if(startLine == endLine)
+                {
+                    control->Home();
+                }
+                control->Tab();
+                control->SetEmptySelection(control->GetLineEndPosition(startLine - 1));
+                control->NewLine();
+                control->InsertText(control->GetCurrentPos(), wxT("{"));
+                control->SetEmptySelection(control->GetLineEndPosition(endLine + 1));
+                control->NewLine();
+                control->BackTab();
+                control->InsertText(control->GetCurrentPos(), wxT("}"));
+                control->CharRight();
+                control->EndUndoAction();
+                return;
+            }
+        }
+    }
+
     // indent
     if (ch == _T('\n'))
     {
Index: src/sdk/cbstyledtextctrl.cpp
===================================================================
--- src/sdk/cbstyledtextctrl.cpp (revision 7582)
+++ src/sdk/cbstyledtextctrl.cpp (working copy)
@@ -123,6 +123,8 @@
 
 void cbStyledTextCtrl::OnKeyDown(wxKeyEvent& event)
 {
+    m_lastSelectedText = GetSelectedText();
+
     switch (event.GetKeyCode())
     {
         case WXK_TAB:
Index: src/include/cbstyledtextctrl.h
===================================================================
--- src/include/cbstyledtextctrl.h (revision 7582)
+++ src/include/cbstyledtextctrl.h (working copy)
@@ -22,6 +22,7 @@
         cbStyledTextCtrl(wxWindow* pParent, int id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
         virtual ~cbStyledTextCtrl();
         wxDateTime GetLastFocusTime() const {return m_lastFocusTime;}
+        wxString GetLastSelectedText() const {return m_lastSelectedText;}
 
         void EnableTabSmartJump(bool enable = true);
         bool IsCharacter(int style);
@@ -52,6 +53,7 @@
         int m_bracePosition;
         int m_lastPosition;
         bool m_tabSmartJump;
+        wxString m_lastSelectedText;
 
         static std::map<int, std::set<int> > CharacterLexerStyles, StringLexerStyles, PreprocessorLexerStyles, CommentLexerStyles;
 

Offline Alpha

  • Developer
  • Lives here!
  • *****
  • Posts: 1513
Re: Events
« Reply #22 on: November 13, 2011, 05:07:56 am »
Changes in this patch:
  • Activation is now controlled by an option (Settings->Editor... "Selection brace completion")
  • Removed a bit of redundant code

Code
Index: src/sdk/editorconfigurationdlg.cpp
===================================================================
--- src/sdk/editorconfigurationdlg.cpp (revision 7582)
+++ src/sdk/editorconfigurationdlg.cpp (working copy)
@@ -20,7 +20,7 @@
     #include <wx/stattext.h>
     #include <wx/textdlg.h>
     #include <wx/xrc/xmlres.h>
-   
+
     #include "manager.h"
     #include "configmanager.h"
     #include "pluginmanager.h"
@@ -118,6 +118,7 @@
     XRCCTRL(*this, "chkUseChangebar", wxCheckBox)->SetValue(m_EnableChangebar);
     XRCCTRL(*this, "chkShowIndentGuides", wxCheckBox)->SetValue(cfg->ReadBool(_T("/show_indent_guides"), false));
     XRCCTRL(*this, "chkBraceSmartIndent", wxCheckBox)->SetValue(cfg->ReadBool(_T("/brace_smart_indent"), true));
+    XRCCTRL(*this, "chkSelectionBraceCompletion", wxCheckBox)->SetValue(cfg->ReadBool(_T("/selection_brace_completion"), false));
     XRCCTRL(*this, "chkTabIndents", wxCheckBox)->SetValue(cfg->ReadBool(_T("/tab_indents"), true));
     XRCCTRL(*this, "chkBackspaceUnindents", wxCheckBox)->SetValue(cfg->ReadBool(_T("/backspace_unindents"), true));
     XRCCTRL(*this, "chkWordWrap", wxCheckBox)->SetValue(cfg->ReadBool(_T("/word_wrap"), false));
@@ -795,6 +796,7 @@
         cfg->Write(_T("/use_tab"),                             XRCCTRL(*this, "chkUseTab", wxCheckBox)->GetValue());
         cfg->Write(_T("/show_indent_guides"),                  XRCCTRL(*this, "chkShowIndentGuides", wxCheckBox)->GetValue());
         cfg->Write(_T("/brace_smart_indent"),                  XRCCTRL(*this, "chkBraceSmartIndent", wxCheckBox)->GetValue());
+        cfg->Write(_T("/selection_brace_completion"),          XRCCTRL(*this, "chkSelectionBraceCompletion", wxCheckBox)->GetValue());
         cfg->Write(_T("/tab_indents"),                         XRCCTRL(*this, "chkTabIndents", wxCheckBox)->GetValue());
         cfg->Write(_T("/backspace_unindents"),                 XRCCTRL(*this, "chkBackspaceUnindents", wxCheckBox)->GetValue());
         cfg->Write(_T("/word_wrap"),                           XRCCTRL(*this, "chkWordWrap", wxCheckBox)->GetValue());
Index: src/sdk/cbeditor.cpp
===================================================================
--- src/sdk/cbeditor.cpp (revision 7582)
+++ src/sdk/cbeditor.cpp (working copy)
@@ -2897,7 +2897,7 @@
             wxTreeItemId sel = Manager::Get()->GetProjectManager()->GetTreeSelection();
             if (sel.IsOk())
                 tree->SelectItem(sel, false);
-           
+
             const wxTreeItemId &itemId = m_pProjectFile->GetTreeItemId();
             if (itemId.IsOk())
             {
@@ -3022,6 +3022,104 @@
     static int autoUnIndentValue = -1;
     static int autoUnIndentLine = -1;
 
+    bool SelectionBraceCompletion = Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/selection_brace_completion"), false);
+    if (SelectionBraceCompletion && !control->GetLastSelectedText().IsEmpty())
+    {
+        wxString selectedText = control->GetLastSelectedText();
+        switch (ch)
+        {
+            case _T('\''):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                selectedText.Replace(wxT("\\'"), wxT("'"));
+                selectedText.Replace(wxT("'"), wxT("\\'"));
+                control->InsertText(pos - 1, wxT("'") + selectedText + wxT("'"));
+                control->SetEmptySelection(pos + selectedText.Length() + 1);
+                control->EndUndoAction();
+                return;
+            }
+            case _T('"'):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                selectedText.Replace(wxT("\\\""), wxT("\""));
+                selectedText.Replace(wxT("\""), wxT("\\\""));
+                control->InsertText(pos - 1, wxT("\"") + selectedText + wxT("\""));
+                control->SetCurrentPos(pos + selectedText.Length() + 1);
+                control->EndUndoAction();
+                return;
+            }
+            case _T('('):
+            case _T(')'):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                control->InsertText(pos - 1, wxT("(") + selectedText + wxT(")"));
+                if(ch == _T(')'))
+                {
+                    control->SetEmptySelection(pos + selectedText.Length() + 1);
+                }
+                control->EndUndoAction();
+                return;
+            }
+            case _T('['):
+            case _T(']'):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                control->InsertText(pos - 1, wxT("[") + selectedText + wxT("]"));
+                if(ch == _T(']'))
+                {
+                    control->SetEmptySelection(pos + selectedText.Length() + 1);
+                }
+                control->EndUndoAction();
+                return;
+            }
+            case _T('<'):
+            case _T('>'):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                control->InsertText(pos - 1, wxT("<") + selectedText + wxT(">"));
+                if(ch == _T('>'))
+                {
+                    control->SetEmptySelection(pos + selectedText.Length() + 1);
+                }
+                control->EndUndoAction();
+                return;
+            }
+            case _T('{'):
+            case _T('}'):
+            {
+                control->BeginUndoAction();
+                control->DeleteBack();
+                control->InsertText(pos - 1, selectedText);
+                control->SetSelectionVoid(pos - 1, pos + selectedText.Length() - 1);
+                int startLine = control->LineFromPosition(control->GetSelectionStart());
+                int endLine = control->LineFromPosition(control->GetSelectionEnd());
+                if(startLine == endLine)
+                {
+                    control->Home();
+                }
+                control->Tab();
+                control->SetEmptySelection(control->GetLineEndPosition(endLine));
+                control->NewLine();
+                control->BackTab();
+                control->InsertText(control->GetCurrentPos(), wxT("}"));
+                control->SetEmptySelection(control->GetLineEndPosition(startLine - 1));
+                control->NewLine();
+                control->InsertText(control->GetCurrentPos(), wxT("{"));
+                if(ch == _T('}'))
+                {
+                    control->SetEmptySelection(control->GetLineEndPosition(endLine + 2));
+                }
+                control->EndUndoAction();
+                return;
+            }
+        }
+    }
+
     // indent
     if (ch == _T('\n'))
     {
Index: src/sdk/cbstyledtextctrl.cpp
===================================================================
--- src/sdk/cbstyledtextctrl.cpp (revision 7582)
+++ src/sdk/cbstyledtextctrl.cpp (working copy)
@@ -123,6 +123,8 @@
 
 void cbStyledTextCtrl::OnKeyDown(wxKeyEvent& event)
 {
+    m_lastSelectedText = GetSelectedText();
+
     switch (event.GetKeyCode())
     {
         case WXK_TAB:
Index: src/sdk/resources/editor_configuration.xrc
===================================================================
--- src/sdk/resources/editor_configuration.xrc (revision 7582)
+++ src/sdk/resources/editor_configuration.xrc (working copy)
@@ -154,7 +154,7 @@
  </object>
  <object class="sizeritem">
  <object class="wxStaticBoxSizer">
- <label>End-of-line options</label>
+ <label>Highlight occurrences</label>
  <orient>wxVERTICAL</orient>
  <object class="sizeritem">
  <object class="wxFlexGridSizer">
@@ -162,64 +162,54 @@
  <vgap>4</vgap>
  <hgap>4</hgap>
  <object class="sizeritem">
- <object class="wxCheckBox" name="chkShowEOL">
- <label>Show end-of-line chars</label>
+ <object class="wxCheckBox" name="chkHighlightOccurrences">
+ <label>Highlight occurrences</label>
+ <checked>1</checked>
  </object>
  <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
  </object>
  <object class="sizeritem">
- <object class="wxCheckBox" name="chkStripTrailings">
- <label>Strip trailing blanks</label>
+ <object class="wxCheckBox" name="chkHighlightOccurrencesCaseSensitive">
+ <label>Case sensitive</label>
  <checked>1</checked>
  </object>
- <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <flag>wxLEFT|wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <border>10</border>
  </object>
  <object class="sizeritem">
- <object class="wxCheckBox" name="chkEnsureFinalEOL">
- <label>End files with blank line</label>
+ <object class="wxCheckBox" name="chkHighlightOccurrencesWholeWord">
+ <label>Whole words only</label>
+ <checked>1</checked>
  </object>
- <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <flag>wxLEFT|wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <border>10</border>
  </object>
  <object class="sizeritem">
- <object class="wxCheckBox" name="chkEnsureConsistentEOL">
- <label>Ensure consistent EOLs</label>
- </object>
- <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
- </object>
- <object class="sizeritem">
  <object class="wxBoxSizer">
  <object class="sizeritem">
- <object class="wxStaticText" name="ID_STATICTEXT2">
- <label>End-of-line mode:</label>
+ <object class="wxStaticText" name="stHighlightColour">
+ <label>Highlight colour</label>
  </object>
- <flag>wxTOP|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
- <border>4</border>
+ <flag>wxRIGHT|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL</flag>
+ <border>5</border>
  </object>
  <object class="sizeritem">
- <object class="wxComboBox" name="cmbEOLMode">
- <content>
- <item>CR LF</item>
- <item>CR</item>
- <item>LF</item>
- </content>
- <style>wxCB_READONLY</style>
+ <object class="wxButton" name="btnHighlightColour">
+ <label>...</label>
+ <bg>#FF0000</bg>
  </object>
- <flag>wxLEFT|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
- <border>16</border>
- <option>1</option>
+ <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
  </object>
  </object>
- <flag>wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
- <option>1</option>
+ <flag>wxLEFT|wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <border>10</border>
  </object>
  </object>
  <flag>wxALL|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
  <border>4</border>
- <option>1</option>
  </object>
  </object>
  <flag>wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
- <border>4</border>
  <option>1</option>
  </object>
  <object class="sizeritem">
@@ -260,17 +250,23 @@
  <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
  </object>
  <object class="sizeritem">
- <object class="wxCheckBox" name="chkShowIndentGuides">
- <label>Show indentation guides</label>
+ <object class="wxCheckBox" name="chkBraceSmartIndent">
+ <label>Brace Smart Indent</label>
  </object>
  <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
  </object>
  <object class="sizeritem">
- <object class="wxCheckBox" name="chkBraceSmartIndent">
- <label>Brace Smart Indent</label>
+ <object class="wxCheckBox" name="chkSelectionBraceCompletion">
+ <label>Selection brace completion</label>
  </object>
  <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
  </object>
+ <object class="sizeritem">
+ <object class="wxCheckBox" name="chkShowIndentGuides">
+ <label>Show indentation guides</label>
+ </object>
+ <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
+ </object>
  </object>
  <flag>wxALL|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
  <border>4</border>
@@ -281,7 +277,7 @@
  </object>
  <object class="sizeritem">
  <object class="wxStaticBoxSizer">
- <label>Highlight occurrences</label>
+ <label>End-of-line options</label>
  <orient>wxVERTICAL</orient>
  <object class="sizeritem">
  <object class="wxFlexGridSizer">
@@ -289,54 +285,64 @@
  <vgap>4</vgap>
  <hgap>4</hgap>
  <object class="sizeritem">
- <object class="wxCheckBox" name="chkHighlightOccurrences">
- <label>Highlight occurrences</label>
- <checked>1</checked>
+ <object class="wxCheckBox" name="chkShowEOL">
+ <label>Show end-of-line chars</label>
  </object>
  <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
  </object>
  <object class="sizeritem">
- <object class="wxCheckBox" name="chkHighlightOccurrencesCaseSensitive">
- <label>Case sensitive</label>
+ <object class="wxCheckBox" name="chkStripTrailings">
+ <label>Strip trailing blanks</label>
  <checked>1</checked>
  </object>
- <flag>wxLEFT|wxALIGN_LEFT|wxALIGN_TOP</flag>
- <border>10</border>
+ <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
  </object>
  <object class="sizeritem">
- <object class="wxCheckBox" name="chkHighlightOccurrencesWholeWord">
- <label>Whole words only</label>
- <checked>1</checked>
+ <object class="wxCheckBox" name="chkEnsureFinalEOL">
+ <label>End files with blank line</label>
  </object>
- <flag>wxLEFT|wxALIGN_LEFT|wxALIGN_TOP</flag>
- <border>10</border>
+ <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
  </object>
  <object class="sizeritem">
+ <object class="wxCheckBox" name="chkEnsureConsistentEOL">
+ <label>Ensure consistent EOLs</label>
+ </object>
+ <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
+ </object>
+ <object class="sizeritem">
  <object class="wxBoxSizer">
  <object class="sizeritem">
- <object class="wxStaticText" name="stHighlightColour">
- <label>Highlight colour</label>
+ <object class="wxStaticText" name="ID_STATICTEXT2">
+ <label>End-of-line mode:</label>
  </object>
- <flag>wxRIGHT|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL</flag>
- <border>5</border>
+ <flag>wxTOP|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <border>4</border>
  </object>
  <object class="sizeritem">
- <object class="wxButton" name="btnHighlightColour">
- <label>...</label>
- <bg>#FF0000</bg>
+ <object class="wxComboBox" name="cmbEOLMode">
+ <content>
+ <item>CR LF</item>
+ <item>CR</item>
+ <item>LF</item>
+ </content>
+ <style>wxCB_READONLY</style>
  </object>
- <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <flag>wxLEFT|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <border>16</border>
+ <option>1</option>
  </object>
  </object>
- <flag>wxLEFT|wxALIGN_LEFT|wxALIGN_TOP</flag>
- <border>10</border>
+ <flag>wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <option>1</option>
  </object>
  </object>
  <flag>wxALL|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
  <border>4</border>
+ <option>1</option>
  </object>
  </object>
  <flag>wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <border>4</border>
  <option>1</option>
  </object>
  </object>


Offline Alpha

  • Developer
  • Lives here!
  • *****
  • Posts: 1513
Re: Events
« Reply #23 on: November 18, 2011, 12:17:16 am »
Out of curiosity, has anyone had the chance to try this?

Any comments or suggestions?

(Also, I am also still unsure of what keyboard shortcut(s) to (optionally) bind these functions to.  Of the vi documentation I read (assuming I understood correctly), it would require a key combination that does not correspond to any normal keyboard shortcuts.)

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9694
Re: Events
« Reply #24 on: November 18, 2011, 07:45:29 am »
Out of curiosity, has anyone had the chance to try this?
Its on my ToDo list, but I'm afraid I didn't find the time yet...
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: https://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: https://wiki.codeblocks.org/index.php?title=FAQ

Offline Alpha

  • Developer
  • Lives here!
  • *****
  • Posts: 1513
Re: Events
« Reply #25 on: November 19, 2011, 03:08:47 am »
Its on my ToDo list, but I'm afraid I didn't find the time yet...
OK, that is fine.

Changes in this patch:
  • Keyboard shortcut Alt-I added; if the next character typed is one of ' " ( ) [ ] < > { }, it is treated the same as if "Selection brace completion" is checked
  • Removed a bit more of redundant code

Submitted to BerliOS as Patch #3234.