Author Topic: BraceCompletion patch to improve Code Completion  (Read 14356 times)

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6034
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
BraceCompletion patch to improve Code Completion
« on: April 05, 2009, 04:17:44 pm »
Hi, blueshake has just built a patch to do BraceCompletion. I have applied in my local copy and tested it. It works Great! Thanks blueshake for your patch. (He has some difficulty to post these code, So, I wrote this post instead).

Here is his patch:
Code
Index: src/plugins/codecompletion/codecompletion.cpp
===================================================================
--- src/plugins/codecompletion/codecompletion.cpp (revision 5519)
+++ src/plugins/codecompletion/codecompletion.cpp (working copy)
@@ -1876,6 +1876,17 @@
 //    else if (event.GetEventType() == wxEVT_SCI_MODIFIED)
 //        Manager::Get()->GetLogManager()->DebugLog(_T("wxEVT_SCI_MODIFIED"));
 
+//do this when the [ { ( " ' were typed
+
+    if (event.GetEventType() == wxEVT_SCI_CHARADDED)
+        {
+            m_timerCodeCompletion.Stop();
+            wxChar ch = event.GetKey();
+            DoBraceCompletion(control, ch);
+            //event.Skip();
+        }
+/////////////////////////////////
+
     if (event.GetEventType() == wxEVT_SCI_CHARADDED &&
         !control->AutoCompActive()) // not already active autocompletion
     {
@@ -1886,9 +1897,10 @@
         int wordstart = control->WordStartPosition(pos, true);
 
         // if more than two chars have been typed, invoke CC
+        ////////////////////////////////
         int autoCCchars = cfg->ReadInt(_T("/auto_launch_chars"), 4);
         bool autoCC = cfg->ReadBool(_T("/auto_launch"), true) &&
-                    pos - wordstart >= autoCCchars;
+                   pos - wordstart >= autoCCchars;
 
         // update calltip highlight while we type
         if (control->CallTipActive())
@@ -2008,3 +2020,77 @@
 {
     // nothing for now
 }
+
+void CodeCompletion::DoBraceCompletion(cbStyledTextCtrl* control, const wxChar& ch)
+{
+    int pos = control->GetCurrentPos();
+    int style = control->GetStyleAt(pos);
+    if (style == wxSCI_C_COMMENT || style == wxSCI_C_COMMENTLINE)
+        {
+            return;
+        }
+    if (ch == _T('\'') )//&& style != || ch == _T('"') )
+        {
+            if (control->GetCharAt(pos) == ch)
+            {
+                control->DeleteBack();
+                control->GotoPos(pos);
+                return;
+            }
+            else
+            {
+                if (style == wxSCI_C_STRING)
+                    return;
+                control->AddText(ch);
+                control->GotoPos(pos);
+                return;
+            }
+        }
+    if (ch == _T('"'))
+        {
+            if (control->GetCharAt(pos) == ch)
+            {
+                control->DeleteBack();
+                control->GotoPos(pos);
+                return;
+            }
+            else
+            {
+                if (style == wxSCI_C_CHARACTER)
+                    return;
+                control->AddText(ch);
+                control->GotoPos(pos);
+                return;
+            }
+        }
+    if (style == wxSCI_C_STRING || style == wxSCI_C_CHARACTER)
+        return;
+    wxString leftBrace(_T("([{"));
+    wxString rightBrace(_T(")]}"));
+    int index = leftBrace.find(ch);
+        if (index != wxNOT_FOUND)
+            {
+                control->AddText(rightBrace.GetChar(index));
+                control->GotoPos(pos);
+                if (ch == _T('{'))
+                {
+                    control->NewLine();
+                    control->GotoPos(pos);
+                    return;
+                }
+            }
+        else
+            {
+                index = rightBrace.find(ch);
+                if (index != wxNOT_FOUND)
+                    {
+                        if (control->GetCharAt(pos) == ch)
+                        {
+                            control->DeleteBack();
+                            control->GotoPos(pos);
+                            return;
+                        }
+
+                    }
+            }
+}
Index: src/plugins/codecompletion/codecompletion.h
===================================================================
--- src/plugins/codecompletion/codecompletion.h (revision 5519)
+++ src/plugins/codecompletion/codecompletion.h (working copy)
@@ -115,7 +115,7 @@
         void OnStartParsingFunctions(wxTimerEvent& event);
         void OnFunction(wxCommandEvent& event);
         void ParseFunctionsAndFillToolbar(bool force = false);
-
+        void DoBraceCompletion(cbStyledTextCtrl* control, const wxChar& ch);
         int m_PageIndex;
         bool m_InitDone;
 



Thanks for testing! :D See the screen shot.

After enter "{", another "}" will be automatically added. So does (  [  "




[attachment deleted by admin]
« Last Edit: April 05, 2009, 04:22:59 pm by ollydbg »
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 killerbot

  • Administrator
  • Lives here!
  • *****
  • Posts: 5517
Re: BraceCompletion patch to improve Code Completion
« Reply #1 on: April 05, 2009, 05:31:58 pm »
I have applied it in my local copy, a little bit modified (indentation issues in the patch, not in the meaning of the new code ;-) ).
Seems to work nice.
I will test it a in my production system, when I don't find any shot term issues, I will commit this.

Thanks for the contribution !!!!!!!!!!!!

Offline danselmi

  • Developer
  • Almost regular
  • *****
  • Posts: 205
Re: BraceCompletion patch to improve Code Completion
« Reply #2 on: April 05, 2009, 07:55:19 pm »
I also applied is on my local copy.

1.: It works great as long as you edit c/c++ sources. I also use cb to edit other sources, where the ' is used to access attributes. I think, we have to check which lexer is configured.
2.: I believe that this code better suits to "smart indenting" (as Ceniza mentioned int this post http://forums.codeblocks.org/index.php/topic,9820.0.html) than to cc.

regards danselmi
« Last Edit: April 05, 2009, 08:44:55 pm by danselmi »

Offline killerbot

  • Administrator
  • Lives here!
  • *****
  • Posts: 5517
Re: BraceCompletion patch to improve Code Completion
« Reply #3 on: April 05, 2009, 09:35:00 pm »
to have all references together (see also) : http://forums.codeblocks.org/index.php/topic,8803.0.html


Though I think that adding to CC could be the first step until a more fundamental refactoring can be done.

Offline mandrav

  • Project Leader
  • Administrator
  • Lives here!
  • *****
  • Posts: 4315
    • Code::Blocks IDE
Re: BraceCompletion patch to improve Code Completion
« Reply #4 on: April 06, 2009, 09:54:26 am »
Though I think that adding to CC could be the first step until a more fundamental refactoring can be done.

Agreed for the refactoring but until then, smart-indenting is the place to put it in.
Be patient!
This bug will be fixed soon...

Offline danselmi

  • Developer
  • Almost regular
  • *****
  • Posts: 205
Re: BraceCompletion patch to improve Code Completion
« Reply #5 on: April 06, 2009, 11:42:30 pm »
I modified your patch:
  • added option in editor configuration dialog
  • moved from cc to smart-indenting code
  • gets only called when lexer is set to cpp or d language
Code
Index: sdk/cbeditor.cpp
===================================================================
--- sdk/cbeditor.cpp (revision 5539)
+++ sdk/cbeditor.cpp (working copy)
@@ -221,6 +221,135 @@
         return -1;
     }
 
+    bool IsComment( int style )
+    {
+        cbStyledTextCtrl* control = m_pOwner->GetControl();
+        switch ( control->GetLexer() )
+        {
+            case wxSCI_LEX_CPP:
+                return  style == wxSCI_C_COMMENT ||
+                        style == wxSCI_C_COMMENTLINE ||
+                        style == wxSCI_C_COMMENTDOC ||
+                        style == wxSCI_C_COMMENTDOCKEYWORD ||
+                        style == wxSCI_C_COMMENTDOCKEYWORDERROR ||
+                        style == wxSCI_C_COMMENTLINEDOC;
+            case wxSCI_LEX_D:
+                return  style == wxSCI_D_COMMENT ||
+                        style == wxSCI_D_COMMENTLINE ||
+                        style == wxSCI_D_COMMENTDOC ||
+                        style == wxSCI_D_COMMENTDOCKEYWORD ||
+                        style == wxSCI_D_COMMENTDOCKEYWORDERROR ||
+                        style == wxSCI_D_COMMENTLINEDOC;
+            default:
+                return false;
+        }
+        return false;
+    }
+    bool IsPreprocessor( int style )
+    {
+        cbStyledTextCtrl* control = m_pOwner->GetControl();
+        if ( control->GetLexer() == wxSCI_LEX_CPP )
+            return  style == wxSCI_C_PREPROCESSOR;
+        return false;
+    }
+    bool IsCharacterOrString( int  style )
+    {
+        cbStyledTextCtrl* control = m_pOwner->GetControl();
+        switch ( control->GetLexer() )
+        {
+            case wxSCI_LEX_CPP:
+                return style == wxSCI_C_STRING || style == wxSCI_C_CHARACTER;
+            case wxSCI_LEX_D:
+                return style == wxSCI_D_STRING || style == wxSCI_D_CHARACTER;
+            default:
+                return false;
+        }
+        return false;
+    }
+    bool IsCharacter( int  style )
+    {
+        cbStyledTextCtrl* control = m_pOwner->GetControl();
+        switch ( control->GetLexer() )
+        {
+            case wxSCI_LEX_CPP:
+                return style == wxSCI_C_CHARACTER;
+            case wxSCI_LEX_D:
+                return style == wxSCI_D_CHARACTER;
+            default:
+                return false;
+        }
+        return false;
+    }
+    void DoBraceCompletion(const wxChar& ch)
+    {
+        cbStyledTextCtrl* control = m_pOwner->GetControl();
+        int pos = control->GetCurrentPos();
+        int style = control->GetStyleAt(pos);
+        if ( IsComment(style) || IsPreprocessor(style) )
+            return;
+        if ( ch == _T('\'') )
+        {
+            if ( control->GetCharAt(pos) == ch && pos > 1 && control->GetCharAt(pos-2) != _T('\\') )
+            {
+                control->DeleteBack();
+                control->GotoPos(pos);
+            }
+            else
+            {
+                if ( control->GetCharAt(pos-2) == _T('\\') || IsCharacterOrString(style) )
+                    return;
+                control->AddText(ch);
+                control->GotoPos(pos);
+            }
+            return;
+        }
+        if ( ch == _T('"') )
+        {
+            if (control->GetCharAt(pos) == ch && pos > 1 && control->GetCharAt(pos-2) != _T('\\') )
+            {
+                control->DeleteBack();
+                control->GotoPos(pos);
+            }
+            else
+            {
+                if ( control->GetCharAt(pos-2) == _T('\\') || IsCharacter(style) )
+                    return;
+                control->AddText(ch);
+                control->GotoPos(pos);
+            }
+            return;
+        }
+        if ( IsCharacterOrString(style) )
+            return;
+        wxString leftBrace(_T("([{"));
+        wxString rightBrace(_T(")]}"));
+        int index = leftBrace.find(ch);
+        if (index != wxNOT_FOUND)
+        {
+            control->AddText(rightBrace.GetChar(index));
+            control->GotoPos(pos);
+            if (ch == _T('{'))
+            {
+                control->NewLine();
+                control->GotoPos(pos);
+                return;
+            }
+        }
+        else
+        {
+            index = rightBrace.find(ch);
+            if (index != wxNOT_FOUND)
+            {
+                if (control->GetCharAt(pos) == ch)
+                {
+                    control->DeleteBack();
+                    control->GotoPos(pos);
+                    return;
+                }
+            }
+        }
+    }
+
     /** Strip Trailing Blanks before saving */
     void StripTrailingSpaces()
     {
@@ -2787,6 +2916,13 @@
         }
     }
 
+    bool braceCompletion = Manager::Get()->GetConfigManager(_T("editor"))->ReadBool(_T("/brace_completion"), true);
+    if ( braceCompletion )
+    {
+        if ( control->GetLexer() == wxSCI_LEX_CPP || control->GetLexer() == wxSCI_LEX_D )
+            m_pData->DoBraceCompletion( ch );
+    }
+
     OnScintillaEvent(event);
 }
 
