diff --git a/include/eepp/system/process.hpp b/include/eepp/system/process.hpp index bc941a840..25c5745b6 100644 --- a/include/eepp/system/process.hpp +++ b/include/eepp/system/process.hpp @@ -73,6 +73,16 @@ class EE_API Process { const std::unordered_map& environment = {}, const std::string& workingDirectory = "" ); + /** @brief Create a process. + ** @param command Command line to execute for this process. + ** @param args Command line arguments to execute for this process. + ** @param options A bit field of Options's to pass. + ** @return On success true is returned. */ + bool create( const std::string& command, const std::vector& args, + Uint32 options = getDefaultOptions(), + const std::unordered_map& environment = {}, + const std::string& workingDirectory = "" ); + /** @brief Starts a new thread to receive all stdout and stderr data */ void startAsyncRead( ReadFn readStdOut = nullptr, ReadFn readStdErr = nullptr ); @@ -149,6 +159,11 @@ class EE_API Process { ** @return The number of bytes actually written into buffer. */ size_t write( const std::string& buffer ); + /** @brief Write the standard output from the child process. + ** @param buffer The buffer to write into. + ** @return The number of bytes actually written into buffer. */ + size_t write( const std::string_view& buffer ); + /** @brief Wait for a process to finish execution. ** @param returnCodeOut The return code of the returned process (can be nullptr). ** @return On success true is returned. diff --git a/include/eepp/system/sys.hpp b/include/eepp/system/sys.hpp index c01925cf7..e8cf61f23 100644 --- a/include/eepp/system/sys.hpp +++ b/include/eepp/system/sys.hpp @@ -3,6 +3,7 @@ #include #include +#include #include namespace EE { namespace System { @@ -103,6 +104,9 @@ class EE_API Sys { /** @return True if current running platform / os is a mobile one */ static bool isMobile(); + + /** @return The process environment variables */ + static std::unordered_map getEnvironmentVariables(); }; }} // namespace EE::System diff --git a/src/eepp/system/process.cpp b/src/eepp/system/process.cpp index 059a4e633..c738e44f9 100644 --- a/src/eepp/system/process.cpp +++ b/src/eepp/system/process.cpp @@ -51,52 +51,27 @@ Process::~Process() { bool Process::create( const std::string& command, Uint32 options, const std::unordered_map& environment, const std::string& workingDirectory ) { - if ( mProcess ) - return false; std::vector cmdArr = String::split( command, " ", "", "\"", true ); - std::vector strings; - mProcess = eeMalloc( sizeof( subprocess_s ) ); - memset( mProcess, 0, sizeof( subprocess_s ) ); - if ( !environment.empty() ) { - std::string rcommand; - if ( FileSystem::fileExists( command ) ) { - rcommand = command; - } else { - rcommand = Sys::which( command ); - if ( rcommand.empty() ) - return false; - } - strings.push_back( rcommand.c_str() ); - std::vector envArr; - std::vector envStrings; - for ( const auto& pair : environment ) { - envArr.push_back( String::format( "%s=%s", pair.first.c_str(), pair.second.c_str() ) ); - envStrings.push_back( envArr[envArr.size() - 1].c_str() ); - } - envStrings.push_back( NULL ); - - auto ret = 0 == subprocess_create_ex( strings.data(), options, envStrings.data(), - !workingDirectory.empty() ? workingDirectory.c_str() - : nullptr, - PROCESS_PTR ); - return ret; - } - for ( size_t i = 0; i < cmdArr.size(); ++i ) - strings.push_back( cmdArr[i].c_str() ); - strings.push_back( NULL ); - auto ret = - 0 == subprocess_create_ex( strings.data(), options, nullptr, - !workingDirectory.empty() ? workingDirectory.c_str() : nullptr, - PROCESS_PTR ); - return ret; + if ( cmdArr.empty() ) + return false; + std::string cmd( cmdArr[0] ); + cmdArr.erase( cmdArr.begin() ); + return create( cmd, cmdArr, options, environment, workingDirectory ); } bool Process::create( const std::string& command, const std::string& args, Uint32 options, const std::unordered_map& environment, const std::string& workingDirectory ) { + return create( command, String::split( args, " ", "", "\"", true ), options, environment, + workingDirectory ); +} + +bool Process::create( const std::string& command, const std::vector& cmdArr, + Uint32 options, + const std::unordered_map& environment, + const std::string& workingDirectory ) { if ( mProcess ) return false; - std::vector cmdArr = String::split( args, " ", "", "\"", true ); std::vector strings; mProcess = eeMalloc( sizeof( subprocess_s ) ); memset( mProcess, 0, sizeof( subprocess_s ) ); @@ -109,17 +84,31 @@ bool Process::create( const std::string& command, const std::string& args, Uint3 if ( rcommand.empty() ) return false; } + std::vector envArr; + std::vector envStrings; + std::unordered_map envVars; + if ( options & Process::InheritEnvironment ) { + envVars = Sys::getEnvironmentVariables(); + options &= ~Process::InheritEnvironment; + } + envArr.reserve( environment.size() + envVars.size() ); + strings.reserve( cmdArr.size() + 1 ); + envStrings.reserve( envArr.size() + 1 ); + strings.push_back( rcommand.c_str() ); for ( size_t i = 0; i < cmdArr.size(); ++i ) strings.push_back( cmdArr[i].c_str() ); strings.push_back( NULL ); - std::vector envArr; - std::vector envStrings; - for ( const auto& pair : environment ) { + // Set / Overwrite our envs + for ( auto& pair : environment ) + envVars[pair.first] = std::move( pair.second ); + + for ( const auto& pair : envVars ) { envArr.push_back( String::format( "%s=%s", pair.first.c_str(), pair.second.c_str() ) ); envStrings.push_back( envArr[envArr.size() - 1].c_str() ); } + envStrings.push_back( NULL ); auto ret = 0 == subprocess_create_ex( strings.data(), options, envStrings.data(), @@ -179,6 +168,10 @@ size_t Process::write( const std::string& buffer ) { return write( buffer.c_str(), buffer.size() ); } +size_t Process::write( const std::string_view& buffer ) { + return write( buffer.data(), buffer.size() ); +} + bool Process::join( int* const returnCodeOut ) { eeASSERT( mProcess != nullptr ); return 0 == subprocess_join( PROCESS_PTR, returnCodeOut ); @@ -312,7 +305,7 @@ void Process::startAsyncRead( ReadFn readStdOut, ReadFn readStdErr ) { mBufferSize ); if ( n == 0 ) break; - if ( n < static_cast( mBufferSize - 1 ) ) + if ( n < mBufferSize - 1 ) buffer[n] = '\0'; if ( !mShuttingDown ) mReadStdOutFn( buffer.c_str(), static_cast( n ) ); @@ -329,7 +322,7 @@ void Process::startAsyncRead( ReadFn readStdOut, ReadFn readStdErr ) { mBufferSize ); if ( n == 0 ) break; - if ( n < static_cast( mBufferSize - 1 ) ) + if ( n < mBufferSize - 1 ) buffer[n] = '\0'; if ( !mShuttingDown ) diff --git a/src/eepp/system/sys.cpp b/src/eepp/system/sys.cpp index 62de25bd5..d4096cc6b 100644 --- a/src/eepp/system/sys.cpp +++ b/src/eepp/system/sys.cpp @@ -77,6 +77,32 @@ using namespace EE::Network; #define PATH_MAX 4096 #endif +std::unordered_map _getEnvironmentVariables() { + std::unordered_map ret; + char** env; +#if defined( WIN ) && ( _MSC_VER >= 1900 ) + env = *__p__environ(); +#else + extern char** environ; + env = environ; +#endif + + for ( ; *env; ++env ) { + auto var = EE::String::split( *env, "=" ); + + if ( var.size() == 2 ) { + ret.insert( std::make_pair( var[0], var[1] ) ); + } else if ( var.size() > 2 ) { + auto val( var[1] ); + for ( size_t i = 2; i < var.size(); ++i ) + val += var[i]; + ret.insert( std::make_pair( var[0], val ) ); + } + } + + return ret; +} + namespace EE { namespace System { #if EE_PLATFORM == EE_PLATFORM_WIN @@ -1192,6 +1218,10 @@ bool Sys::isMobile() { #endif } +std::unordered_map Sys::getEnvironmentVariables() { + return _getEnvironmentVariables(); +} + std::string Sys::getProcessFilePath() { #if EE_PLATFORM != EE_PLATFORM_WIN char exename[PATH_MAX]; diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp index 20ae17e9d..5aef9022f 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp @@ -262,10 +262,12 @@ bool AutoCompletePlugin::onKeyDown( UICodeEditor* editor, const KeyEvent& event editor->invalidateDraw(); return true; } else if ( event.getKeyCode() == KEY_ESCAPE ) { - resetSuggestions( editor ); - resetSignatureHelp(); - editor->invalidateDraw(); - return true; + if ( !ret ) { + resetSuggestions( editor ); + resetSignatureHelp(); + editor->invalidateDraw(); + return true; + } } else if ( event.getKeyCode() == KEY_HOME ) { mSuggestionIndex = 0; mSuggestionsStartIndex = 0; diff --git a/src/tools/ecode/projectbuild.cpp b/src/tools/ecode/projectbuild.cpp index 6f6db54ed..78f07acd5 100644 --- a/src/tools/ecode/projectbuild.cpp +++ b/src/tools/ecode/projectbuild.cpp @@ -17,33 +17,6 @@ using json = nlohmann::json; using namespace EE::Scene; -/** @return The process environment variables */ -static ecode::ProjectBuildKeyVal getEnvironmentVariables() { - ecode::ProjectBuildKeyVal ret; - char** env; -#if defined( WIN ) && ( _MSC_VER >= 1900 ) - env = *__p__environ(); -#else - extern char** environ; - env = environ; -#endif - - for ( ; *env; ++env ) { - auto var = String::split( *env, "=" ); - - if ( var.size() == 2 ) { - ret.push_back( std::make_pair( var[0], var[1] ) ); - } else if ( var.size() > 2 ) { - auto val( var[1] ); - for ( size_t i = 2; i < var.size(); ++i ) - val += var[i]; - ret.push_back( std::make_pair( var[0], val ) ); - } - } - - return ret; -} - namespace ecode { static const char* VAR_PROJECT_ROOT = "${project_root}"; @@ -764,17 +737,8 @@ void ProjectBuildManager::runBuild( const std::string& buildName, const std::str int progress = c > 0 ? c / (Float)totSteps : 0; mProcess = std::make_unique(); auto options = Process::SearchUserPath | Process::NoWindow | Process::CombinedStdoutStderr; - ProjectBuildKeyVal env; - if ( !cmd.config.clearSysEnv ) { - if ( !res.envs.empty() ) { - env = getEnvironmentVariables(); - env.insert( env.begin(), res.envs.begin(), res.envs.end() ); - } else { - options |= Process::InheritEnvironment; - } - } else { - env = res.envs; - } + if ( !cmd.config.clearSysEnv ) + options |= Process::InheritEnvironment; if ( !cmd.enabled ) { c++; @@ -797,7 +761,7 @@ void ProjectBuildManager::runBuild( const std::string& buildName, const std::str nullptr ); } - if ( mProcess->create( cmd.cmd, cmd.args, options, toUnorderedMap( env ), + if ( mProcess->create( cmd.cmd, cmd.args, options, toUnorderedMap( res.envs ), cmd.workingDir ) ) { std::string buffer( 1024, '\0' ); unsigned bytesRead = 0; diff --git a/src/tools/ecode/statusbuildoutputcontroller.cpp b/src/tools/ecode/statusbuildoutputcontroller.cpp index 095b8db7f..b430af721 100644 --- a/src/tools/ecode/statusbuildoutputcontroller.cpp +++ b/src/tools/ecode/statusbuildoutputcontroller.cpp @@ -568,12 +568,11 @@ void StatusBuildOutputController::createContainer() { ->setId( "copy-error-message" ); menu->add( mApp->i18n( "copy_file_path", "Copy File Path" ), mApp->findIcon( "copy" ) ) ->setId( "copy-file-path" ); - menu->on( Event::OnItemClicked, [this, model, modelEvent, idx]( const Event* event ) { + menu->on( Event::OnItemClicked, [this, model, idx]( const Event* event ) { UIMenuItem* item = event->getNode()->asType(); std::string id( item->getId() ); if ( id == "copy-error-message" ) { - Variant msg( model->data( model->index( modelEvent->getModelIndex().row(), 0 ), - ModelRole::Display ) ); + Variant msg( model->data( model->index( idx.row(), 0 ), ModelRole::Display ) ); mApp->getWindow()->getClipboard()->setText( msg.toString() ); } else if ( id == "copy-file-path" ) { Variant msg( model->data( idx, ModelRole::Custom ) );