From 4edb776d51ceb2b2c276de07f6eac92b746e6756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Mon, 6 Oct 2025 00:12:05 -0300 Subject: [PATCH] Added a new option to set files associations in projects. Introduced a new configuration file for projects in the project file `.ecode/settings.json` file. Initially it supports files associations the following way: ```json { "files.associations": { "glob_pattern": "language_name", "functional": "cpp", "map": "cpp", "**/c++/**": "cpp" } } ``` Format is exactly the same as in vscode, and also, if no `.ecode/settings.json` file exists but does `.vscode/settings.json` file exists, it will fallback to that one. This is related to the discussion in issue SpartanJ/ecode#585. --- .../eepp/ui/doc/syntaxdefinitionmanager.hpp | 2 + src/eepp/ui/doc/syntaxdefinitionmanager.cpp | 5 ++ src/tools/ecode/appconfig.cpp | 46 +++++++++++++++++++ src/tools/ecode/appconfig.hpp | 2 + src/tools/ecode/ecode.cpp | 5 ++ 5 files changed, 60 insertions(+) diff --git a/include/eepp/ui/doc/syntaxdefinitionmanager.hpp b/include/eepp/ui/doc/syntaxdefinitionmanager.hpp index 138feb183..445cfab60 100644 --- a/include/eepp/ui/doc/syntaxdefinitionmanager.hpp +++ b/include/eepp/ui/doc/syntaxdefinitionmanager.hpp @@ -92,6 +92,8 @@ class EE_API SyntaxDefinitionManager { bool isFileFormatSupported( const std::string& filePath, std::string_view header ); + void resetFileAssociations(); + void setFileAssociations( FileAssociations&& fa ); FileAssociations getFileAssociations() const; diff --git a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp index b34831afe..47f0e337d 100644 --- a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp +++ b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp @@ -1469,6 +1469,11 @@ bool SyntaxDefinitionManager::isFileFormatSupported( const std::string& filePath return &find( filePath, header ) != mDefinitions[0].get(); } +void SyntaxDefinitionManager::resetFileAssociations() { + Lock l( mFileAssociationsMutex ); + mFileAssociations.clear(); +} + void SyntaxDefinitionManager::setFileAssociations( SyntaxDefinitionManager::FileAssociations&& fa ) { Lock l( mFileAssociationsMutex ); diff --git a/src/tools/ecode/appconfig.cpp b/src/tools/ecode/appconfig.cpp index 0841521cf..37e6f8cfd 100644 --- a/src/tools/ecode/appconfig.cpp +++ b/src/tools/ecode/appconfig.cpp @@ -919,10 +919,56 @@ void AppConfig::loadProject( std::string projectFolder, UICodeEditorSplitter* ed plugin->onLoadProject( projectFolder, projectPluginsStatePath ); } ); } + + loadFileAssociations( projectFolder ); } bool AppConfig::isNewVersion() const { return windowState.lastRunVersion != ecode::Version::getVersionNum(); } +void AppConfig::loadFileAssociations( const std::string& projectFolder ) { + std::string faPath( projectFolder + ".ecode/settings.json" ); + + if ( !FileSystem::fileExists( faPath ) ) { + faPath = projectFolder + ".vscode/settings.json"; + if ( !FileSystem::fileExists( faPath ) ) + return; + } + + std::string data; + if ( !FileSystem::fileGet( faPath, data ) ) + return; + + json j; + try { + j = json::parse( data, nullptr, true, true ); + } catch ( const json::exception& e ) { + Log::error( "AppConfig::loadFileAssociations - Error parsing config from " + "path %s, error: %s, config file content:\n%s", + faPath, e.what(), data ); + return; + } + + if ( j.contains( "files.associations" ) && j["files.associations"].is_object() ) { + const auto& associations = j["files.associations"]; + SyntaxDefinitionManager::FileAssociations fa; + + for ( const auto& item : associations.items() ) { + const std::string& key = item.key(); + const json& val = item.value(); + + if ( val.is_string() ) { + fa[key] = val; + } else { + Log::warning( "AppConfig::loadFileAssociations - Skipping key '%s' because its " + "value is not a string.", + key ); + } + } + + SyntaxDefinitionManager::instance()->setFileAssociations( std::move( fa ) ); + } +} + } // namespace ecode diff --git a/src/tools/ecode/appconfig.hpp b/src/tools/ecode/appconfig.hpp index 9bd754333..d6102be40 100644 --- a/src/tools/ecode/appconfig.hpp +++ b/src/tools/ecode/appconfig.hpp @@ -269,6 +269,8 @@ class AppConfig { void editorLoadedCounter( ecode::App* app ); + void loadFileAssociations( const std::string& projectFolder ); + nlohmann::json saveNode( Node* node ); Mutex tabWidgetTypesMutex; diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 2dbd6bf18..1e77598ed 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -2108,6 +2108,9 @@ void App::closeFolder() { mFileSystemModel->setRootPath( "" ); mPluginManager->setWorkspaceFolder( "" ); updateOpenRecentFolderBtn(); + + SyntaxDefinitionManager::instance()->resetFileAssociations(); + if ( mUniversalLocator ) mUniversalLocator->updateFilesTable(); if ( getConfig().ui.welcomeScreen ) { @@ -3524,6 +3527,8 @@ void App::loadFolder( std::string path, bool forceNewWindow ) { if ( mProjectBuildManager ) mProjectBuildManager.reset(); + SyntaxDefinitionManager::instance()->resetFileAssociations(); + mProjectBuildManager = std::make_unique( rpath, mThreadPool, mSidePanel, this ); mConfig.loadProject( rpath, mSplitter, mConfigPath, mProjectDocConfig, this,