diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp
index c0a3b89ca..4c22ecc9b 100644
--- a/src/tools/ecode/ecode.cpp
+++ b/src/tools/ecode/ecode.cpp
@@ -3448,7 +3448,8 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe
{ "refresh", 0xf064 },
{ "hearth-pulse", 0xee10 },
{ "add", 0xea12 },
- { "hammer", 0xedee } };
+ { "hammer", 0xedee },
+ { "eraser", 0xec9e } };
for ( const auto& icon : icons )
iconTheme->add( UIGlyphIcon::New( icon.first, iconFont, icon.second ) );
diff --git a/src/tools/ecode/projectbuild.cpp b/src/tools/ecode/projectbuild.cpp
index 74b40e66f..f12a8b9a3 100644
--- a/src/tools/ecode/projectbuild.cpp
+++ b/src/tools/ecode/projectbuild.cpp
@@ -103,11 +103,49 @@ ProjectBuildManager::~ProjectBuildManager() {
Sys::sleep( Milliseconds( 0.1f ) );
}
-ProjectBuildCommandsRes ProjectBuildManager::run( const std::string& buildName,
- const ProjectBuildi18nFn& i18n,
- const std::string& buildType,
- const ProjectBuildProgressFn& progressFn,
- const ProjectBuildDoneFn& doneFn ) {
+ProjectBuildCommandsRes ProjectBuildManager::generateBuildCommands( const std::string& buildName,
+ const ProjectBuildi18nFn& i18n,
+ const std::string& buildType ) {
+ if ( !mLoaded )
+ return { i18n( "project_build_not_loaded", "No project build loaded!" ) };
+
+ const auto& buildIt = mBuilds.find( buildName );
+
+ if ( buildIt == mBuilds.end() )
+ return { i18n( "build_name_not_found", "Build name not found!" ) };
+
+ const auto& build = buildIt->second;
+
+ if ( !build.mBuildTypes.empty() && buildType.empty() )
+ return { i18n( "build_type_required", "Build type must be set!" ) };
+
+ std::string currentOS = String::toLower( Sys::getPlatform() );
+
+ if ( !build.isOSSupported( currentOS ) )
+ return {
+ i18n( "build_os_not_supported", "Operating System not supported for this build!" ) };
+
+ std::string nproc = String::format( "%d", Sys::getCPUCount() );
+ ProjectBuildCommandsRes res;
+
+ for ( const auto& step : build.mBuild ) {
+ ProjectBuildCommand buildCmd( step, build.mEnvs );
+ replaceVar( buildCmd, VAR_OS, currentOS );
+ replaceVar( buildCmd, VAR_NPROC, nproc );
+ if ( !buildType.empty() )
+ replaceVar( buildCmd, VAR_BUILD_TYPE, buildType );
+ buildCmd.config = build.mConfig;
+ res.cmds.emplace_back( std::move( buildCmd ) );
+ }
+
+ return res;
+}
+
+ProjectBuildCommandsRes ProjectBuildManager::build( const std::string& buildName,
+ const ProjectBuildi18nFn& i18n,
+ const std::string& buildType,
+ const ProjectBuildProgressFn& progressFn,
+ const ProjectBuildDoneFn& doneFn ) {
ProjectBuildCommandsRes res = generateBuildCommands( buildName, i18n, buildType );
if ( !res.isValid() )
return res;
@@ -123,6 +161,64 @@ ProjectBuildCommandsRes ProjectBuildManager::run( const std::string& buildName,
return res;
};
+ProjectBuildCommandsRes ProjectBuildManager::generateCleanCommands( const std::string& buildName,
+ const ProjectBuildi18nFn& i18n,
+ const std::string& buildType ) {
+ if ( !mLoaded )
+ return { i18n( "project_build_not_loaded", "No project build loaded!" ) };
+
+ const auto& buildIt = mBuilds.find( buildName );
+
+ if ( buildIt == mBuilds.end() )
+ return { i18n( "build_name_not_found", "Build name not found!" ) };
+
+ const auto& build = buildIt->second;
+
+ if ( !build.mBuildTypes.empty() && buildType.empty() )
+ return { i18n( "build_type_required", "Build type must be set!" ) };
+
+ std::string currentOS = String::toLower( Sys::getPlatform() );
+
+ if ( !build.isOSSupported( currentOS ) )
+ return {
+ i18n( "build_os_not_supported", "Operating System not supported for this build!" ) };
+
+ std::string nproc = String::format( "%d", Sys::getCPUCount() );
+ ProjectBuildCommandsRes res;
+
+ for ( const auto& step : build.mClean ) {
+ ProjectBuildCommand buildCmd( step, build.mEnvs );
+ replaceVar( buildCmd, VAR_OS, currentOS );
+ replaceVar( buildCmd, VAR_NPROC, nproc );
+ if ( !buildType.empty() )
+ replaceVar( buildCmd, VAR_BUILD_TYPE, buildType );
+ buildCmd.config = build.mConfig;
+ res.cmds.emplace_back( std::move( buildCmd ) );
+ }
+
+ return res;
+}
+
+ProjectBuildCommandsRes ProjectBuildManager::clean( const std::string& buildName,
+ const ProjectBuildi18nFn& i18n,
+ const std::string& buildType,
+ const ProjectBuildProgressFn& progressFn,
+ const ProjectBuildDoneFn& doneFn ) {
+ ProjectBuildCommandsRes res = generateCleanCommands( buildName, i18n, buildType );
+ if ( !res.isValid() )
+ return res;
+ if ( !mThreadPool ) {
+ res.errorMsg = i18n( "no_threads", "Threaded ecode required to compile builds." );
+ return res;
+ }
+
+ mThreadPool->run( [this, res, progressFn, doneFn, i18n, buildName, buildType]() {
+ runBuild( buildName, buildType, i18n, res, progressFn, doneFn );
+ } );
+
+ return res;
+};
+
static bool isValidType( const std::string& typeStr ) {
return "error" == typeStr || "warning" == typeStr || "notice" == typeStr;
}
@@ -269,44 +365,6 @@ bool ProjectBuildManager::load() {
return true;
}
-ProjectBuildCommandsRes ProjectBuildManager::generateBuildCommands( const std::string& buildName,
- const ProjectBuildi18nFn& i18n,
- const std::string& buildType ) {
- if ( !mLoaded )
- return { i18n( "project_build_not_loaded", "No project build loaded!" ) };
-
- const auto& buildIt = mBuilds.find( buildName );
-
- if ( buildIt == mBuilds.end() )
- return { i18n( "build_name_not_found", "Build name not found!" ) };
-
- const auto& build = buildIt->second;
-
- if ( !build.mBuildTypes.empty() && buildType.empty() )
- return { i18n( "build_type_required", "Build type must be set!" ) };
-
- std::string currentOS = String::toLower( Sys::getPlatform() );
-
- if ( !build.isOSSupported( currentOS ) )
- return {
- i18n( "build_os_not_supported", "Operating System not supported for this build!" ) };
-
- std::string nproc = String::format( "%d", Sys::getCPUCount() );
- ProjectBuildCommandsRes res;
-
- for ( const auto& step : build.mBuild ) {
- ProjectBuildCommand buildCmd( step, build.mEnvs );
- replaceVar( buildCmd, VAR_OS, currentOS );
- replaceVar( buildCmd, VAR_NPROC, nproc );
- if ( !buildType.empty() )
- replaceVar( buildCmd, VAR_BUILD_TYPE, buildType );
- buildCmd.config = build.mConfig;
- res.cmds.emplace_back( std::move( buildCmd ) );
- }
-
- return res;
-}
-
ProjectBuildOutputParser ProjectBuildManager::getOutputParser( const std::string& buildName ) {
auto buildIt = mBuilds.find( buildName );
if ( buildIt != mBuilds.end() )
@@ -314,6 +372,20 @@ ProjectBuildOutputParser ProjectBuildManager::getOutputParser( const std::string
return {};
}
+bool ProjectBuildManager::hasBuildCommands( const std::string& name ) {
+ auto buildIt = mBuilds.find( name );
+ if ( buildIt != mBuilds.end() )
+ return buildIt->second.hasBuild();
+ return false;
+}
+
+bool ProjectBuildManager::hasCleanCommands( const std::string& name ) {
+ auto buildIt = mBuilds.find( name );
+ if ( buildIt != mBuilds.end() )
+ return buildIt->second.hasClean();
+ return false;
+}
+
void ProjectBuildManager::cancelBuild() {
mCancelBuild = true;
if ( mProcess ) {
@@ -338,7 +410,21 @@ void ProjectBuildManager::buildCurrentConfig( StatusBuildOutputController* sboc
build = &buildIt.second;
if ( build )
- sboc->run( build->getName(), mConfig.buildType, getOutputParser( build->getName() ) );
+ sboc->runBuild( build->getName(), mConfig.buildType,
+ getOutputParser( build->getName() ) );
+ }
+}
+
+void ProjectBuildManager::cleanCurrentConfig( StatusBuildOutputController* sboc ) {
+ if ( sboc && !isBuilding() && !getBuilds().empty() ) {
+ const ProjectBuild* build = nullptr;
+ for ( const auto& buildIt : getBuilds() )
+ if ( buildIt.second.getName() == mConfig.buildName )
+ build = &buildIt.second;
+
+ if ( build )
+ sboc->runClean( build->getName(), mConfig.buildType,
+ getOutputParser( build->getName() ) );
}
}
@@ -487,6 +573,7 @@ void ProjectBuildManager::buildSidePanelTab() {
+
)html" );
@@ -501,6 +588,7 @@ void ProjectBuildManager::updateSidePanelTab() {
UIWidget* buildTab = mTab->getOwnedWidget()->find( "build_tab" );
UIDropDownList* buildList = buildTab->find( "build_list" );
UIPushButton* buildButton = buildTab->find( "build_button" );
+ UIPushButton* cleanButton = buildTab->find( "clean_button" );
buildList->getListBox()->clear();
@@ -561,7 +649,11 @@ void ProjectBuildManager::updateSidePanelTab() {
mConfig.buildType = buildTypeList->getListBox()->getItemSelectedText();
} );
- buildButton->setEnabled( !mConfig.buildName.empty() );
+ buildButton->setEnabled( !mConfig.buildName.empty() && hasBuild( mConfig.buildName ) &&
+ hasBuildCommands( mConfig.buildName ) );
+
+ cleanButton->setEnabled( !mConfig.buildName.empty() && hasBuild( mConfig.buildName ) &&
+ hasCleanCommands( mConfig.buildName ) );
buildButton->addMouseClickListener(
[this]( const Event* ) {
@@ -572,6 +664,16 @@ void ProjectBuildManager::updateSidePanelTab() {
}
},
MouseButton::EE_BUTTON_LEFT );
+
+ cleanButton->addMouseClickListener(
+ [this]( const Event* ) {
+ if ( isBuilding() ) {
+ cancelBuild();
+ } else {
+ cleanCurrentConfig( mApp->getStatusBuildOutputController() );
+ }
+ },
+ MouseButton::EE_BUTTON_LEFT );
}
} // namespace ecode
diff --git a/src/tools/ecode/projectbuild.hpp b/src/tools/ecode/projectbuild.hpp
index 90bd2808f..f558a5c1a 100644
--- a/src/tools/ecode/projectbuild.hpp
+++ b/src/tools/ecode/projectbuild.hpp
@@ -135,6 +135,10 @@ class ProjectBuild {
const ProjectBuildOutputParser& getOutputParser() const { return mOutputParser; }
+ bool hasBuild() const { return !mBuild.empty(); }
+
+ bool hasClean() const { return !mClean.empty(); }
+
protected:
friend class ProjectBuildManager;
@@ -189,15 +193,24 @@ class ProjectBuildManager {
~ProjectBuildManager();
- ProjectBuildCommandsRes run( const std::string& buildName, const ProjectBuildi18nFn& i18n,
- const std::string& buildType = "",
- const ProjectBuildProgressFn& progressFn = {},
- const ProjectBuildDoneFn& doneFn = {} );
+ ProjectBuildCommandsRes build( const std::string& buildName, const ProjectBuildi18nFn& i18n,
+ const std::string& buildType = "",
+ const ProjectBuildProgressFn& progressFn = {},
+ const ProjectBuildDoneFn& doneFn = {} );
ProjectBuildCommandsRes generateBuildCommands( const std::string& buildName,
const ProjectBuildi18nFn& i18n,
const std::string& buildType = "" );
+ ProjectBuildCommandsRes clean( const std::string& buildName, const ProjectBuildi18nFn& i18n,
+ const std::string& buildType = "",
+ const ProjectBuildProgressFn& progressFn = {},
+ const ProjectBuildDoneFn& doneFn = {} );
+
+ ProjectBuildCommandsRes generateCleanCommands( const std::string& buildName,
+ const ProjectBuildi18nFn& i18n,
+ const std::string& buildType = "" );
+
ProjectBuildOutputParser getOutputParser( const std::string& buildName );
const ProjectBuildMap& getBuilds() const { return mBuilds; }
@@ -206,6 +219,12 @@ class ProjectBuildManager {
const std::string& getProjectFile() const { return mProjectFile; }
+ bool hasBuild( const std::string& name ) { return mBuilds.find( name ) != mBuilds.end(); }
+
+ bool hasBuildCommands( const std::string& name );
+
+ bool hasCleanCommands( const std::string& name );
+
bool loaded() const { return mLoaded; }
bool loading() const { return mLoading; }
@@ -220,6 +239,8 @@ class ProjectBuildManager {
void buildCurrentConfig( StatusBuildOutputController* sboc );
+ void cleanCurrentConfig( StatusBuildOutputController* sboc );
+
protected:
std::string mProjectRoot;
std::string mProjectFile;
diff --git a/src/tools/ecode/statusbuildoutputcontroller.cpp b/src/tools/ecode/statusbuildoutputcontroller.cpp
index 494af3c43..a04d2119c 100644
--- a/src/tools/ecode/statusbuildoutputcontroller.cpp
+++ b/src/tools/ecode/statusbuildoutputcontroller.cpp
@@ -81,8 +81,18 @@ UIPushButton* StatusBuildOutputController::getBuildButton( App* app ) {
return nullptr;
}
-void StatusBuildOutputController::run( const std::string& buildName, const std::string& buildType,
- const ProjectBuildOutputParser& outputParser ) {
+UIPushButton* StatusBuildOutputController::getCleanButton( App* app ) {
+ if ( app->getSidePanel() ) {
+ UIWidget* tab = app->getSidePanel()->find( "build_tab" );
+ if ( tab )
+ return tab->find( "clean_button" );
+ }
+ return nullptr;
+}
+
+void StatusBuildOutputController::runBuild( const std::string& buildName,
+ const std::string& buildType,
+ const ProjectBuildOutputParser& outputParser ) {
if ( !mApp->getProjectBuildManager() )
return;
@@ -115,8 +125,14 @@ void StatusBuildOutputController::run( const std::string& buildName, const std::
UIPushButton* buildButton = getBuildButton( mApp );
if ( buildButton )
buildButton->setText( mApp->i18n( "cancel_build", "Cancel Build" ) );
+ UIPushButton* cleanButton = getCleanButton( mApp );
+ bool enableCleanButton = false;
+ if ( cleanButton && cleanButton->isEnabled() ) {
+ cleanButton->setEnabled( false );
+ enableCleanButton = true;
+ }
- auto res = pbm->run(
+ auto res = pbm->build(
buildName, [this]( const auto& key, const auto& def ) { return mApp->i18n( key, def ); },
buildType,
[this]( auto, auto buffer ) {
@@ -127,7 +143,7 @@ void StatusBuildOutputController::run( const std::string& buildName, const std::
mContainer->setScrollY( mContainer->getMaxScroll().y );
} );
},
- [this]( auto exitCode ) {
+ [this, enableCleanButton]( auto exitCode ) {
String buffer;
if ( EXIT_SUCCESS == exitCode ) {
@@ -145,9 +161,102 @@ void StatusBuildOutputController::run( const std::string& buildName, const std::
mContainer->setScrollY( mContainer->getMaxScroll().y );
} );
- UIPushButton* buildButton = nullptr;
- if ( ( buildButton = getBuildButton( mApp ) ) )
+ UIPushButton* buildButton = getBuildButton( mApp );
+ if ( buildButton )
buildButton->setText( mApp->i18n( "build", "Build" ) );
+
+ if ( enableCleanButton ) {
+ UIPushButton* cleanButton = getCleanButton( mApp );
+ if ( cleanButton )
+ cleanButton->setEnabled( true );
+ }
+ } );
+
+ if ( !res.isValid() ) {
+ mApp->getNotificationCenter()->addNotification( res.errorMsg );
+ }
+}
+
+void StatusBuildOutputController::runClean( const std::string& buildName,
+ const std::string& buildType,
+ const ProjectBuildOutputParser& outputParser ) {
+ if ( !mApp->getProjectBuildManager() )
+ return;
+
+ auto pbm = mApp->getProjectBuildManager();
+
+ show();
+
+ mContainer->getDocument().reset();
+ mContainer->setScrollY( mContainer->getMaxScroll().y );
+
+ std::vector patterns;
+
+ for ( const auto& parser : outputParser.getConfig() ) {
+ SyntaxPattern ptn( { parser.pattern }, getProjectOutputParserTypeToString( parser.type ) );
+ patterns.emplace_back( std::move( ptn ) );
+ }
+
+ patterns.emplace_back(
+ SyntaxPattern( { "%d%d%d%d%-%d%d%-%d%d%s%d%d%:%d%d%:%d%d%:.*error.*[^\n]+" }, "error" ) );
+ patterns.emplace_back( SyntaxPattern(
+ { "%d%d%d%d%-%d%d%-%d%d%s%d%d%:%d%d%:%d%d%:.*warning.*[^\n]+" }, "warning" ) );
+ patterns.emplace_back(
+ SyntaxPattern( { "%d%d%d%d%-%d%d%-%d%d%s%d%d%:%d%d%:%d%d%:[^\n]+" }, "notice" ) );
+
+ SyntaxDefinition synDef( "custom_build", {}, patterns );
+
+ mContainer->getDocument().setSyntaxDefinition( synDef );
+ mContainer->getVScrollBar()->setValue( 1.f );
+
+ UIPushButton* buildButton = getBuildButton( mApp );
+ bool enableBuildButton = false;
+ if ( buildButton && buildButton->isEnabled() ) {
+ buildButton->setEnabled( false );
+ enableBuildButton = true;
+ }
+ UIPushButton* cleanButton = getCleanButton( mApp );
+ if ( cleanButton )
+ cleanButton->setText( mApp->i18n( "cancel_clean", "Cancel Clean" ) );
+
+ auto res = pbm->clean(
+ buildName, [this]( const auto& key, const auto& def ) { return mApp->i18n( key, def ); },
+ buildType,
+ [this]( auto, auto buffer ) {
+ mContainer->runOnMainThread( [this, buffer]() {
+ bool scrollToBottom = mContainer->getVScrollBar()->getValue() == 1.f;
+ mContainer->getDocument().textInput( buffer );
+ if ( scrollToBottom )
+ mContainer->setScrollY( mContainer->getMaxScroll().y );
+ } );
+ },
+ [this, enableBuildButton]( auto exitCode ) {
+ String buffer;
+
+ if ( EXIT_SUCCESS == exitCode ) {
+ buffer = Sys::getDateTimeStr() + ": " +
+ mApp->i18n( "build_successful", "Build run successfully\n" );
+ } else {
+ buffer = Sys::getDateTimeStr() + ": " +
+ mApp->i18n( "build_failed", "Build run with errors\n" );
+ }
+
+ mContainer->runOnMainThread( [this, buffer]() {
+ bool scrollToBottom = mContainer->getVScrollBar()->getValue() == 1.f;
+ mContainer->getDocument().textInput( buffer );
+ if ( scrollToBottom )
+ mContainer->setScrollY( mContainer->getMaxScroll().y );
+ } );
+
+ UIPushButton* cleanButton = getCleanButton( mApp );
+ if ( cleanButton )
+ cleanButton->setText( mApp->i18n( "clean", "Clean" ) );
+
+ if ( enableBuildButton ) {
+ UIPushButton* buildButton = getBuildButton( mApp );
+ if ( buildButton )
+ buildButton->setEnabled( true );
+ }
} );
if ( !res.isValid() ) {
diff --git a/src/tools/ecode/statusbuildoutputcontroller.hpp b/src/tools/ecode/statusbuildoutputcontroller.hpp
index 62c7bfa49..52ea0785d 100644
--- a/src/tools/ecode/statusbuildoutputcontroller.hpp
+++ b/src/tools/ecode/statusbuildoutputcontroller.hpp
@@ -25,8 +25,11 @@ class StatusBuildOutputController {
void show();
- void run( const std::string& buildName, const std::string& buildType,
- const ProjectBuildOutputParser& outputParser = {} );
+ void runBuild( const std::string& buildName, const std::string& buildType,
+ const ProjectBuildOutputParser& outputParser = {} );
+
+ void runClean( const std::string& buildName, const std::string& buildType,
+ const ProjectBuildOutputParser& outputParser = {} );
UICodeEditor* getContainer();
@@ -40,6 +43,8 @@ class StatusBuildOutputController {
UICodeEditor* createContainer();
UIPushButton* getBuildButton( App* app );
+
+ UIPushButton* getCleanButton( App* app );
};
} // namespace ecode