From d11c4ce865e2811fc2ecdcc971a0c2de3aecc72e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Fri, 30 Jun 2023 00:37:10 -0300 Subject: [PATCH] eepp: Reduced the default indent in UITreeView. ecode: Search Project every minute when editor is active. Added "Copy Error Message" in editor right-click context menu --- include/eepp/ui/uiwidget.hpp | 22 ++--- src/eepp/ui/uitreeview.cpp | 2 +- src/tools/ecode/appconfig.cpp | 89 +++++++++---------- src/tools/ecode/appconfig.hpp | 2 +- src/tools/ecode/ecode.cpp | 29 +++--- src/tools/ecode/ecode.hpp | 2 + .../ecode/plugins/linter/linterplugin.cpp | 65 +++++++++++--- .../ecode/plugins/linter/linterplugin.hpp | 5 ++ 8 files changed, 129 insertions(+), 87 deletions(-) diff --git a/include/eepp/ui/uiwidget.hpp b/include/eepp/ui/uiwidget.hpp index 0ff4416e4..ceef58141 100644 --- a/include/eepp/ui/uiwidget.hpp +++ b/include/eepp/ui/uiwidget.hpp @@ -241,6 +241,17 @@ class EE_API UIWidget : public UINode { void setTooltipEnabled( bool enabled ); + UIWidget* getPrevWidget() const; + + UIWidget* getNextWidget() const; + + String getTranslatorString( const std::string& str ); + + String getTranslatorString( const std::string& str, const String& defaultValue ); + + String i18n( const std::string& str ); + + String i18n( const std::string& str, const String& defaultValue ); protected: friend class UIManager; friend class UISceneNode; @@ -341,17 +352,6 @@ class EE_API UIWidget : public UINode { void reloadFontFamily(); - UIWidget* getPrevWidget() const; - - UIWidget* getNextWidget() const; - - String getTranslatorString( const std::string& str ); - - String getTranslatorString( const std::string& str, const String& defaultValue ); - - String i18n( const std::string& str ); - - String i18n( const std::string& str, const String& defaultValue ); }; }} // namespace EE::UI diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index a6b6ad611..6824389f0 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -16,7 +16,7 @@ UITreeView* UITreeView::New() { UITreeView::UITreeView() : UIAbstractTableView( "treeview" ), - mIndentWidth( PixelDensity::dpToPx( 12 ) ), + mIndentWidth( PixelDensity::dpToPx( 6 ) ), mExpanderIconSize( PixelDensity::dpToPxI( 12 ) ) { setClipType( ClipType::ContentBox ); mExpandIcon = getUISceneNode()->findIcon( "tree-expanded" ); diff --git a/src/tools/ecode/appconfig.cpp b/src/tools/ecode/appconfig.cpp index cce54d6b1..0f886661f 100644 --- a/src/tools/ecode/appconfig.cpp +++ b/src/tools/ecode/appconfig.cpp @@ -351,38 +351,32 @@ void AppConfig::saveProject( std::string projectFolder, UICodeEditorSplitter* ed const std::string& configPath, const ProjectDocumentConfig& docConfig, const ProjectBuildConfiguration& buildConfig ) { FileSystem::dirAddSlashAtEnd( projectFolder ); - std::vector editors = editorSplitter->getAllEditors(); - std::vector paths; - for ( auto editor : editors ) - if ( editor->getDocument().hasFilepath() ) - paths.emplace_back( ProjectPath{ editor->getDocument().getFilePath(), - editor->getDocument().getSelection() } ); std::string projectsPath( configPath + "projects" + FileSystem::getOSSlash() ); if ( !FileSystem::fileExists( projectsPath ) ) FileSystem::makeDir( projectsPath ); MD5::Result hash = MD5::fromString( projectFolder ); std::string projectCfgPath( projectsPath + hash.toHexString() + ".cfg" ); - IniFile ini( projectCfgPath, false ); - ini.setValue( "path", "folder_path", projectFolder ); - ini.setValueB( "document", "use_global_settings", docConfig.useGlobalSettings ); - ini.setValueB( "document", "h_as_cpp", docConfig.hAsCPP ); - ini.setValueB( "document", "trim_trailing_whitespaces", docConfig.doc.trimTrailingWhitespaces ); - ini.setValueB( "document", "force_new_line_at_end_of_file", + IniFile cfg( projectCfgPath, false ); + cfg.setValue( "path", "folder_path", projectFolder ); + cfg.setValueB( "document", "use_global_settings", docConfig.useGlobalSettings ); + cfg.setValueB( "document", "h_as_cpp", docConfig.hAsCPP ); + cfg.setValueB( "document", "trim_trailing_whitespaces", docConfig.doc.trimTrailingWhitespaces ); + cfg.setValueB( "document", "force_new_line_at_end_of_file", docConfig.doc.forceNewLineAtEndOfFile ); - ini.setValueB( "document", "auto_detect_indent_type", docConfig.doc.autoDetectIndentType ); - ini.setValueB( "document", "write_bom", docConfig.doc.writeUnicodeBOM ); - ini.setValueI( "document", "indent_width", docConfig.doc.indentWidth ); - ini.setValueB( "document", "indent_spaces", docConfig.doc.indentSpaces ); - ini.setValue( "document", "line_endings", + cfg.setValueB( "document", "auto_detect_indent_type", docConfig.doc.autoDetectIndentType ); + cfg.setValueB( "document", "write_bom", docConfig.doc.writeUnicodeBOM ); + cfg.setValueI( "document", "indent_width", docConfig.doc.indentWidth ); + cfg.setValueB( "document", "indent_spaces", docConfig.doc.indentSpaces ); + cfg.setValue( "document", "line_endings", TextDocument::lineEndingToString( docConfig.doc.lineEndings ) ); - ini.setValueI( "document", "tab_width", docConfig.doc.tabWidth ); - ini.setValueI( "document", "line_breaking_column", docConfig.doc.lineBreakingColumn ); - ini.setValue( "build", "build_name", buildConfig.buildName ); - ini.setValue( "build", "build_type", buildConfig.buildType ); - ini.setValue( "nodes", "documents", + cfg.setValueI( "document", "tab_width", docConfig.doc.tabWidth ); + cfg.setValueI( "document", "line_breaking_column", docConfig.doc.lineBreakingColumn ); + cfg.setValue( "build", "build_name", buildConfig.buildName ); + cfg.setValue( "build", "build_type", buildConfig.buildType ); + cfg.setValue( "nodes", "documents", saveNode( editorSplitter->getBaseLayout()->getFirstChild() ).dump() ); - ini.deleteKey( "files" ); - ini.writeFile(); + cfg.deleteKey( "files" ); + cfg.writeFile(); } static void countTotalEditors( json j, size_t& curTotal ) { @@ -431,14 +425,15 @@ void AppConfig::loadDocuments( UICodeEditorSplitter* editorSplitter, json j, UITab* tab = nullptr; if ( ( tab = editorSplitter->isDocumentOpen( path, false, true ) ) != nullptr ) { auto tabAndEditor = editorSplitter->createCodeEditorInTabWidget( curTabWidget ); - UICodeEditor* editor = tabAndEditor.second; - editor->setDocument( + UICodeEditor* teditor = tabAndEditor.second; + teditor->setDocument( tab->getOwnedWidget()->asType()->getDocumentRef() ); editorSplitter->removeUnusedTab( curTabWidget ); - if ( !editor->getDocument().getSelection().isValid() || - editor->getDocument().getSelection() == TextRange( { 0, 0 }, { 0, 0 } ) ) { - editor->getDocument().setSelection( selection ); - editor->scrollToCursor(); + if ( !teditor->getDocument().getSelection().isValid() || + teditor->getDocument().getSelection() == + TextRange( { 0, 0 }, { 0, 0 } ) ) { + teditor->getDocument().setSelection( selection ); + teditor->scrollToCursor(); } if ( curTabWidget->getTabCount() == totalToLoad ) curTabWidget->setTabSelected( @@ -492,44 +487,44 @@ void AppConfig::loadDocuments( UICodeEditorSplitter* editorSplitter, json j, void AppConfig::loadProject( std::string projectFolder, UICodeEditorSplitter* editorSplitter, const std::string& configPath, ProjectDocumentConfig& docConfig, - std::shared_ptr pool, ecode::App* app ) { + ecode::App* app ) { FileSystem::dirAddSlashAtEnd( projectFolder ); std::string projectsPath( configPath + "projects" + FileSystem::getOSSlash() ); MD5::Result hash = MD5::fromString( projectFolder ); std::string projectCfgPath( projectsPath + hash.toHexString() + ".cfg" ); if ( !FileSystem::fileExists( projectCfgPath ) ) return; - IniFile ini( projectCfgPath ); + IniFile cfg( projectCfgPath ); - docConfig.useGlobalSettings = ini.getValueB( "document", "use_global_settings", true ); - docConfig.hAsCPP = ini.getValueB( "document", "h_as_cpp", false ); + docConfig.useGlobalSettings = cfg.getValueB( "document", "use_global_settings", true ); + docConfig.hAsCPP = cfg.getValueB( "document", "h_as_cpp", false ); docConfig.doc.trimTrailingWhitespaces = - ini.getValueB( "document", "trim_trailing_whitespaces", false ); + cfg.getValueB( "document", "trim_trailing_whitespaces", false ); docConfig.doc.forceNewLineAtEndOfFile = - ini.getValueB( "document", "force_new_line_at_end_of_file", false ); + cfg.getValueB( "document", "force_new_line_at_end_of_file", false ); docConfig.doc.autoDetectIndentType = - ini.getValueB( "document", "auto_detect_indent_type", true ); - docConfig.doc.writeUnicodeBOM = ini.getValueB( "document", "write_bom", false ); - docConfig.doc.indentWidth = ini.getValueI( "document", "indent_width", 4 ); - docConfig.doc.indentSpaces = ini.getValueB( "document", "indent_spaces", false ); + cfg.getValueB( "document", "auto_detect_indent_type", true ); + docConfig.doc.writeUnicodeBOM = cfg.getValueB( "document", "write_bom", false ); + docConfig.doc.indentWidth = cfg.getValueI( "document", "indent_width", 4 ); + docConfig.doc.indentSpaces = cfg.getValueB( "document", "indent_spaces", false ); docConfig.doc.lineEndings = - TextDocument::stringToLineEnding( ini.getValue( "document", "line_endings", "LF" ) ); + TextDocument::stringToLineEnding( cfg.getValue( "document", "line_endings", "LF" ) ); - docConfig.doc.tabWidth = eemax( 2, ini.getValueI( "document", "tab_width", 4 ) ); + docConfig.doc.tabWidth = eemax( 2, cfg.getValueI( "document", "tab_width", 4 ) ); docConfig.doc.lineBreakingColumn = - eemax( 0, ini.getValueI( "document", "line_breaking_column", 100 ) ); + eemax( 0, cfg.getValueI( "document", "line_breaking_column", 100 ) ); if ( app->getProjectBuildManager() ) { ProjectBuildConfiguration prjCfg; - prjCfg.buildName = ini.getValue( "build", "build_name", "" ); - prjCfg.buildType = ini.getValue( "build", "build_type", "" ); + prjCfg.buildName = cfg.getValue( "build", "build_name", "" ); + prjCfg.buildType = cfg.getValue( "build", "build_type", "" ); app->getProjectBuildManager()->setConfig( prjCfg ); } - if ( ini.keyValueExists( "nodes", "documents" ) ) { + if ( cfg.keyValueExists( "nodes", "documents" ) ) { json j; try { - j = json::parse( ini.getValue( "nodes", "documents" ) ); + j = json::parse( cfg.getValue( "nodes", "documents" ) ); } catch ( const json::exception& e ) { Log::error( "AppConfig::loadProject: error loading project: %s", e.what() ); return; diff --git a/src/tools/ecode/appconfig.hpp b/src/tools/ecode/appconfig.hpp index 0e4d232ee..f169c9cf4 100644 --- a/src/tools/ecode/appconfig.hpp +++ b/src/tools/ecode/appconfig.hpp @@ -187,7 +187,7 @@ class AppConfig { void loadProject( std::string projectFolder, UICodeEditorSplitter* editorSplitter, const std::string& configPath, ProjectDocumentConfig& docConfig, - std::shared_ptr pool, ecode::App* app ); + ecode::App* app ); protected: Int64 editorsToLoad{ 0 }; diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 7426cb8eb..f3c308287 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -52,10 +52,7 @@ bool App::onCloseRequestCallback( EE::Window::Window* ) { "Do you really want to close the code editor?\nAll changes will be lost." ) .unescape() ); msgBox->addEventListener( Event::OnConfirm, [this]( const Event* ) { - if ( !mCurrentProject.empty() ) - mConfig.saveProject( mCurrentProject, mSplitter, mConfigPath, mProjectDocConfig, - mProjectBuildManager ? mProjectBuildManager->getConfig() - : ProjectBuildConfiguration() ); + saveProject(); saveConfig(); mWindow->close(); } ); @@ -65,10 +62,7 @@ bool App::onCloseRequestCallback( EE::Window::Window* ) { msgBox->showWhenReady(); return false; } else { - if ( !mCurrentProject.empty() ) - mConfig.saveProject( mCurrentProject, mSplitter, mConfigPath, mProjectDocConfig, - mProjectBuildManager ? mProjectBuildManager->getConfig() - : ProjectBuildConfiguration() ); + saveProject(); saveConfig(); return true; } @@ -1892,6 +1886,13 @@ bool App::isUnlockedCommand( const std::string& command ) { return std::find( cmds.begin(), cmds.end(), command ) != cmds.end(); } +void App::saveProject() { + if ( !mCurrentProject.empty() ) + mConfig.saveProject( mCurrentProject, mSplitter, mConfigPath, mProjectDocConfig, + mProjectBuildManager ? mProjectBuildManager->getConfig() + : ProjectBuildConfiguration() ); +} + void App::closeEditors() { mRecentClosedFiles = {}; @@ -1899,9 +1900,8 @@ void App::closeEditors() { mSplitter->clearNavigationHistory(); mStatusBar->setVisible( mConfig.ui.showStatusBar ); - mConfig.saveProject( mCurrentProject, mSplitter, mConfigPath, mProjectDocConfig, - mProjectBuildManager ? mProjectBuildManager->getConfig() - : ProjectBuildConfiguration() ); + saveProject(); + std::vector editors = mSplitter->getAllEditors(); while ( !editors.empty() ) { UICodeEditor* editor = editors[0]; @@ -2938,7 +2938,7 @@ void App::loadFolder( const std::string& path ) { Clock projClock; mProjectBuildManager = std::make_unique( rpath, mThreadPool, mSidePanel, this ); - mConfig.loadProject( rpath, mSplitter, mConfigPath, mProjectDocConfig, mThreadPool, this ); + mConfig.loadProject( rpath, mSplitter, mConfigPath, mProjectDocConfig, this ); Log::info( "Load project took: %.2f ms", projClock.getElapsedTime().asMilliseconds() ); loadFileSystemMatcher( rpath ); @@ -4001,17 +4001,18 @@ Anchor.error:hover { if ( mConfig.workspace.checkForUpdatesAtStartup ) checkForUpdates( true ); -#if EE_PLATFORM == EE_PLATFORM_LINUX mUISceneNode->setInterval( [this] { if ( mWindow && mThreadPool && mWindow->getInput()->getElapsedSinceLastKeyboardOrMouseEvent().asSeconds() < 60.f ) { + saveProject(); +#if EE_PLATFORM == EE_PLATFORM_LINUX mThreadPool->run( [] { malloc_trim( 0 ); } ); +#endif } }, Seconds( 60.f ) ); -#endif mWindow->runMainLoop( &appLoop, mBenchmarkMode ? 0 : mConfig.context.FrameRateLimit ); } diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index 113c14156..4643875c3 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -411,6 +411,8 @@ class App : public UICodeEditorSplitter::Client { const std::string& getFileToOpen() const; + void saveProject(); + protected: std::vector mArgs; EE::Window::Window* mWindow{ nullptr }; diff --git a/src/tools/ecode/plugins/linter/linterplugin.cpp b/src/tools/ecode/plugins/linter/linterplugin.cpp index f5391b341..11dd83188 100644 --- a/src/tools/ecode/plugins/linter/linterplugin.cpp +++ b/src/tools/ecode/plugins/linter/linterplugin.cpp @@ -9,7 +9,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -487,10 +490,14 @@ void LinterPlugin::onRegister( UICodeEditor* editor ) { if ( editor->hasDocument() ) { auto& doc = editor->getDocument(); - doc.setCommand( "linter-go-to-next-error", [this, editor]() { goToNextError( editor ); } ); + doc.setCommand( "linter-go-to-next-error", [this, editor] { goToNextError( editor ); } ); doc.setCommand( "linter-go-to-previous-error", - [this, editor]() { goToPrevError( editor ); } ); + [this, editor] { goToPrevError( editor ); } ); + + doc.setCommand( "linter-copy-error-message", [this, editor] { + editor->getUISceneNode()->getWindow()->getClipboard()->setText( mErrorMsg ); + } ); } mEditors.insert( { editor, listeners } ); @@ -858,18 +865,21 @@ void LinterPlugin::drawAfterLineText( UICodeEditor* editor, const Int64& index, !match.codeActions.empty() ) { rLineWidth = editor->getLineWidth( index ); Color wcolor( editor->getColorScheme().getEditorSyntaxStyle( "warning" ).color ); - UIIcon* notification = - editor->getUISceneNode()->getUIIconThemeManager()->findIcon( "lightbulb-autofix" ); - Float size = lineHeight; - Drawable* drawable = notification->getSize( (int)eefloor( size ) ); - if ( drawable == nullptr ) - return; + if ( nullptr == mLightbulbIcon ) { + mLightbulbIcon = editor->getUISceneNode()->getUIIconThemeManager()->findIcon( + "lightbulb-autofix" ); + } + if ( nullptr != mLightbulbIcon ) { + Drawable* drawable = mLightbulbIcon->getSize( (int)eefloor( lineHeight ) ); + if ( drawable == nullptr ) + return; - Color oldColor( drawable->getColor() ); - drawable->setColor( wcolor ); - drawable->draw( { position.x + rLineWidth, position.y } ); - drawable->setColor( oldColor ); - quickFixRendered = true; + Color oldColor( drawable->getColor() ); + drawable->setColor( wcolor ); + drawable->draw( { position.x + rLineWidth, position.y } ); + drawable->setColor( oldColor ); + quickFixRendered = true; + } } if ( !mErrorLens || i != 0 ) @@ -1120,4 +1130,33 @@ void LinterPlugin::invalidateEditors( TextDocument* doc ) { } } +bool LinterPlugin::onCreateContextMenu( UICodeEditor* editor, UIPopUpMenu* menu, + const Vector2i& pos, const Uint32& /*flags*/ ) { + Lock l( mMatchesMutex ); + auto it = mMatches.find( editor->getDocumentRef().get() ); + if ( it == mMatches.end() ) + return false; + + Vector2f localPos( editor->convertToNodeSpace( pos.asFloat() ) ); + TextPosition cursorPosition = editor->resolveScreenPosition( pos.asFloat() ); + auto matchIt = it->second.find( cursorPosition.line() ); + if ( matchIt == it->second.end() ) + return false; + + auto& matches = matchIt->second; + for ( auto& match : matches ) { + if ( match.box[editor].contains( localPos ) ) { + menu->addSeparator(); + menu->add( editor->i18n( "copy_error_message", "Copy Error Message" ), + mManager->getUISceneNode()->findIcon( "copy" )->getSize( + PixelDensity::dpToPxI( 12 ) ) ) + ->setId( "linter-copy-error-message" ); + mErrorMsg = match.text; + break; + } + } + + return false; +} + } // namespace ecode diff --git a/src/tools/ecode/plugins/linter/linterplugin.hpp b/src/tools/ecode/plugins/linter/linterplugin.hpp index 4c46cd946..d1aa3e1cf 100644 --- a/src/tools/ecode/plugins/linter/linterplugin.hpp +++ b/src/tools/ecode/plugins/linter/linterplugin.hpp @@ -106,6 +106,9 @@ class LinterPlugin : public Plugin { Linter getLinterForLang( const std::string& lang, const std::vector& extensions ); + virtual bool onCreateContextMenu( UICodeEditor* editor, UIPopUpMenu* menu, + const Vector2i& position, const Uint32& flags ); + protected: std::vector mLinters; std::unordered_map> mEditors; @@ -128,6 +131,8 @@ class LinterPlugin : public Plugin { std::set mLanguagesDisabled; std::set mLSPLanguagesDisabled; String::HashType mConfigHash{ 0 }; + UIIcon* mLightbulbIcon{ nullptr }; + std::string mErrorMsg; LinterPlugin( PluginManager* pluginManager, bool sync );