Code::Blocks Forums

Developer forums (C::B DEVELOPMENT STRICTLY!) => Plugins development => Topic started by: DrewBoo on March 13, 2008, 01:03:20 am

Title: For your consideration: AStyle patch
Post by: DrewBoo on March 13, 2008, 01:03:20 am
I just uploaded patch 2405 to BerliOS.  This patch adds features to the AStyle plugin.

Comments, questions and complaints from anyone are welcome.

https://developer.berlios.de/patch/index.php?func=detailpatch&patch_id=2405&group_id=5358

Changes to AStyle:

Notes:

Affected Files:

The Patch: (it's small enough)
Code
Index: astyleplugin.cpp
===================================================================
--- astyleplugin.cpp (revision 4944)
+++ astyleplugin.cpp (working copy)
@@ -24,12 +24,25 @@
 #include <wx/xrc/xmlres.h>
 #include <wx/fs_zip.h>
 #include <wx/strconv.h>
+#include <wx/progdlg.h>
 #include "asstreamiterator.h"
 #include "cbstyledtextctrl.h"
 
 using std::istringstream;
 using std::string;
 
+namespace
+{
+ const int idCodeFormatterFile = wxNewId();
+ const int idCodeFormatterActiveFile = wxNewId();
+ const int idCodeFormatterProject = wxNewId();
+}
+
+BEGIN_EVENT_TABLE( AStylePlugin, cbPlugin )
+ EVT_MENU( idCodeFormatterActiveFile, AStylePlugin::OnFormatActiveFile )
+ EVT_MENU( idCodeFormatterProject, AStylePlugin::OnFormatProject )
+END_EVENT_TABLE()
+
 // this auto-registers the plugin
 
 namespace
@@ -78,6 +91,97 @@
     return dlg;
 }
 
