News:

Accounts with zero posts and zero activity during the last months will be deleted periodically to fight SPAM!

Main Menu

BraceCompletion patch to improve Code Completion

Started by ollydbg, April 05, 2009, 04:17:44 PM

Previous topic - Next topic

ollydbg

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:

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]
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.

killerbot

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 !!!!!!!!!!!!

danselmi

#2
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.next.codeblocks.org/index.php/topic,9820.0.html) than to cc.

regards danselmi
spell checker plugin: [url="http://developer.berlios.de/projects/spellchecker/"]http://developer.berlios.de/projects/spellchecker/[/url]
nassi shneiderman plugin: [url="http://developer.berlios.de/projects/nassiplugin"]http://developer.berlios.de/projects/nassiplugin[/url]

killerbot

to have all references together (see also) : http://forums.next.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.

mandrav

Quote from: killerbot on April 05, 2009, 09:35:00 PM
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...

danselmi

#5
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

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>

spell checker plugin: [url="http://developer.berlios.de/projects/spellchecker/"]http://developer.berlios.de/projects/spellchecker/[/url]
nassi shneiderman plugin: [url="http://developer.berlios.de/projects/nassiplugin"]http://developer.berlios.de/projects/nassiplugin[/url]

killerbot

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.

danselmi

#7
Quoteok, this modification is even better I think
kudos to blueshake! I only moved the code around.

QuotePS : 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.

QuoteHowever I stumbled already on 1 issue !!
I tried to correct that (and updated my previous post).
spell checker plugin: [url="http://developer.berlios.de/projects/spellchecker/"]http://developer.berlios.de/projects/spellchecker/[/url]
nassi shneiderman plugin: [url="http://developer.berlios.de/projects/nassiplugin"]http://developer.berlios.de/projects/nassiplugin[/url]

killerbot

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.

Ceniza

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.

danselmi

#10
Quotethe 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.
spell checker plugin: [url="http://developer.berlios.de/projects/spellchecker/"]http://developer.berlios.de/projects/spellchecker/[/url]
nassi shneiderman plugin: [url="http://developer.berlios.de/projects/nassiplugin"]http://developer.berlios.de/projects/nassiplugin[/url]