Developer forums (C::B DEVELOPMENT STRICTLY!) > Plugins development
For your consideration: AStyle patch
DrewBoo:
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:
* New context menu in Code::Blocks editor to format the currently active file
* New context menu in Code::Blocks Project Manager to format any source file
* New context menu in Code::Blocks Project Manager to format entire project :D
* If formatting doesn't change the file, the contents are not modified
* If formatting only changes the spacing at the end of lines, the contents are not modified
Notes:
* When formatting an entire project, I strived to create familiar behavior, so -- modeling the "Replace in Files" dialog -- files that are changed are automatically opened and modified in the editor, but not saved. Files that are not changed are not opened.
* Formatting a project uses a progress dialog, with a working cancel button
* Formatting a project won't touch files that aren't recognized as source or header files
* As it turns out, AStyle can at times add space to the end of a line. This could have created unexpected behavior when used in conjunction with Code::Blocks' integrated "Strip Trailing Blanks" feature. This is why the plugin now, when formatting a file, will not touch the file if the only changes it makes involve trailing blanks. Without this feature, you could format an entire project, save all the files (stripping the blanks), and if you tried formatting the project again, all project files would get opened and modified again.
Affected Files:
* astyleplugin.h
* astyleplugin.cpp
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
--- End code ---
JGM:
nice work! :D
Ceniza:
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.
DrewBoo:
--- Quote from: 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).
--- End quote ---
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.
--- Quote from: Ceniza on March 13, 2008, 12:53:43 pm ---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.
--- End quote ---
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?
JGM:
--- Quote from: DrewBoo on March 13, 2008, 04:09:36 pm ---Is there a coding style guideline that I could look at so my code was more consistent with the rest of the codebase?
--- End quote ---
http://wiki.codeblocks.org/index.php?title=Coding_style
Navigation
[0] Message Index
[#] Next page
Go to full version