+void AStylePlugin::BuildModuleMenu( const ModuleType type, wxMenu* menu, const FileTreeData* data )
+{
+ if ( !menu || !IsAttached() )
+ return;
+
+ switch ( type )
+ {
+ case mtEditorManager:
+ menu->AppendSeparator();
+ menu->Append( idCodeFormatterActiveFile, _( "Format This File (AStyle)" ), _( "Format the source code in the current file" ) );
+ break;
+
+ case mtProjectManager:
+ if ( data ) switch ( data->GetKind() )
+ {
+ case FileTreeData::ftdkProject:
+ menu->AppendSeparator();
+ menu->Append( idCodeFormatterProject, _( "Format This Project (AStyle)" ), _( "Format the source code in this project" ) );
+ break;
+
+ case FileTreeData::ftdkFile:
+ menu->AppendSeparator();
+ menu->Append( idCodeFormatterProject, _( "Format This File (AStyle)" ), _( "Format the source code in this file" ) );
+ break;
+
+ default:
+ // Do nothing.
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void AStylePlugin::OnFormatProject( wxCommandEvent& event )
+{
+ wxTreeCtrl *tree = Manager::Get()->GetProjectManager()->GetTree();
+
+ if ( NULL == tree )
+ return;
+
+ wxTreeItemId treeItem =  tree->GetSelection();
+
+ if ( false == treeItem.IsOk() )
+ return;
+
+ const FileTreeData *data = static_cast<FileTreeData*>( tree->GetItemData( treeItem ) );
+
+ if ( NULL == data )
+ return;
+
+ switch ( data->GetKind() )
+ {
+ case FileTreeData::ftdkProject:
+ {
+ cbProject* prj = data->GetProject();
+ wxProgressDialog progressDlg(_("Please wait"), _("Formatting..."), prj->GetFilesCount(), NULL, wxPD_CAN_ABORT|wxPD_AUTO_HIDE|wxPD_SMOOTH );
+ progressDlg.Show();
+ for ( int i = 0; i < prj->GetFilesCount(); ++i )
+ {
+ ProjectFile* pf = prj->GetFile( i );
+ wxString filename = pf->file.GetFullPath();
+
+ FileType fileType = FileTypeOf( filename );
+ if ( fileType == ftSource || fileType == ftHeader )
+ {
+ FormatFile( filename );
+ if ( false == progressDlg.Update( i, wxString("Formatting ") + pf->relativeFilename ) )
+ break;
+ }
+ }
+ }
+ break;
+
+ case FileTreeData::ftdkFile:
+ {
+ ProjectFile* f = data->GetProject()->GetFile( data->GetFileIndex() );
+ if ( f )
+ FormatFile( f->file.GetFullPath() );
+ }
+ break;
+ }
+}
+
+void AStylePlugin::OnFormatActiveFile( wxCommandEvent& event )
+{
+ Execute();
+}
+
 int AStylePlugin::Execute()
 {
     if (!IsAttached())
@@ -92,10 +196,96 @@
         return 0;
     }
 
+    FormatEditor( ed );
+}
+
+void AStylePlugin::FormatFile( const wxString &filename )
+{
+ cbEditor* ed = Manager::Get()->GetEditorManager()->IsBuiltinOpen( filename );
+
+ if ( ed )
+ {
+ // File is already open
+ FormatEditor( ed );
+ }
+ else
+ {
+ // File is not open.  We must open it.
+ ed = Manager::Get()->GetEditorManager()->Open( filename );
+
+ if ( ed )
+ {
+ bool changed = FormatEditor( ed );
+
+ if ( !changed )
+ {
+ // We opened a file and it didn't change.  Close it.
+ Manager::Get()->GetEditorManager()->Close( filename );
+ }
+ }
+ }
+}
+
+// Special code to compare strings which doesn't care
+// about spaces leading up to the EOL.
+static bool BuffersDiffer( const wxString &a, const wxString &b )
+{
+ const wxChar *aCurrent = a.c_str();
+ const wxChar *bCurrent = b.c_str();
+ const wxChar * const aEnd = aCurrent + a.Len();
+ const wxChar * const bEnd = bCurrent + b.Len();
+
+ while ( aCurrent != aEnd && bCurrent != bEnd )
+ {
+ if ( *aCurrent != *bCurrent )
+ {
+ // Check for varying space at EOL
+ while ( *aCurrent == ' ' || *aCurrent == '\t' )
+ {
+ if ( ++aCurrent == aEnd )
+ break;
+ }
+ while ( *bCurrent == ' ' || *bCurrent == '\t' )
+ {
+ if ( ++bCurrent == bEnd )
+ break;
+ }
+
+ // Make sure it was at EOL
+ if ( ( *aCurrent != '\r' && *aCurrent != '\n' ) || ( *bCurrent != '\r' && *bCurrent != '\n' ) )
+ return true;
+ }
+
+ ++aCurrent;
+ ++bCurrent;
+ }
+
+ while ( aCurrent != aEnd )
+ {
+ if ( *aCurrent != ' ' && *aCurrent != '\t' )
+ {
+ return true;
+ }
+
+ }
+
+ while ( bCurrent != bEnd )
+ {
+ if ( *bCurrent != ' ' && *bCurrent != '\t' )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool AStylePlugin::FormatEditor( cbEditor *ed )
+{
     if (ed->GetControl()->GetReadOnly())
     {
         cbMessageBox(_("The file is read-only"), _("Error"), wxICON_ERROR);
-        return 0;
+        return false;
     }
 
     wxString edText(ed->GetControl()->GetText());
@@ -167,20 +357,24 @@
 
     int pos = ed->GetControl()->GetCurrentPos();
 
-    ed->GetControl()->BeginUndoAction();
-    ed->GetControl()->SetText(formattedText);
+    bool changed = BuffersDiffer( formattedText, edText );
 
-    for (std::vector<int>::const_iterator i = new_bookmark.begin(); i != new_bookmark.end(); ++i)
-    {
-        ed->ToggleBookmark(*i);
-    }
+ if ( changed )
+ {
+ ed->GetControl()->BeginUndoAction();
+ ed->GetControl()->SetText(formattedText);
 
-    ed->GetControl()->EndUndoAction();
+ for (std::vector<int>::const_iterator i = new_bookmark.begin(); i != new_bookmark.end(); ++i)
+ {
+ ed->ToggleBookmark(*i);
+ }
 
-    ed->GetControl()->GotoPos(pos);
-    ed->SetModified(true);
+ ed->GetControl()->EndUndoAction();
+ ed->GetControl()->GotoPos(pos);
+ ed->SetModified(true);
+ }
 
     wxSetCursor(wxNullCursor);
 
-    return 0;
+ return changed;
 }
Index: astyleplugin.h
===================================================================
--- astyleplugin.h (revision 4944)
+++ astyleplugin.h (working copy)
@@ -28,9 +28,18 @@
     int Configure();
     int GetConfigurationGroup() const { return cgEditor; }
     cbConfigurationPanel* GetConfigurationPanel(wxWindow* parent);
+ void BuildModuleMenu( const ModuleType type, wxMenu* menu, const FileTreeData* data = 0 );
     int Execute();
+
+ void OnFormatActiveFile( wxCommandEvent& event );
+ void OnFormatProject( wxCommandEvent& event );
+ void FormatFile( const wxString &filename );
+ bool FormatEditor( cbEditor *ed );
+
     void OnAttach(); // fires when the plugin is attached to the application
     void OnRelease(bool appShutDown); // fires when the plugin is released from the application
+
+ DECLARE_EVENT_TABLE()
 };
 
 #endif // ASTYLEPLUGIN_H

Title: Re: For your consideration: AStyle patch
Post by: JGM on March 13, 2008, 01:23:53 am
nice work! :D
Title: Re: For your consideration: AStyle patch
Post by: Ceniza on March 13, 2008, 12:53:43 pm
Looks good to me, but a bit cruel for huge projects. Just imagine running that on the Code::Blocks project file (or try it if you prefer :P).

I made a few minor changes to the patch (NULL/false comparisons to !, NULL to 0, removal of warnings), but the functionality remains untouched. Nice job, and thank you for it.

Patch applied.
Title: Re: For your consideration: AStyle patch
Post by: DrewBoo on March 13, 2008, 04:09:36 pm
Looks good to me, but a bit cruel for huge projects. Just imagine running that on the Code::Blocks project file (or try it if you prefer :P).

Yeah, I didn't have any huge projects to test it on, but a tiny buzzing in the back of my brain told me to add the progress dialog with the cancel button.

I made a few minor changes to the patch (NULL/false comparisons to !, NULL to 0, removal of warnings), but the functionality remains untouched. Nice job, and thank you for it.

Patch applied.

Absolutely my pleasure, Ceniza.

What compiler and warning level were you using when you got compile warnings?  I could try to match that next time I'm feeling ambitious.

Is there a coding style guideline that I could look at so my code was more consistent with the rest of the codebase?

Title: Re: For your consideration: AStyle patch
Post by: JGM on March 13, 2008, 04:39:17 pm
Is there a coding style guideline that I could look at so my code was more consistent with the rest of the codebase?

http://wiki.codeblocks.org/index.php?title=Coding_style
Title: Re: For your consideration: AStyle patch
Post by: Ceniza on March 13, 2008, 06:04:27 pm
What compiler and warning level were you using when you got compile warnings?  I could try to match that next time I'm feeling ambitious.

g++ 4.2.1-dw2 (mingw32-2). I haven't checked, but the warning level must be -Wall. I just compiled it using the Code::Blocks project file, so it's whatever it uses.

Is there a coding style guideline that I could look at so my code was more consistent with the rest of the codebase?

JGM gave you the link already. If you can follow it, the better. I haven't even checked that link.