Index: sdk/editorconfigurationdlg.cpp
===================================================================
--- sdk/editorconfigurationdlg.cpp (revision 5539)
+++ sdk/editorconfigurationdlg.cpp (working copy)
@@ -106,6 +106,7 @@
 
     XRCCTRL(*this, "chkAutoIndent", wxCheckBox)->SetValue(cfg->ReadBool(_T("/auto_indent"), true));
     XRCCTRL(*this, "chkSmartIndent", wxCheckBox)->SetValue(cfg->ReadBool(_T("/smart_indent"), true));
+    XRCCTRL(*this, "chkBraceCompletion", wxCheckBox)->SetValue(cfg->ReadBool(_T("/brace_completion"), true));
     XRCCTRL(*this, "chkUseTab", wxCheckBox)->SetValue(cfg->ReadBool(_T("/use_tab"), false));
     m_EnableScrollWidthTracking = cfg->ReadBool(_T("/margin/scroll_width_tracking"), false);
     XRCCTRL(*this, "chkScrollWidthTracking", wxCheckBox)->SetValue(m_EnableScrollWidthTracking);
@@ -863,6 +864,7 @@
 
         cfg->Write(_T("/auto_indent"),          XRCCTRL(*this, "chkAutoIndent", wxCheckBox)->GetValue());
         cfg->Write(_T("/smart_indent"),         XRCCTRL(*this, "chkSmartIndent", wxCheckBox)->GetValue());
