diff --git a/bin/assets/colorschemes/colorschemes.conf b/bin/assets/colorschemes/colorschemes.conf index 641858e45..1a5ffc612 100644 --- a/bin/assets/colorschemes/colorschemes.conf +++ b/bin/assets/colorschemes/colorschemes.conf @@ -711,3 +711,45 @@ operator = #000000 function = #000080,bold link = #007f00 link_hover = #007f00,transparent,underline + +[jEdit] +background = #ffffff +text = #000000 +caret = #000000 +selection = #ccccff +line_highlight = #ffffe0 +line_number = #464646 +line_number2 = #181818 +gutter_background = #dfdfdf +whitespace = #c0c0c0 +line_break_column = #54575b99 +matching_bracket = #dbdbdb +matching_selection = #ffff00 +matching_search = #0000f0 +suggestion = #1d1f27,#e1e1e6 +suggestion_selected = #222533,#ffffff +suggestion_scrollbar = #3daee9 +error = #ff3030 +warning = yellow +notice = #8abdff +selection_region = #c0c0c077 +minimap_background = #FFFFFF1A +minimap_visible_area = #dfdfdfAA +minimap_current_line = #f0f0f00A +minimap_hover = #FFFFFF1A +minimap_selection = #8abdff80 +minimap_highlight = #FFFF0080 + +normal = #000000 +symbol = #000000 +comment = #cc0000 +keyword = #006699,bold +type = #0099ff,bold +parameter = #009966,bold +number = #ff0000 +literal = #cc00cc +string = #ff00cc +operator = #000000,bold +function = #9966ff +link = #0000ff +link_hover = #0000ff,transparent,underline diff --git a/src/eepp/system/sys.cpp b/src/eepp/system/sys.cpp index 910162db6..d5293a55e 100644 --- a/src/eepp/system/sys.cpp +++ b/src/eepp/system/sys.cpp @@ -13,12 +13,18 @@ #include #include +#if EE_PLATFORM == EE_PLATFORM_MACOS || EE_PLATFORM == EE_PLATFORM_IOS +#define EE_USE_POSIX_SPAWN +#elif defined( __GLIBC__ ) && ( __GLIBC__ > 2 || ( __GLIBC__ == 2 && __GLIBC_MINOR__ >= 29 ) ) +#define EE_USE_POSIX_SPAWN +#endif + // This taints the System module! #if EE_PLATFORM == EE_PLATFORM_ANDROID #include #endif -#if defined( EE_PLATFORM_POSIX ) +#ifdef EE_PLATFORM_POSIX #include #include #include @@ -73,6 +79,9 @@ typedef DWORD( WINAPI* GetModuleBaseName_t )( HANDLE, HMODULE, LPSTR, DWORD ); #if EE_PLATFORM == EE_PLATFORM_MACOS || EE_PLATFORM == EE_PLATFORM_IOS #include #include +#endif + +#ifdef EE_USE_POSIX_SPAWN #include #endif @@ -100,8 +109,7 @@ using namespace EE::Network; #define PATH_MAX 4096 #endif -std::unordered_map _getEnvironmentVariables() { - std::unordered_map ret; +char** _getEnviron() { char** env; #if defined( WIN ) && ( _MSC_VER >= 1900 ) env = *__p__environ(); @@ -109,6 +117,12 @@ std::unordered_map _getEnvironmentVariables() { extern char** environ; env = environ; #endif + return env; +} + +std::unordered_map _getEnvironmentVariables() { + std::unordered_map ret; + char** env = _getEnviron(); for ( ; *env; ++env ) { auto var = EE::String::split( *env, "=" ); @@ -1257,6 +1271,33 @@ static int windowsSystem( const std::string& programPath, const std::string& wor int Sys::execute( const std::string& cmd, const std::string& workingDir ) { #if EE_PLATFORM == EE_PLATFORM_WIN return windowsSystem( cmd, workingDir ); +#elif defined( EE_USE_POSIX_SPAWN ) + pid_t pid; + std::vector cmdArr = String::split( cmd, " ", "", "\"", true ); + std::vector strings; + for ( size_t i = 0; i < cmdArr.size(); ++i ) + strings.push_back( const_cast( cmdArr[i].c_str() ) ); + strings.push_back( NULL ); + + posix_spawn_file_actions_t actions; + if ( !workingDir.empty() ) { + if ( posix_spawn_file_actions_init( &actions ) != 0 ) + return -1; // Failed to initialize + + if ( posix_spawn_file_actions_addchdir_np( &actions, workingDir.c_str() ) != 0 ) { + posix_spawn_file_actions_destroy( &actions ); + return -1; // Failed to add chdir action + } + } + int status = posix_spawnp( &pid, strings[0], workingDir.empty() ? NULL : &actions, NULL, + strings.data(), _getEnviron() ); + + if ( !workingDir.empty() ) + posix_spawn_file_actions_destroy( &actions ); + + if ( status == 0 ) + return pid; + return -1; #elif EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN pid_t pid = fork(); if ( pid == 0 ) { @@ -1270,9 +1311,11 @@ int Sys::execute( const std::string& cmd, const std::string& workingDir ) { FileSystem::changeWorkingDirectory( workingDir ); execvp( strings[0], (char* const*)strings.data() ); - exit( 0 ); + exit( 127 ); } return pid; +#else + return -1; #endif } @@ -1489,9 +1532,6 @@ std::vector Sys::pidof( const std::string& processName ) { } } - for ( auto pid : pids ) - eePRINTL( "Found pid %d", pid ); - FreeLibrary( hPsapi ); return pids; #elif EE_PLATFORM == EE_PLATFORM_LINUX || EE_PLATFORM == EE_PLATFORM_ANDROID diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index f5ec40924..2cc88f080 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -971,6 +971,9 @@ App::~App() { mDirTree.reset(); fsRemoveAll( mPidPath ); + + if ( mFirstInstance ) + FileSystem::fileRemove( firstInstanceIndicatorPath() ); } void App::updateRecentButtons() { @@ -2452,6 +2455,16 @@ void App::createWidgetInspector() { UIWidgetInspector::create( mUISceneNode, mMenuIconSize ); } +void App::openInNewWindow( const std::string& params ) { + std::string processPath = Sys::getProcessFilePath(); + if ( !processPath.empty() ) { + std::string cmd( processPath + " -x" ); + if ( !params.empty() ) + cmd += " " + params; + Sys::execute( cmd ); + } +} + void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { const CodeEditorConfig& config = mConfig.editor; const DocumentConfig& docc = !mCurrentProject.empty() && !mProjectDocConfig.useGlobalSettings @@ -2548,11 +2561,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { if ( editor == nullptr || editor->getDocumentRef() == nullptr || editor->getDocumentRef()->getFilePath().empty() ) return; - std::string processPath = Sys::getProcessFilePath(); - if ( !processPath.empty() ) { - auto cmd( processPath + " -x \"" + editor->getDocumentRef()->getFilePath() + "\"" ); - Sys::execute( cmd ); - } + openInNewWindow( "\"" + editor->getDocumentRef()->getFilePath() + "\"" ); } ); doc.setCommand( "move-to-new-window", [this] { auto editor = mSplitter->getCurEditor(); @@ -2562,11 +2571,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { UITabWidget* tabWidget = mSplitter->tabWidgetFromEditor( editor ); if ( tabWidget ) tabWidget->removeTab( (UITab*)editor->getData() ); - std::string processPath = Sys::getProcessFilePath(); - if ( !processPath.empty() ) { - auto cmd( processPath + " -x \"" + editor->getDocumentRef()->getFilePath() + "\"" ); - Sys::execute( cmd ); - } + openInNewWindow( "\"" + editor->getDocumentRef()->getFilePath() + "\"" ); } ); doc.setCommand( "move-tab-to-start", [this] { auto widget = mSplitter->getCurWidget(); @@ -3438,11 +3443,7 @@ void App::loadFolder( std::string path, bool forceNewWindow ) { if ( ( mConfig.ui.openProjectInNewWindow || forceNewWindow ) && ( !mCurrentProject.empty() && mCurrentProject != getPlaygroundPath() ) ) { - std::string processPath = Sys::getProcessFilePath(); - if ( !processPath.empty() ) { - std::string cmd( processPath + " " + path ); - Sys::execute( cmd ); - } + openInNewWindow( "\"" + path + "\"" ); return; } @@ -3619,6 +3620,10 @@ FontTrueType* App::loadFont( const std::string& name, std::string fontPath, return nullptr; } +std::string App::firstInstanceIndicatorPath() const { + return mConfigPath + "first-instance"; +} + bool App::needsRedirectToRunningProcess( std::string file ) { if ( mConfig.ui.openFilesInNewWindow || file.empty() ) return false; @@ -3643,23 +3648,31 @@ bool App::needsRedirectToRunningProcess( std::string file ) { return false; Uint64 processPid = Sys::getProcessID(); - Uint64 latestPid = processPid; - Uint64 lastCreationTime = 0; + Uint64 selectedPid = processPid; + Uint64 selCreationTime = Sys::getProcessCreationTime( processPid ); + + auto isBetter = + FileSystem::fileExists( firstInstanceIndicatorPath() ) + ? []( Uint64 newTime, + Uint64 bestTime ) { return newTime <= bestTime; } // Finding oldest (min) + : []( Uint64 newTime, Uint64 bestTime ) { + return newTime >= bestTime; + }; // Finding newest (max) for ( const auto pid : pids ) { - if ( pid != Sys::getProcessID() ) { - Uint64 creationTime = Sys::getProcessCreationTime( pid ); - if ( creationTime >= lastCreationTime ) { - latestPid = pid; - lastCreationTime = creationTime; - } + if ( pid == processPid ) + continue; + Uint64 creationTime = Sys::getProcessCreationTime( pid ); + if ( isBetter( creationTime, selCreationTime ) ) { + selectedPid = pid; + selCreationTime = creationTime; } } - if ( latestPid == processPid ) + if ( selectedPid == processPid ) return false; - std::string pidPath = mIpcPath + String::toString( latestPid ); + std::string pidPath = mIpcPath + String::toString( selectedPid ); if ( !FileSystem::isDirectory( pidPath ) ) return false; FileSystem::dirAddSlashAtEnd( pidPath ); @@ -3686,6 +3699,7 @@ void App::init( InitParameters& params ) { mUseFrameBuffer = params.frameBuffer; mBenchmarkMode = params.benchmarkMode; mDisablePlugins = params.disablePlugins; + mRedirectToFirstInstance = params.redirectToFirstInstance; mResPath = Sys::getProcessPath(); #if EE_PLATFORM == EE_PLATFORM_LINUX @@ -3840,6 +3854,14 @@ void App::init( InitParameters& params ) { mAsyncResourcesLoaded = true; mAsyncResourcesLoadCond.notify_all(); + + if ( mRedirectToFirstInstance ) { + std::string processName( FileSystem::fileNameFromPath( Sys::getProcessFilePath() ) ); + mFirstInstance = Sys::pidof( processName ).size() == 1; + std::string indicatorPath( firstInstanceIndicatorPath() ); + if ( !FileSystem::fileExists( indicatorPath ) ) + FileSystem::fileWrite( indicatorPath, "" ); + } } ); mWindow = engine->createWindow( winSettings, mConfig.context ); @@ -4504,6 +4526,11 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { "Disable all plugins. This option is not persisted and is effective " "only when the command opens a new window.", { "disable-plugins" } ); + args::Flag redirectToFirstInstance( + parser, "first-instance", + "When multiple ecode instances are running, the `--first-instance` flag opens a file in " + "the earliest launched instance instead of the most recently launched one.", + { "first-instance" } ); #ifdef EE_TEXT_SHAPER_ENABLED args::Flag textShaper( parser, "text-shaper", "Enables text-shaping capabilities", @@ -4586,6 +4613,7 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { ( exportLangPath && !exportLangPath.Get().empty() ); params.profile = profile.Get(); params.disablePlugins = disablePlugins.Get(); + params.redirectToFirstInstance = redirectToFirstInstance.Get(); appInstance = eeNew( App, ( jobs, args ) ); appInstance->init( params ); diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index a53a649f7..b193c4760 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -49,7 +49,7 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider { std::string css; std::string fileToOpen; bool stdOutLogs{ false }; - bool disableFileLogs{ false}; + bool disableFileLogs{ false }; bool openClean{ false }; bool portable{ false }; std::string language; @@ -57,6 +57,7 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider { bool prematureExit{ false }; std::string profile; bool disablePlugins{ false }; + bool redirectToFirstInstance{ false }; }; void init( InitParameters& ); @@ -362,13 +363,7 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider { mTerminalManager->configureTerminalScrollback(); } ); t.setCommand( "check-for-updates", [this] { mSettingsActions->checkForUpdates( false ); } ); - t.setCommand( "create-new-window", [] { - std::string processPath = Sys::getProcessFilePath(); - if ( !processPath.empty() ) { - std::string cmd( processPath + " -x" ); - Sys::execute( cmd ); - } - } ); + t.setCommand( "create-new-window", [this] { openInNewWindow(); } ); t.setCommand( "create-new-welcome-tab", [this] { createWelcomeTab(); } ); mSplitter->registerSplitterCommands( t ); @@ -625,6 +620,8 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider { bool mUseFrameBuffer{ false }; bool mBenchmarkMode{ false }; bool mDisablePlugins{ false }; + bool mRedirectToFirstInstance{ false }; + bool mFirstInstance{ false }; bool mPortableMode{ false }; bool mPortableModeFailed{ false }; bool mDestroyingApp{ false }; @@ -793,6 +790,10 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider { std::function getForcePositionFn( TextPosition initialPosition ); + + void openInNewWindow( const std::string& params = "" ); + + std::string firstInstanceIndicatorPath() const; }; } // namespace ecode