diff --git a/.ecode/project_build.json b/.ecode/project_build.json index 071c66627..162193d2c 100644 --- a/.ecode/project_build.json +++ b/.ecode/project_build.json @@ -38,5 +38,45 @@ "var": { "build_dir": "${project_root}/make/${os}" } + }, + "eepp": { + "build": [ + { + "args": "--with-debug-symbols gmake", + "command": "premake4", + "working_dir": "${project_root}" + }, + { + "args": "-j${nproc} config=${build_type}", + "command": "make", + "working_dir": "${build_dir}" + } + ], + "build_types": [ + "debug", + "release" + ], + "clean": [ + { + "args": "config=${build_type} clean", + "command": "make", + "working_dir": "${build_dir}" + } + ], + "config": { + "clear_sys_env": false + }, + "os": [ + "linux" + ], + "output_parser": { + "config": { + "preset": "generic", + "relative_file_paths": true + } + }, + "var": { + "build_dir": "${project_root}/make/${os}" + } } } \ No newline at end of file diff --git a/include/eepp/scene/event.hpp b/include/eepp/scene/event.hpp index e00e02857..fc1f7a0c8 100644 --- a/include/eepp/scene/event.hpp +++ b/include/eepp/scene/event.hpp @@ -98,6 +98,7 @@ class EE_API Event { OnWindowAdded, OnWindowRemoved, OnItemValueChange, + OnCopy, NoEvent = eeINDEX_NOT_FOUND }; diff --git a/include/eepp/ui/abstract/uiabstracttableview.hpp b/include/eepp/ui/abstract/uiabstracttableview.hpp index a1c0425a5..24976124e 100644 --- a/include/eepp/ui/abstract/uiabstracttableview.hpp +++ b/include/eepp/ui/abstract/uiabstracttableview.hpp @@ -112,6 +112,7 @@ class EE_API UIAbstractTableView : public UIAbstractView { /** Tries to make all columns visible in the widget content. */ void setFitAllColumnsToWidget( bool fitAllColumnsToWidget ); + void recalculateColumnsWidth(); protected: friend class EE::UI::UITableHeaderColumn; diff --git a/src/eepp/ui/abstract/uiabstracttableview.cpp b/src/eepp/ui/abstract/uiabstracttableview.cpp index 2e3cdfee1..076de6254 100644 --- a/src/eepp/ui/abstract/uiabstracttableview.cpp +++ b/src/eepp/ui/abstract/uiabstracttableview.cpp @@ -785,4 +785,8 @@ void UIAbstractTableView::setFitAllColumnsToWidget( bool fitAllColumnsToWidget ) mFitAllColumnsToWidget = fitAllColumnsToWidget; } +void UIAbstractTableView::recalculateColumnsWidth() { + createOrUpdateColumns( false ); +} + }}} // namespace EE::UI::Abstract diff --git a/src/eepp/ui/abstract/uiabstractview.cpp b/src/eepp/ui/abstract/uiabstractview.cpp index 0bad4957d..52e3ad346 100644 --- a/src/eepp/ui/abstract/uiabstractview.cpp +++ b/src/eepp/ui/abstract/uiabstractview.cpp @@ -153,7 +153,7 @@ void UIAbstractView::beginEditing( const ModelIndex& index, UIWidget* editedWidg mEditWidget->toFront(); mEditingDelegate->willBeginEditing(); mEditingDelegate->onCommit = [this]() { - if ( getModel() ) + if ( getModel() && mEditIndex.isValid() ) getModel()->setData( mEditIndex, mEditingDelegate->getValue() ); stopEditing(); }; diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 4999c40dd..1de1eba36 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -763,6 +763,18 @@ UITabWidget* App::getSidePanel() const { return mSidePanel; } +const std::map& App::getRealLocalKeybindings() const { + return mRealLocalKeybindings; +} + +const std::map& App::getRealSplitterKeybindings() const { + return mRealSplitterKeybindings; +} + +const std::map& App::getRealTerminalKeybindings() const { + return mRealTerminalKeybindings; +} + void App::switchSidePanel() { mConfig.ui.showSidePanel = !mConfig.ui.showSidePanel; mSettings->getWindowMenu() @@ -1387,41 +1399,91 @@ static void updateKeybindings( IniFile& ini, const std::string& group, Input* in } void App::loadKeybindings() { - if ( mKeybindings.empty() ) { - KeyBindings bindings( mWindow->getInput() ); - IniFile ini( mKeybindingsPath ); + if ( !mKeybindings.empty() ) + return; - std::string defMod = ini.getValue( "modifier", "mod", "" ); - if ( defMod.empty() ) { - defMod = KeyMod::getDefaultModifierString(); - ini.setValue( "modifier", "mod", defMod ); - ini.writeFile(); - } + KeyBindings bindings( mWindow->getInput() ); + IniFile ini( mKeybindingsPath ); - bool forceRebind = false; - auto version = ini.getValueU( "version", "version", 0 ); - if ( version != ecode::Version::getVersionNum() ) { - ini.setValueU( "version", "version", ecode::Version::getVersionNum() ); - ini.writeFile(); - forceRebind = true; - } - - Uint32 defModKeyCode = KeyMod::getKeyMod( defMod ); - if ( KEYMOD_NONE != defModKeyCode ) - KeyMod::setDefaultModifier( defModKeyCode ); - - updateKeybindings( ini, "editor", mWindow->getInput(), mKeybindings, mKeybindingsInvert, - getDefaultKeybindings(), forceRebind, getMigrateKeybindings(), - mConfig.iniState ); - - updateKeybindings( ini, "global_search", mWindow->getInput(), mGlobalSearchKeybindings, - GlobalSearchController::getDefaultKeybindings(), forceRebind, - getMigrateKeybindings(), mConfig.iniState ); - - updateKeybindings( ini, "document_search", mWindow->getInput(), mDocumentSearchKeybindings, - DocSearchController::getDefaultKeybindings(), forceRebind, - getMigrateKeybindings(), mConfig.iniState ); + std::string defMod = ini.getValue( "modifier", "mod", "" ); + if ( defMod.empty() ) { + defMod = KeyMod::getDefaultModifierString(); + ini.setValue( "modifier", "mod", defMod ); + ini.writeFile(); } + + bool forceRebind = false; + auto version = ini.getValueU( "version", "version", 0 ); + if ( version != ecode::Version::getVersionNum() ) { + ini.setValueU( "version", "version", ecode::Version::getVersionNum() ); + ini.writeFile(); + forceRebind = true; + } + + Uint32 defModKeyCode = KeyMod::getKeyMod( defMod ); + if ( KEYMOD_NONE != defModKeyCode ) + KeyMod::setDefaultModifier( defModKeyCode ); + + updateKeybindings( ini, "editor", mWindow->getInput(), mKeybindings, mKeybindingsInvert, + getDefaultKeybindings(), forceRebind, getMigrateKeybindings(), + mConfig.iniState ); + + updateKeybindings( ini, "global_search", mWindow->getInput(), mGlobalSearchKeybindings, + GlobalSearchController::getDefaultKeybindings(), forceRebind, + getMigrateKeybindings(), mConfig.iniState ); + + updateKeybindings( ini, "document_search", mWindow->getInput(), mDocumentSearchKeybindings, + DocSearchController::getDefaultKeybindings(), forceRebind, + getMigrateKeybindings(), mConfig.iniState ); + + auto localKeybindings = getLocalKeybindings(); + for ( const auto& kb : localKeybindings ) { + auto found = mKeybindingsInvert.find( kb.second ); + if ( found != mKeybindingsInvert.end() ) { + mRealLocalKeybindings[bindings.getShortcutFromString( found->second )] = kb.second; + } else { + mRealLocalKeybindings[kb.first] = kb.second; + } + } + + auto localSplitterKeybindings = UICodeEditorSplitter::getLocalDefaultKeybindings(); + for ( const auto& kb : localSplitterKeybindings ) { + auto found = mKeybindingsInvert.find( kb.second ); + if ( found != mKeybindingsInvert.end() ) { + mRealSplitterKeybindings[bindings.getShortcutFromString( found->second )] = kb.second; + } else { + mRealSplitterKeybindings[kb.first] = kb.second; + } + } + + auto localTerminalKeybindings = TerminalManager::getTerminalKeybindings(); + for ( const auto& kb : localTerminalKeybindings ) { + auto found = mKeybindingsInvert.find( kb.second ); + if ( found != mKeybindingsInvert.end() ) { + mRealTerminalKeybindings[bindings.getShortcutFromString( found->second )] = kb.second; + } else { + mRealTerminalKeybindings[kb.first] = kb.second; + } + } +} + +void App::reloadKeybindings() { + mKeybindings.clear(); + mKeybindingsInvert.clear(); + mRealLocalKeybindings.clear(); + mRealSplitterKeybindings.clear(); + mRealTerminalKeybindings.clear(); + mRealDefaultKeybindings.clear(); + loadKeybindings(); + mSplitter->forEachEditor( [&]( UICodeEditor* ed ) { + ed->getKeyBindings().reset(); + ed->getKeyBindings().addKeybindsStringUnordered( mKeybindings ); + } ); + mSplitter->forEachWidgetType( UI_TYPE_TERMINAL, [this]( UIWidget* widget ) { + mTerminalManager->setKeybindings( widget->asType() ); + } ); + mMainLayout->getKeyBindings().reset(); + mMainLayout->getKeyBindings().addKeybinds( getRealDefaultKeybindings() ); } void App::onDocumentStateChanged( UICodeEditor*, TextDocument& ) { @@ -1681,6 +1743,18 @@ AppConfig& App::getConfig() { return mConfig; } +const std::map& App::getRealDefaultKeybindings() { + if ( mRealDefaultKeybindings.empty() ) { + mRealDefaultKeybindings.insert( mRealLocalKeybindings.begin(), + mRealLocalKeybindings.end() ); + mRealDefaultKeybindings.insert( mRealSplitterKeybindings.begin(), + mRealSplitterKeybindings.end() ); + mRealDefaultKeybindings.insert( mRealTerminalKeybindings.begin(), + mRealTerminalKeybindings.end() ); + } + return mRealDefaultKeybindings; +} + std::map App::getDefaultKeybindings() { auto bindings = UICodeEditorSplitter::getDefaultKeybindings(); auto local = getLocalKeybindings(); @@ -1715,10 +1789,10 @@ std::map App::getLocalKeybindings() { { { KEY_K, KEYMOD_CTRL | KEYMOD_LALT | KEYMOD_SHIFT }, "terminal-split-bottom" }, { { KEY_S, KEYMOD_CTRL | KEYMOD_LALT | KEYMOD_SHIFT }, "terminal-split-swap" }, { { KEY_T, KEYMOD_CTRL | KEYMOD_LALT | KEYMOD_SHIFT }, "reopen-closed-tab" }, - { { KEY_1, KEYMOD_LALT }, "toggle-locatebar" }, - { { KEY_2, KEYMOD_LALT }, "toggle-global-search" }, - { { KEY_3, KEYMOD_LALT }, "toggle-status-build-output" }, - { { KEY_4, KEYMOD_LALT }, "toggle-status-terminal" }, + { { KEY_1, KEYMOD_LALT }, "toggle-status-locate-bar" }, + { { KEY_2, KEYMOD_LALT }, "toggle-status-global-search-bar" }, + { { KEY_3, KEYMOD_LALT }, "toggle-status-terminal" }, + { { KEY_4, KEYMOD_LALT }, "toggle-status-build-output" }, }; } @@ -1749,8 +1823,8 @@ std::vector App::getUnlockedCommands() { "open-global-search", "project-build-start", "project-build-cancel", - "toggle-locatebar", - "toggle-global-search", + "toggle-status-locate-bar", + "toggle-status-global-search-bar", "toggle-status-build-output", "toggle-status-terminal", "menu-toggle", @@ -2120,13 +2194,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { if ( mSplitter->curEditorExistsAndFocused() && mSplitter->getCurEditor() == editor ) editor->setFocus(); if ( editor->getDocument().getFilePath() == mKeybindingsPath ) { - mKeybindings.clear(); - mKeybindingsInvert.clear(); - loadKeybindings(); - mSplitter->forEachEditor( [&]( UICodeEditor* ed ) { - ed->getKeyBindings().reset(); - ed->getKeyBindings().addKeybindsStringUnordered( mKeybindings ); - } ); + reloadKeybindings(); } else if ( mFileSystemMatcher && mFileSystemMatcher->getIgnoreFilePath() == editor->getDocument().getFilePath() ) { loadFileSystemMatcher( mFileSystemMatcher ? mFileSystemMatcher->getPath() @@ -3532,10 +3600,10 @@ TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child - - - - + + + + @@ -3821,7 +3889,6 @@ TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child mMainSplitter->setSplitPartition( StyleSheetLength( mConfig.windowState.statusBarPartition ) ); mStatusBar = mUISceneNode->find( "status_bar" ); - mStatusBar->setApp( this ); #if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN mFileWatcher = new efsw::FileWatcher(); @@ -3856,6 +3923,8 @@ TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child initImageView(); + mStatusBar->setApp( this ); + mSettings = std::make_unique(); mSettings->createSettingsMenu( this ); @@ -3867,7 +3936,7 @@ TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child mConsole->setVisible( false ); registerUnlockedCommands( *mMainLayout ); - mMainLayout->getKeyBindings().addKeybinds( getDefaultKeybindings() ); + mMainLayout->getKeyBindings().addKeybinds( getRealDefaultKeybindings() ); Log::instance()->setKeepLog( false ); Log::info( "Complete UI took: %.2f ms", globalClock.getElapsedTime().asMilliseconds() ); diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index 22e5b252c..95bdf7c46 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -133,6 +133,8 @@ class App : public UICodeEditorSplitter::Client { Drawable* findIcon( const std::string& name, const size_t iconSize ); + const std::map& getRealDefaultKeybindings(); + std::map getDefaultKeybindings(); std::map getLocalKeybindings(); @@ -226,13 +228,13 @@ class App : public UICodeEditorSplitter::Client { t.setCommand( "console-toggle", [&] { consoleToggle(); } ); t.setCommand( "find-replace", [&] { showFindView(); } ); t.setCommand( "open-global-search", [&] { showGlobalSearch( false ); } ); - t.setCommand( "toggle-global-search", + t.setCommand( "toggle-status-global-search-bar", [&] { mGlobalSearchController->toggleGlobalSearchBar(); } ); t.setCommand( "toggle-status-build-output", [&] { mStatusBuildOutputController->toggle(); } ); t.setCommand( "toggle-status-terminal", [&] { mStatusTerminalController->toggle(); } ); t.setCommand( "open-locatebar", [&] { mUniversalLocator->showLocateBar(); } ); - t.setCommand( "toggle-locatebar", [&] { mUniversalLocator->toggleLocateBar(); } ); + t.setCommand( "toggle-status-locate-bar", [&] { mUniversalLocator->toggleLocateBar(); } ); t.setCommand( "open-command-palette", [&] { mUniversalLocator->showCommandPalette(); } ); t.setCommand( "project-build-start", [&] { if ( mProjectBuildManager && mStatusBuildOutputController ) { @@ -395,7 +397,13 @@ class App : public UICodeEditorSplitter::Client { UITabWidget* getSidePanel() const; - protected: + const std::map& getRealLocalKeybindings() const; + + const std::map& getRealSplitterKeybindings() const; + + const std::map& getRealTerminalKeybindings() const; + + protected: std::vector mArgs; EE::Window::Window* mWindow{ nullptr }; UISceneNode* mUISceneNode{ nullptr }; @@ -418,6 +426,10 @@ class App : public UICodeEditorSplitter::Client { std::unordered_map mKeybindingsInvert; std::unordered_map mGlobalSearchKeybindings; std::unordered_map mDocumentSearchKeybindings; + std::map mRealLocalKeybindings; + std::map mRealSplitterKeybindings; + std::map mRealTerminalKeybindings; + std::map mRealDefaultKeybindings; std::string mConfigPath; std::string mPluginsPath; std::string mColorSchemesPath; @@ -502,6 +514,8 @@ class App : public UICodeEditorSplitter::Client { void loadKeybindings(); + void reloadKeybindings(); + void onDocumentStateChanged( UICodeEditor*, TextDocument& ); void onDocumentModified( UICodeEditor* editor, TextDocument& ); diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index cff189707..fd6c245a1 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -845,7 +845,8 @@ void LSPClientPlugin::loadLSPConfig( std::vector& lsps, const std std::string name = obj.contains( "name" ) ? obj["name"] : obj["use"]; if ( lspR.name == name ) { lspOverwritten = true; - lspR.usesOtherDefinition = obj.contains( "use" ); + if ( obj.contains( "use" ) && obj["use"].is_string() ) + lspR.usesLSP = obj["use"].get(); if ( obj.contains( "share_process" ) && obj["share_process"].is_boolean() ) { lspR.shareProcessWithOtherDefinition = obj["share_process"].get(); } @@ -896,7 +897,7 @@ void LSPClientPlugin::loadLSPConfig( std::vector& lsps, const std lsp.host = tlsp.host; lsp.port = tlsp.port; lsp.initializationOptions = tlsp.initializationOptions; - lsp.usesOtherDefinition = true; + lsp.usesLSP = use; if ( obj.contains( "share_process" ) && obj["share_process"].is_boolean() ) { lsp.shareProcessWithOtherDefinition = obj["share_process"].get(); } diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.cpp b/src/tools/ecode/plugins/lsp/lspclientserver.cpp index 1f629429d..45e81f0a0 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.cpp @@ -1114,8 +1114,13 @@ void LSPClientServer::initialize() { } LSPClientServer::LSPClientServer( LSPClientServerManager* manager, const String::HashType& id, - const LSPDefinition& lsp, const std::string& rootPath ) : - mManager( manager ), mId( id ), mLSP( lsp ), mRootPath( rootPath ) {} + const LSPDefinition& lsp, const std::string& rootPath, + const std::vector& languagesSupported ) : + mManager( manager ), + mId( id ), + mLSP( lsp ), + mRootPath( rootPath ), + mLanguagesSupported( languagesSupported ) {} LSPClientServer::~LSPClientServer() { shutdown(); @@ -2050,4 +2055,9 @@ void LSPClientServer::shutdown() { } } +bool LSPClientServer::supportsLanguage( const std::string& lang ) const { + return std::find( mLanguagesSupported.begin(), mLanguagesSupported.end(), lang ) != + mLanguagesSupported.end(); +} + } // namespace ecode diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.hpp b/src/tools/ecode/plugins/lsp/lspclientserver.hpp index 55598deec..60e4d10b0 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.hpp @@ -61,7 +61,8 @@ class LSPClientServer { }; LSPClientServer( LSPClientServerManager* manager, const String::HashType& id, - const LSPDefinition& lsp, const std::string& rootPath ); + const LSPDefinition& lsp, const std::string& rootPath, + const std::vector& languagesSupported ); ~LSPClientServer(); @@ -221,6 +222,8 @@ class LSPClientServer { void shutdown(); + bool supportsLanguage( const std::string& lang ) const; + protected: LSPClientServerManager* mManager{ nullptr }; String::HashType mId; @@ -247,6 +250,7 @@ class LSPClientServer { std::string mReceiveErr; LSPServerCapabilities mCapabilities; URI mWorkspaceFolder; + std::vector mLanguagesSupported; struct DidChangeQueue { URI uri; diff --git a/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp b/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp index 5ea3b106a..892ece3e9 100644 --- a/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp @@ -45,8 +45,9 @@ LSPClientServerManager::supportsLSP( const std::shared_ptr& doc ) std::unique_ptr LSPClientServerManager::runLSPServer( const String::HashType& id, const LSPDefinition& lsp, - const std::string& rootPath ) { - auto server = std::make_unique( this, id, lsp, rootPath ); + const std::string& rootPath, + std::vector languagesSupported ) { + auto server = std::make_unique( this, id, lsp, rootPath, languagesSupported ); server->start(); return server; } @@ -96,7 +97,22 @@ void LSPClientServerManager::tryRunServer( const std::shared_ptr& Lock l( mClientsMutex ); auto clientIt = mClients.find( id ); if ( clientIt == mClients.end() ) { - std::unique_ptr serverUP = runLSPServer( id, lsp, rootPath ); + auto rlsp = lsp; + if ( !lsp.usesLSP.empty() ) { + for ( const auto& flsp : mLSPs ) { + if ( flsp.name == lsp.usesLSP ) { + rlsp = flsp; + break; + } + } + } + std::vector languagesSupported; + languagesSupported.push_back( rlsp.language ); + for ( const auto& flsp : mLSPs ) + if ( flsp.name == lsp.usesLSP ) + languagesSupported.push_back( flsp.language ); + std::unique_ptr serverUP = + runLSPServer( id, rlsp, rootPath, languagesSupported ); if ( ( server = serverUP.get() ) ) { mClients[id] = std::move( serverUP ); if ( !mLSPWorkspaceFolder.uri.empty() ) @@ -471,7 +487,7 @@ LSPClientServer* LSPClientServerManager::getOneLSPClientServer( const URI& uri ) LSPClientServer* LSPClientServerManager::getOneLSPClientServer( const std::string& language ) { Lock l( mClientsMutex ); for ( auto& server : mClients ) { - if ( server.second->getDefinition().language == language ) + if ( server.second->supportsLanguage( language ) ) return server.second.get(); } return nullptr; @@ -482,7 +498,7 @@ LSPClientServerManager::getLSPClientServers( const std::string& language ) { std::vector servers; Lock l( mClientsMutex ); for ( auto& server : mClients ) { - if ( server.second->getDefinition().language == language ) + if ( server.second->supportsLanguage( language ) ) servers.push_back( server.second.get() ); } return servers; diff --git a/src/tools/ecode/plugins/lsp/lspclientservermanager.hpp b/src/tools/ecode/plugins/lsp/lspclientservermanager.hpp index ea699c483..b3e7ed5b9 100644 --- a/src/tools/ecode/plugins/lsp/lspclientservermanager.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientservermanager.hpp @@ -114,7 +114,8 @@ class LSPClientServerManager { std::unique_ptr runLSPServer( const String::HashType& id, const LSPDefinition& lsp, - const std::string& rootPath ); + const std::string& rootPath, + std::vector languagesSupported ); std::string findRootPath( const LSPDefinition& lsp, const std::shared_ptr& doc ); diff --git a/src/tools/ecode/plugins/lsp/lspdefinition.hpp b/src/tools/ecode/plugins/lsp/lspdefinition.hpp index 2224ab2be..7939e4657 100644 --- a/src/tools/ecode/plugins/lsp/lspdefinition.hpp +++ b/src/tools/ecode/plugins/lsp/lspdefinition.hpp @@ -24,7 +24,7 @@ struct LSPDefinition { int port{ 0 }; nlohmann::json initializationOptions; - bool usesOtherDefinition{ false }; + std::string usesLSP; bool shareProcessWithOtherDefinition{ false }; bool disabled{ false }; diff --git a/src/tools/ecode/projectbuild.cpp b/src/tools/ecode/projectbuild.cpp index bc8677777..9b3ef52b5 100644 --- a/src/tools/ecode/projectbuild.cpp +++ b/src/tools/ecode/projectbuild.cpp @@ -170,9 +170,113 @@ ProjectBuildManager::ProjectBuildManager( const std::string& projectRoot, void ProjectBuildManager::addNewBuild() { std::string name = mNewBuild.getName(); - ProjectBuild build = mNewBuild; + ProjectBuild newBuild = mNewBuild; + bool found; + do { + found = false; + for ( const auto& b : mBuilds ) { + if ( b.first == name ) { + name += " (" + mApp->i18n( "copy", "Copy" ) + ")"; + found = true; + } + } + } while ( found ); + newBuild.mName = name; mBuilds.insert( - std::make_pair( std::move( name ), std::move( build ) ) ); + std::make_pair( std::move( name ), std::move( newBuild ) ) ); +} + +bool ProjectBuildManager::cloneBuild( const std::string& build, std::string newBuildName ) { + auto oldBuild = mBuilds.find( build ); + if ( oldBuild == mBuilds.end() ) + return false; + ProjectBuild newBuild = oldBuild->second; + newBuild.mName = newBuildName; + mBuilds.insert( std::make_pair( std::move( newBuildName ), + std::move( newBuild ) ) ); + return true; +} + +void ProjectBuildManager::addBuild( UIWidget* buildTab ) { + mNewBuild = ProjectBuild( mApp->i18n( "new_name", "new_name" ), mProjectRoot ); + std::string hashName = String::toString( String::hash( "new_name" ) ); + UIWidget* widget = nullptr; + if ( ( widget = buildTab->getUISceneNode()->getRoot()->querySelector( "#build_settings_" + + hashName ) ) ) { + widget->asType()->select(); + return; + } + auto ret = + mApp->getSplitter()->createWidget( UIBuildSettings::New( mNewBuild, mConfig, true ), + mApp->i18n( "build_settings", "Build Settings" ) ); + auto bs = ret.second->asType(); + bs->setTab( ret.first ); + mCbs[bs].insert( bs->on( Event::OnConfirm, [this, bs]( const Event* event ) { + event->getNode()->removeEventListener( event->getCallbackId() ); + mCbs[bs].erase( event->getCallbackId() ); + addNewBuild(); + saveAsync(); + updateSidePanelTab(); + } ) ); + mCbs[bs].insert( bs->on( Event::OnClose, [this, bs]( auto ) { mCbs.erase( bs ); } ) ); + bs->on( Event::OnClear, [this]( const Event* event ) { + if ( mBuilds.erase( event->asTextEvent()->getText() ) > 0 ) { + if ( mConfig.buildName == event->asTextEvent()->getText() ) + mConfig.buildName = mBuilds.empty() ? "" : mBuilds.begin()->first; + updateSidePanelTab(); + } + } ); + ret.first->setIcon( mApp->findIcon( "hammer" ) ); +} + +void ProjectBuildManager::editBuild( std::string buildName, UIWidget* buildTab ) { + if ( buildName.empty() ) + return; + + auto build = mBuilds.find( buildName ); + if ( build == mBuilds.end() ) + return; + + std::string hashName = String::toString( String::hash( buildName ) ); + UIWidget* widget = nullptr; + if ( ( widget = buildTab->getUISceneNode()->getRoot()->querySelector( "#build_settings_" + + hashName ) ) ) { + widget->asType()->select(); + return; + } + auto ret = + mApp->getSplitter()->createWidget( UIBuildSettings::New( build->second, mConfig, false ), + mApp->i18n( "build_settings", "Build Settings" ) ); + auto bs = ret.second->asType(); + bs->setTab( ret.first ); + mCbs[bs].insert( bs->on( Event::OnConfirm, [this, bs]( const Event* event ) { + event->getNode()->removeEventListener( event->getCallbackId() ); + mCbs[bs].erase( event->getCallbackId() ); + saveAsync(); + } ) ); + mCbs[bs].insert( bs->on( Event::OnClose, [this, bs]( auto ) { mCbs.erase( bs ); } ) ); + bs->on( Event::OnClear, [this]( const Event* event ) { + if ( mBuilds.erase( event->asTextEvent()->getText() ) > 0 ) { + if ( mConfig.buildName == event->asTextEvent()->getText() ) + mConfig.buildName = mBuilds.empty() ? "" : mBuilds.begin()->first; + updateSidePanelTab(); + } + } ); + bs->on( Event::OnCopy, [this, buildName, buildTab]( const Event* event ) { + std::string clonedName( event->asTextEvent()->getText() ); + if ( mBuilds.find( clonedName ) != mBuilds.end() ) { + UIMessageBox::New( + UIMessageBox::OK, + mApp->i18n( "cloned_name_must_be_different", + "Cloned name must be different from any existing build name." ) ) + ->show(); + } else { + cloneBuild( buildName, clonedName ); + updateSidePanelTab(); + editBuild( clonedName, buildTab ); + } + } ); + ret.first->setIcon( mApp->findIcon( "hammer" ) ); } ProjectBuildManager::~ProjectBuildManager() { @@ -746,6 +850,8 @@ void ProjectBuildManager::updateSidePanelTab() { first = tbuild.first; } + std::sort( buildNamesItems.begin(), buildNamesItems.end() ); + buildList->getListBox()->addListBoxItems( buildNamesItems ); if ( !first.empty() && buildList->getListBox()->getItemIndex( first ) != eeINDEX_NOT_FOUND ) { @@ -792,80 +898,15 @@ void ProjectBuildManager::updateSidePanelTab() { } } ); - buildAdd->onClick( [this, buildTab]( auto ) { - mNewBuild = ProjectBuild( mApp->i18n( "new_name", "new_name" ), mProjectRoot ); - UIWidget* widget = nullptr; - if ( ( widget = buildTab->getUISceneNode()->getRoot()->querySelector( - "#build_settings_new_name" ) ) ) { - widget->asType()->select(); - return; - } - auto ret = - mApp->getSplitter()->createWidget( UIBuildSettings::New( mNewBuild, mConfig, true ), - mApp->i18n( "build_settings", "Build Settings" ) ); - auto bs = ret.second->asType(); - bs->setTab( ret.first ); - mCbs[bs].insert( bs->on( Event::OnConfirm, [this, bs]( const Event* event ) { - event->getNode()->removeEventListener( event->getCallbackId() ); - mCbs[bs].erase( event->getCallbackId() ); - std::string name = mNewBuild.getName(); - ProjectBuild build = mNewBuild; - mBuilds.insert( std::make_pair( std::move( name ), - std::move( build ) ) ); - saveAsync(); - updateSidePanelTab(); - } ) ); - mCbs[bs].insert( bs->on( Event::OnClose, [this, bs]( auto ) { mCbs.erase( bs ); } ) ); - bs->on( Event::OnClear, [this]( const Event* event ) { - if ( mBuilds.erase( event->asTextEvent()->getText() ) > 0 ) { - if ( mConfig.buildName == event->asTextEvent()->getText() ) - mConfig.buildName = mBuilds.empty() ? "" : mBuilds.begin()->first; - updateSidePanelTab(); - } - } ); - ret.first->setIcon( mApp->findIcon( "hammer" ) ); - } ); + buildAdd->onClick( [this, buildTab]( auto ) { addBuild( buildTab ); } ); - buildEdit->onClick( [this, buildTab]( auto ) { - if ( !mConfig.buildName.empty() ) { - auto build = mBuilds.find( mConfig.buildName ); - if ( build != mBuilds.end() ) { - UIWidget* widget = nullptr; - if ( ( widget = buildTab->getUISceneNode()->getRoot()->querySelector( - "#build_settings_" + mConfig.buildName ) ) ) { - widget->asType()->select(); - return; - } - auto ret = mApp->getSplitter()->createWidget( - UIBuildSettings::New( build->second, mConfig, false ), - mApp->i18n( "build_settings", "Build Settings" ) ); - auto bs = ret.second->asType(); - bs->setTab( ret.first ); - mCbs[bs].insert( bs->on( Event::OnConfirm, [this, bs]( const Event* event ) { - event->getNode()->removeEventListener( event->getCallbackId() ); - mCbs[bs].erase( event->getCallbackId() ); - saveAsync(); - } ) ); - mCbs[bs].insert( - bs->on( Event::OnClose, [this, bs]( auto ) { mCbs.erase( bs ); } ) ); - bs->on( Event::OnClear, [this]( const Event* event ) { - if ( mBuilds.erase( event->asTextEvent()->getText() ) > 0 ) { - if ( mConfig.buildName == event->asTextEvent()->getText() ) - mConfig.buildName = mBuilds.empty() ? "" : mBuilds.begin()->first; - updateSidePanelTab(); - } - } ); - ret.first->setIcon( mApp->findIcon( "hammer" ) ); - } - } - } ); + buildEdit->onClick( [this, buildTab]( auto ) { editBuild( mConfig.buildName, buildTab ); } ); } void ProjectBuildManager::updateBuildType() { UIWidget* buildTab = mTab->getOwnedWidget()->find( "build_tab" ); UIDropDownList* buildList = buildTab->find( "build_list" ); UIDropDownList* buildTypeList = buildTab->find( "build_type_list" ); - // UIPushButton* buildTypeAdd = buildTab->find( "build_type_add" ); buildTypeList->getListBox()->clear(); @@ -888,7 +929,6 @@ void ProjectBuildManager::updateBuildType() { } } buildTypeList->setEnabled( !buildTypeList->getListBox()->isEmpty() ); - // buildTypeAdd->setEnabled( !mConfig.buildName.empty() ); buildTypeList->removeEventsOfType( Event::OnItemSelected ); buildTypeList->addEventListener( Event::OnItemSelected, [this, buildTypeList]( const Event* ) { diff --git a/src/tools/ecode/projectbuild.hpp b/src/tools/ecode/projectbuild.hpp index cd8a510a2..abe52794d 100644 --- a/src/tools/ecode/projectbuild.hpp +++ b/src/tools/ecode/projectbuild.hpp @@ -320,6 +320,12 @@ class ProjectBuildManager { void updateBuildType(); void addNewBuild(); + + bool cloneBuild( const std::string& build, std::string newBuildName ); + + void addBuild( UIWidget* buildTab ); + + void editBuild( std::string buildName, UIWidget* buildTab ); }; } // namespace ecode diff --git a/src/tools/ecode/statusbuildoutputcontroller.cpp b/src/tools/ecode/statusbuildoutputcontroller.cpp index 97e236637..e590c0902 100644 --- a/src/tools/ecode/statusbuildoutputcontroller.cpp +++ b/src/tools/ecode/statusbuildoutputcontroller.cpp @@ -240,10 +240,10 @@ void StatusBuildOutputController::runClean( const std::string& buildName, if ( EXIT_SUCCESS == exitCode ) { buffer = Sys::getDateTimeStr() + ": " + - mApp->i18n( "build_successful", "Build run successfully\n" ); + mApp->i18n( "clean_successful", "Clean run successfully\n" ); } else { buffer = Sys::getDateTimeStr() + ": " + - mApp->i18n( "build_failed", "Build run with errors\n" ); + mApp->i18n( "clean_failed", "Clean run with errors\n" ); } mContainer->runOnMainThread( [this, buffer]() { @@ -278,6 +278,10 @@ UICodeEditor* StatusBuildOutputController::createContainer() { editor->setLocked( true ); editor->setLineBreakingColumn( 0 ); editor->setShowLineNumber( false ); + editor->getDocument().reset(); + editor->getDocument().textInput( + mApp->i18n( "no_build_has_been_run", "No build has been run" ) ); + editor->setScrollY( editor->getMaxScroll().y ); return editor; } diff --git a/src/tools/ecode/statusterminalcontroller.cpp b/src/tools/ecode/statusterminalcontroller.cpp index 635f9d665..fc40d0602 100644 --- a/src/tools/ecode/statusterminalcontroller.cpp +++ b/src/tools/ecode/statusterminalcontroller.cpp @@ -95,16 +95,7 @@ UITerminal* StatusTerminalController::createTerminal( const std::string& working term->setColorScheme( csIt != terminalColorSchemes.end() ? terminalColorSchemes.at( currentTerminalColorScheme ) : TerminalColorScheme::getDefault() ); - term->addKeyBinds( mApp->getLocalKeybindings() ); - term->addKeyBinds( UICodeEditorSplitter::getLocalDefaultKeybindings() ); - term->addKeyBinds( { { { KEY_E, KEYMOD_CTRL | KEYMOD_LALT | KEYMOD_SHIFT }, - UITerminal::getExclusiveModeToggleCommandName() } } ); - // Remove the keybinds that are problematic for a terminal - term->getKeyBindings().removeCommandsKeybind( - { "open-file", "download-file-web", "open-folder", "debug-draw-highlight-toggle", - "debug-draw-boxes-toggle", "debug-draw-debug-data", "debug-widget-tree-view", - "open-locatebar", "open-command-palette", "open-global-search", "menu-toggle", - "console-toggle", "go-to-line" } ); + mApp->getTerminalManager()->setKeybindings( term ); term->setCommand( "switch-to-previous-colorscheme", [&] { auto it = mApp->getTerminalManager()->getTerminalColorSchemes().find( mApp->getTerminalManager()->getTerminalCurrentColorScheme() ); diff --git a/src/tools/ecode/terminalmanager.cpp b/src/tools/ecode/terminalmanager.cpp index 521235381..fd4b85227 100644 --- a/src/tools/ecode/terminalmanager.cpp +++ b/src/tools/ecode/terminalmanager.cpp @@ -287,15 +287,7 @@ UITerminal* TerminalManager::createNewTerminal( const std::string& title, UITabW return; mApp->setAppTitle( event->getNode()->asType()->getTitle() ); } ); - term->addKeyBinds( mApp->getLocalKeybindings() ); - term->addKeyBinds( UICodeEditorSplitter::getLocalDefaultKeybindings() ); - term->addKeyBinds( getTerminalKeybindings() ); - // Remove the keybinds that are problematic for a terminal - term->getKeyBindings().removeCommandsKeybind( - { "open-file", "download-file-web", "open-folder", "debug-draw-highlight-toggle", - "debug-draw-boxes-toggle", "debug-draw-debug-data", "debug-widget-tree-view", - "open-locatebar", "open-command-palette", "open-global-search", "menu-toggle", - "console-toggle", "go-to-line" } ); + setKeybindings( term ); term->setCommand( "terminal-rename", [&, term] { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, mApp->i18n( "new_terminal_name", "New terminal name:" ) ); @@ -336,4 +328,17 @@ UITerminal* TerminalManager::createNewTerminal( const std::string& title, UITabW #endif } +void TerminalManager::setKeybindings( UITerminal* term ) { + term->getKeyBindings().reset(); + term->addKeyBinds( mApp->getRealLocalKeybindings() ); + term->addKeyBinds( mApp->getRealSplitterKeybindings() ); + term->addKeyBinds( mApp->getRealTerminalKeybindings() ); + // Remove the keybinds that are problematic for a terminal + term->getKeyBindings().removeCommandsKeybind( + { "open-file", "download-file-web", "open-folder", "debug-draw-highlight-toggle", + "debug-draw-boxes-toggle", "debug-draw-debug-data", "debug-widget-tree-view", + "open-locatebar", "open-command-palette", "open-global-search", "menu-toggle", + "console-toggle", "go-to-line" } ); +} + } // namespace ecode diff --git a/src/tools/ecode/terminalmanager.hpp b/src/tools/ecode/terminalmanager.hpp index f039de8ed..4135badcb 100644 --- a/src/tools/ecode/terminalmanager.hpp +++ b/src/tools/ecode/terminalmanager.hpp @@ -50,6 +50,8 @@ class TerminalManager { const std::string& getTerminalCurrentColorScheme() { return mTerminalCurrentColorScheme; } + void setKeybindings( UITerminal* term ); + protected: App* mApp; std::string mTerminalColorSchemesPath; diff --git a/src/tools/ecode/uibuildsettings.cpp b/src/tools/ecode/uibuildsettings.cpp index 788082a7b..1bc049c43 100644 --- a/src/tools/ecode/uibuildsettings.cpp +++ b/src/tools/ecode/uibuildsettings.cpp @@ -306,6 +306,7 @@ static const auto SETTINGS_PANEL_XML = R"xml( + @@ -543,6 +544,23 @@ UIBuildSettings::UIBuildSettings( ProjectBuild& build, ProjectBuildConfiguration } ); } ); + find( "build_clone" )->onClick( [this]( auto ) { + UIMessageBox* msgBox = UIMessageBox::New( + UIMessageBox::INPUT, i18n( "build_cloned_name", "New Cloned Build Name:" ) ); + msgBox->setTitle( i18n( "build_settings", "Build Settings" ) ); + msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + msgBox->showWhenReady(); + msgBox->on( Event::OnWindowReady, [this, msgBox]( auto ) { + msgBox->getTextInput()->setText( mBuild.getName() ); + msgBox->getTextInput()->getDocument().selectAll(); + } ); + msgBox->addEventListener( Event::OnConfirm, [msgBox, this]( const Event* ) { + const auto& newBuildName = msgBox->getTextInput()->getText(); + sendTextEvent( Event::OnCopy, newBuildName ); + msgBox->closeWindow(); + } ); + } ); + find( "build_type_add" )->onClick( [this, buildTypeDropDown, panelBuildTypeDDL]( auto ) { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "build_type_name", "Build Type Name:" ) ); @@ -663,23 +681,26 @@ void UIBuildSettings::refreshTab() { mTab->setText( String::format( ( i18n( "build_seetings", "Build Settings" ) + ": %s" ).toUtf8().c_str(), mBuild.mName.c_str() ) ); - mTab->setId( "build_settings_" + mBuild.mName ); + std::string hashName = String::toString( String::hash( mIsNew ? "new_name" : mBuild.mName ) ); + mTab->setId( "build_settings_" + hashName ); } void UIBuildSettings::bindTable( const std::string& name, const std::string& key, ProjectBuildKeyVal& data ) { - const auto createInputDelegate = []( const ModelIndex& ) -> ModelEditingDelegate* { + UITableView* table = find( name ); + auto model = ItemPairListModel::create( data ); + const auto createInputDelegate = [table]( const ModelIndex& ) -> ModelEditingDelegate* { auto delegate = StringModelEditingDelegate::New(); - delegate->onWillBeginEditing = [delegate]() { - delegate->getWidget()->asType()->on( - Event::OnFocusLoss, [delegate]( auto ) { delegate->onCommit(); } ); + delegate->onWillBeginEditing = [delegate, table]() { + delegate->getWidget()->asType()->on( Event::OnFocusLoss, + [delegate, table]( auto ) { + delegate->onCommit(); + table->recalculateColumnsWidth(); + } ); }; return delegate; }; - - UITableView* table = find( name ); - auto model = ItemPairListModel::create( data ); model->setColumnName( 0, getTranslatorString( key + "_name", "Name" ) ); model->setColumnName( 1, getTranslatorString( key + "_value", "Value" ) ); model->setIsEditable( true ); diff --git a/src/tools/ecode/uistatusbar.cpp b/src/tools/ecode/uistatusbar.cpp index 3ed839ea9..c8456d97a 100644 --- a/src/tools/ecode/uistatusbar.cpp +++ b/src/tools/ecode/uistatusbar.cpp @@ -14,6 +14,20 @@ UIStatusBar::UIStatusBar() : WidgetCommandExecuter( getUISceneNode()->getWindow()->getInput() ) {} void UIStatusBar::updateState() { + forEachChild( [this]( Node* node ) { + if ( node->isWidget() && String::startsWith( node->getId(), "status_" ) ) { + auto widget = node->asType(); + widget->removeClass( "selected" ); + if ( nullptr == widget->getTooltip() ) { + std::string name( widget->getId() ); + String::replaceAll( name, "_", "-" ); + auto kb = mApp->getKeybind( "toggle-" + name ); + if ( !kb.empty() ) + widget->setTooltipText( kb ); + } + } + } ); + getParent()->forEachChild( [this]( Node* node ) { UIWidget* but = find( "status_" + node->getId() ); if ( but && but != this ) { @@ -25,23 +39,14 @@ void UIStatusBar::updateState() { } } ); - UIWidget* termBut = find( "status_terminal" ); - if ( termBut ) - termBut->removeClass( "selected" ); - UIWidget* boBut = find( "status_build_output" ); - if ( boBut ) - boBut->removeClass( "selected" ); - - if ( mApp->getMainSplitter() ) { - if ( mApp->getMainSplitter()->getLastWidget() ) { - UIWidget* widget = mApp->getMainSplitter()->getLastWidget(); - UIWidget* but = find( "status_" + widget->getId() ); - if ( but && but != this ) { - if ( widget->isVisible() ) { - but->addClass( "selected" ); - } else { - but->removeClass( "selected" ); - } + if ( mApp->getMainSplitter() && mApp->getMainSplitter()->getLastWidget() ) { + UIWidget* widget = mApp->getMainSplitter()->getLastWidget(); + UIWidget* but = find( "status_" + widget->getId() ); + if ( but && but != this ) { + if ( widget->isVisible() ) { + but->addClass( "selected" ); + } else { + but->removeClass( "selected" ); } } } @@ -80,6 +85,7 @@ Uint32 UIStatusBar::onMessage( const NodeMessage* msg ) { void UIStatusBar::setApp( App* app ) { mApp = app; + updateState(); } void UIStatusBar::onVisibilityChange() { @@ -87,4 +93,9 @@ void UIStatusBar::onVisibilityChange() { updateState(); } +void UIStatusBar::onChildCountChange( Node*, const bool& ) { + if ( mApp ) + updateState(); +} + } // namespace ecode diff --git a/src/tools/ecode/uistatusbar.hpp b/src/tools/ecode/uistatusbar.hpp index b867a14dc..fecb72dc8 100644 --- a/src/tools/ecode/uistatusbar.hpp +++ b/src/tools/ecode/uistatusbar.hpp @@ -28,6 +28,8 @@ class UIStatusBar : public UILinearLayout, public WidgetCommandExecuter { App* mApp{ nullptr }; virtual void onVisibilityChange(); + + virtual void onChildCountChange( Node* child, const bool& removed ); }; } // namespace ecode diff --git a/src/tools/ecode/uiwelcomescreen.cpp b/src/tools/ecode/uiwelcomescreen.cpp index 16ac506f9..20adff8c0 100644 --- a/src/tools/ecode/uiwelcomescreen.cpp +++ b/src/tools/ecode/uiwelcomescreen.cpp @@ -178,7 +178,6 @@ UIWelcomeScreen::UIWelcomeScreen( App* app ) : setId( "welcome_ecode" ); setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent ); app->registerUnlockedCommands( *this ); - getKeyBindings().addKeybinds( app->getDefaultKeybindings() ); getUISceneNode()->loadLayoutFromString( LAYOUT, this, String::hash( "UIWelcomeScreen" ) ); auto bindBtn = [this]( const std::string& id ) {