+        cfg->Write(_T("/brace_completion"),     XRCCTRL(*this, "chkBraceCompletion", wxCheckBox)->GetValue());
         cfg->Write(_T("/use_tab"),              XRCCTRL(*this, "chkUseTab", wxCheckBox)->GetValue());
         cfg->Write(_T("/show_indent_guides"),   XRCCTRL(*this, "chkShowIndentGuides", wxCheckBox)->GetValue());
         cfg->Write(_T("/tab_indents"),          XRCCTRL(*this, "chkTabIndents", wxCheckBox)->GetValue());
Index: sdk/resources/editor_configuration.xrc
===================================================================
--- sdk/resources/editor_configuration.xrc (revision 5539)
+++ sdk/resources/editor_configuration.xrc (working copy)
@@ -275,6 +275,13 @@
                               <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
                             </object>
                             <object class="sizeritem">
+                              <object class="wxCheckBox" name="chkBraceCompletion">
+                                <label>Brace completion</label>
+                                <checked>1</checked>
+                              </object>
+                              <flag>wxALIGN_LEFT|wxALIGN_TOP</flag>
+                            </object>
+                            <object class="sizeritem">
                               <object class="wxCheckBox" name="chkBackspaceUnindents">
                                 <label>Backspace unindents</label>
                                 <checked>1</checked>

« Last Edit: April 22, 2009, 02:02:20 am by danselmi »

Offline killerbot

  • Administrator
  • Lives here!
  • *****
  • Posts: 5517
Re: BraceCompletion patch to improve Code Completion
« Reply #6 on: April 08, 2009, 09:07:00 am »
ok, this modification is even better I think :-)

However I stumbled already on 1 issue !!

When you use " within a set of "" :

Example :

std::string Test = ""     <--------------- after i typed the first "

then i start typing in bewteen the ""

std::string Test = "This is "   <-------------------- all still ok

std::string Test = "This is \""   <---------- the \" will trigger things to go wrong
  it changes into : std::string Test = "This is \"  <------------- NOT ok

so I continue to type :
std::string Test = "This is \"my\"
 turns in to : std::string Test = "This is \"my\""  <----------- which is ok again

and I type some more :

std::string Test = "This is \"my\" test";  <--- ok : syntax correct

Now let's add also \"\" around the is (so not extending the ones around 'my') :

When I type the first part of it I get :
std::string Test = "This \""is \"my\" test"
where it should have been : std::string Test = "This \"is \"my\" test"

and when I type the end part the same thing occurs
std::string Test = "This \""is\"" \"my\" test"

So basically, when the " is escaped (\) don't do the special stuff ;-)


PS : I think it should also be active for :
 - C language (or is that part of the CPP lexer)
 - java code/lexer


PS2 : this evening I will apply the modified patch in my private build and test. In case of applying to the trunk I will now work based upon the modified patch, with the setting to enable/disable the functionality.

Offline danselmi

  • Developer
  • Almost regular
  • *****
  • Posts: 205
Re: BraceCompletion patch to improve Code Completion
« Reply #7 on: April 08, 2009, 11:22:36 pm »
Quote
ok, this modification is even better I think
kudos to blueshake! I only moved the code around.

Quote
PS : I think it should also be active for :
 - C language (or is that part of the CPP lexer)
Yes, C language is part of C++. Scintilla has no special lexer for java so the cpp lexer can be used to highlight java sources (adjust the lexer configuration "lexer_cpp.xml"). If scintilla is configured to use the cpp lexer for java sources then BraceCompletion will also work for that.

Quote
However I stumbled already on 1 issue !!
I tried to correct that (and updated my previous post).
« Last Edit: April 10, 2009, 02:10:44 pm by danselmi »

Offline killerbot

  • Administrator
  • Lives here!
  • *****
  • Posts: 5517
Re: BraceCompletion patch to improve Code Completion
« Reply #8 on: April 12, 2009, 01:19:02 pm »
I have updated my test build with the updated patch code.
Everything still is fine :-)

The first issue I mentioned is solved, but the next issues still remain.

Quote
std::string Test = "This is \"my\" test";  <--- ok : syntax correct

Now let's add also \"\" around the is (so not extending the ones around 'my') :

When I type the first part of it I get :
std::string Test = "This \""is \"my\" test"
where it should have been : std::string Test = "This \"is \"my\" test"

and when I type the end part the same thing occurs
std::string Test = "This \""is\"" \"my\" test"

Most probably to solve this, the character in front should be checked, and when that is a '\' the code should stop issuing the completion part.

Offline Ceniza

  • Developer
  • Lives here!
  • *****
  • Posts: 1441
    • CenizaSOFT
Re: BraceCompletion patch to improve Code Completion
« Reply #9 on: April 12, 2009, 03:52:01 pm »
What about using current style information? If the double quote is typed inside a piece of text that is already marked as a string, do not complete. Comments could also be subject to this criteria. Just in case, by "current style information" I mean the style applied by Scintilla's lexer in the editor. No checking of previous characters required.

Offline danselmi

  • Developer
  • Almost regular
  • *****
  • Posts: 205
Re: BraceCompletion patch to improve Code Completion
« Reply #10 on: April 22, 2009, 11:28:08 pm »
Quote
the character in front should be checked, and when that is a '\' the code should stop issuing the completion part.
I updated my previous post and submitted the patch at berlios. patch id: 2746.

I also played around with the style information. It is not as easy as I expected: The style information reflects the state just after adding the character which triggers the BraceCompletion. So there are also checks needed about the style or character before the current position.
« Last Edit: April 24, 2009, 12:42:16 am by danselmi »