diff --git a/.ecode/project_build.json b/.ecode/project_build.json index be9c9ea21..56c99d1f3 100644 --- a/.ecode/project_build.json +++ b/.ecode/project_build.json @@ -1,5 +1,5 @@ { - "ecode-debug": { + "ecode": { "build": [ { "args": "--with-mojoal --with-debug-symbols gmake", @@ -7,30 +7,35 @@ "working_dir": "${project_root}" }, { - "args": "-j$(nproc) config=debug ecode", + "args": "-j${nproc} config=${build_type} ecode", "command": "make", "working_dir": "${build_dir}" } ], + "build_types": [ + "debug", + "release" + ], "clean": [ { - "args": "config=debug clean", + "args": "config=${build_type} clean", "command": "make", "working_dir": "${build_dir}" } ], "config": { - "clear_sys_env": false - }, - "var": { - "build_dir": "${project_root}/make/linux" + "clear_sys_env": false, + "enabled": true }, "env": { "SHELL": "fish" }, + "os": [ + "linux" + ], "output_parser": { "config": { - "relative_file_paths": true + "relative_file_paths": true }, "error": [ { @@ -43,6 +48,9 @@ } } ] + }, + "var": { + "build_dir": "${project_root}/make/${os}" } } } diff --git a/projects/linux/ee.files b/projects/linux/ee.files index debbbfd70..4bb872e29 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -1197,6 +1197,8 @@ ../../src/tools/ecode/plugins/lsp/lspprotocol.hpp ../../src/tools/ecode/plugins/pluginmanager.cpp ../../src/tools/ecode/plugins/pluginmanager.hpp +../../src/tools/ecode/projectbuild.cpp +../../src/tools/ecode/projectbuild.hpp ../../src/tools/ecode/projectdirectorytree.cpp ../../src/tools/ecode/projectdirectorytree.hpp ../../src/tools/ecode/projectsearch.cpp diff --git a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp index c0ea032c9..2e9f0bb5b 100644 --- a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp +++ b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp @@ -373,7 +373,7 @@ static void addC() { { { "^%s*(#define)%s*" }, { "keyword", "keyword", "literal" } }, { { "^%s*(#else)%s*" }, { "keyword", "keyword", "literal" } }, { { "^%s*#", "[^\\]\n" }, "comment" }, - { { "\"", "\"", "\\" }, "string" }, + { { "\"", "[\"\n]", "\\" }, "string" }, { { "'", "'", "\\" }, "string" }, { { "-?0x%x+" }, "number" }, { { "-?%d+[%d%.eE]*f?" }, "number" }, @@ -643,7 +643,7 @@ static void addCPP() { { { "R\"%(", "%)\"" }, "string" }, { { "//.-\n" }, "comment" }, { { "/%*", "%*/" }, "comment" }, - { { "\"", "\"", "\\" }, "string" }, + { { "\"", "[\"\n]", "\\" }, "string" }, { { "'", "'", "\\" }, "string" }, { { "^%s*(#include)%s+([<%\"][%w%d%.%\\%/%_%-]+[>%\"])" }, { "keyword", "keyword", "literal" } }, diff --git a/src/tools/ecode/plugins/formatter/formatterplugin.cpp b/src/tools/ecode/plugins/formatter/formatterplugin.cpp index bab9f1956..a89296528 100644 --- a/src/tools/ecode/plugins/formatter/formatterplugin.cpp +++ b/src/tools/ecode/plugins/formatter/formatterplugin.cpp @@ -392,9 +392,11 @@ void FormatterPlugin::runFormatter( UICodeEditor* editor, const Formatter& forma editor->runOnMainThread( [&, res, editor]() { std::shared_ptr doc = editor->getDocumentRef(); TextPosition pos = doc->getSelection().start(); + auto scroll = editor->getScroll(); doc->selectAll(); doc->textInput( res.result ); doc->setSelection( pos ); + editor->setScroll( scroll ); } ); return; } @@ -429,9 +431,11 @@ void FormatterPlugin::runFormatter( UICodeEditor* editor, const Formatter& forma editor->runOnMainThread( [&, data, editor]() { std::shared_ptr doc = editor->getDocumentRef(); TextPosition pos = doc->getSelection().start(); + auto scroll = editor->getScroll(); doc->selectAll(); doc->textInput( data ); doc->setSelection( pos ); + editor->setScroll( scroll ); } ); } } diff --git a/src/tools/ecode/projectbuild.cpp b/src/tools/ecode/projectbuild.cpp index 156680ae2..6ce886c0b 100644 --- a/src/tools/ecode/projectbuild.cpp +++ b/src/tools/ecode/projectbuild.cpp @@ -10,28 +10,39 @@ using namespace EE; namespace ecode { -static const char* PROJECT_ROOT = "${project_root}"; +static const char* VAR_PROJECT_ROOT = "${project_root}"; +static const char* VAR_BUILD_TYPE = "${build_type}"; +static const char* VAR_OS = "${os}"; +static const char* VAR_NPROC = "${nproc}"; + +static void replaceVar( ProjectBuildStep& s, const std::string& var, const std::string& val ) { + static std::string slashDup = FileSystem::getOSSlash() + FileSystem::getOSSlash(); + String::replaceAll( s.workingDir, var, val ); + String::replaceAll( s.cmd, var, val ); + String::replaceAll( s.args, var, val ); + String::replaceAll( s.workingDir, slashDup, FileSystem::getOSSlash() ); +} void ProjectBuild::replaceVars() { const std::vector steps{ &mBuild, &mClean }; - auto replaceVar = []( ProjectBuildStep& s, const std::string& var, const std::string& val ) { - String::replaceAll( s.workingDir, var, val ); - String::replaceAll( s.cmd, var, val ); - String::replaceAll( s.args, var, val ); - }; - for ( auto& step : steps ) { for ( auto& s : *step ) { - replaceVar( s, PROJECT_ROOT, mProjectRoot ); + replaceVar( s, VAR_PROJECT_ROOT, mProjectRoot ); for ( auto& var : mVars ) { std::string varKey( "${" + var.first + "}" ); - String::replaceAll( var.second, PROJECT_ROOT, mProjectRoot ); + String::replaceAll( var.second, VAR_PROJECT_ROOT, mProjectRoot ); replaceVar( s, varKey, var.second ); } } } } +bool ProjectBuild::isOSSupported( const std::string& os ) const { + return mOS.empty() || std::any_of( mOS.begin(), mOS.end(), [&]( const auto& oos ) { + return oos == os || oos == "any"; + } ); +} + ProjectBuildManager::ProjectBuildManager( const std::string& projectRoot, std::shared_ptr pool ) : mProjectRoot( projectRoot ), mThreadPool( pool ) { @@ -61,7 +72,7 @@ static ProjectOutputParserTypes outputParserType( const std::string& typeStr ) { bool ProjectBuildManager::load() { ScopedOp op( [this]() { mLoading = true; }, [this]() { mLoading = false; } ); - mProjectFile = mProjectRoot + ".ecode/project-build.json"; + mProjectFile = mProjectRoot + ".ecode/project_build.json"; if ( !FileSystem::fileExists( mProjectFile ) ) return false; std::string data; @@ -82,7 +93,20 @@ bool ProjectBuildManager::load() { ProjectBuild b( build.key(), mProjectRoot ); const auto& buildObj = build.value(); + if ( buildObj.contains( "os" ) && buildObj["os"].is_array() ) { + const auto& oss = buildObj["os"]; + for ( const auto& os : oss ) + b.mOS.emplace( os ); + } + + if ( buildObj.contains( "build_types" ) && buildObj["build_types"].is_array() ) { + const auto& bts = buildObj["build_types"]; + for ( const auto& bt : bts ) + b.mBuildTypes.emplace( bt ); + } + if ( buildObj.contains( "config" ) && buildObj["config"].is_object() ) { + b.mConfig.enabled = buildObj.value( "enabled", true ); b.mConfig.clearSysEnv = buildObj.value( "clear_sys_env", false ); } @@ -135,24 +159,28 @@ bool ProjectBuildManager::load() { if ( !isValidType( typeStr ) ) continue; - const auto& ptrnCfg = op.value(); - ProjectBuildOutputParserConfig opc; - opc.type = outputParserType( typeStr ); - opc.pattern = ptrnCfg.value( "pattern", "" ); + const auto& ptrnCfgs = op.value(); + if ( ptrnCfgs.is_array() ) { + for ( const auto& ptrnCfg : ptrnCfgs ) { + ProjectBuildOutputParserConfig opc; + opc.type = outputParserType( typeStr ); + opc.pattern = ptrnCfg.value( "pattern", "" ); - if ( ptrnCfg.contains( "pattern_order" ) ) { - const auto& po = ptrnCfg["pattern_order"]; - if ( po.contains( "line" ) && po["line"].is_number() ) - opc.patternOrder.line = po["line"].get(); - if ( po.contains( "col" ) && po["col"].is_number() ) - opc.patternOrder.col = po["col"].get(); - if ( po.contains( "message" ) && po["message"].is_number() ) - opc.patternOrder.message = po["message"].get(); - if ( po.contains( "file" ) && po["file"].is_number() ) - opc.patternOrder.file = po["file"].get(); + if ( ptrnCfg.contains( "pattern_order" ) ) { + const auto& po = ptrnCfg["pattern_order"]; + if ( po.contains( "line" ) && po["line"].is_number() ) + opc.patternOrder.line = po["line"].get(); + if ( po.contains( "col" ) && po["col"].is_number() ) + opc.patternOrder.col = po["col"].get(); + if ( po.contains( "message" ) && po["message"].is_number() ) + opc.patternOrder.message = po["message"].get(); + if ( po.contains( "file" ) && po["file"].is_number() ) + opc.patternOrder.file = po["file"].get(); + } + + outputParser.mConfig.emplace_back( std::move( opc ) ); + } } - - outputParser.mConfig.emplace_back( std::move( opc ) ); } } } @@ -166,9 +194,43 @@ bool ProjectBuildManager::load() { return true; } -void ProjectBuildManager::run( const std::string& buildName ) { +ProjectBuildCommandsRes ProjectBuildManager::generateBuildCommands( + const std::string& buildName, + std::function i18n, + const std::string& buildType ) { if ( !mLoaded ) - return; + return { i18n( "project_build_not_loaded", "No project build loaded!" ) }; + + const auto& buildIt = mBuilds.find( buildName ); + + if ( buildIt == mBuilds.end() ) + return { i18n( "build_name_not_found", "Build name not found!" ) }; + + const auto& build = buildIt->second; + + if ( !build.mBuildTypes.empty() && buildType.empty() ) + return { i18n( "build_type_required", "Build type must be set!" ) }; + + std::string currentOS = String::toLower( Sys::getPlatform() ); + + if ( !build.isOSSupported( currentOS ) ) + return { + i18n( "build_os_not_supported", "Operating System not supported for this build!" ) }; + + std::string nproc = String::format( "%d", Sys::getCPUCount() ); + ProjectBuildCommandsRes res; + + for ( const auto& step : build.mBuild ) { + ProjectBuildCommand buildCmd( step, build.mEnvs ); + replaceVar( buildCmd, VAR_OS, currentOS ); + replaceVar( buildCmd, VAR_NPROC, nproc ); + if ( !buildType.empty() ) + replaceVar( buildCmd, VAR_BUILD_TYPE, buildType ); + + res.cmds.emplace_back( std::move( buildCmd ) ); + } + + return res; } } // namespace ecode diff --git a/src/tools/ecode/projectbuild.hpp b/src/tools/ecode/projectbuild.hpp index 8128b63dd..476b6f986 100644 --- a/src/tools/ecode/projectbuild.hpp +++ b/src/tools/ecode/projectbuild.hpp @@ -5,44 +5,50 @@ #include #include #include +#include #include +using namespace EE; using namespace EE::System; namespace ecode { /** reference: - { "ecode": { "build": [ { "args": "--with-mojoal --with-debug-symbols gmake", "command": "premake4", - "working_dir": "$PROJECT_ROOT" + "working_dir": "${project_root}" }, { - "args": "-j$(nproc) config=release ecode", + "args": "-j${nproc} config=${build_type} ecode", "command": "make", "working_dir": "${build_dir}" } ], + "build_types": [ + "debug", + "release" + ], "clean": [ { - "args": "config=release clean", + "args": "config=${build_type} clean", "command": "make", "working_dir": "${build_dir}" } ], "config": { - "clear_sys_env": false - }, - "var": { - "build_dir": "$PROJECT_ROOT/make/linux" + "clear_sys_env": false, + "enabled": true }, "env": { "SHELL": "fish" }, + "os": [ + "linux" + ], "output_parser": { "config": { "relative_file_paths": true @@ -58,6 +64,9 @@ namespace ecode { } } ] + }, + "var": { + "build_dir": "${project_root}/make/${os}" } } } @@ -73,6 +82,7 @@ using ProjectBuildSteps = std::vector; using ProjectBuildKeyVal = std::unordered_map; struct ProjectBuildConfig { + bool enabled{ true }; bool clearSysEnv{ false }; }; @@ -102,11 +112,17 @@ class ProjectBuild { ProjectBuild( const std::string& name, const std::string& projectRoot ) : mName( name ), mProjectRoot( projectRoot ){}; + const ProjectBuildConfig& getConfig() const { return mConfig; } + + bool isOSSupported( const std::string& os ) const; + protected: friend class ProjectBuildManager; std::string mName; std::string mProjectRoot; + std::unordered_set mOS; + std::unordered_set mBuildTypes; ProjectBuildSteps mBuild; ProjectBuildSteps mClean; ProjectBuildKeyVal mEnvs; @@ -119,11 +135,36 @@ class ProjectBuild { using ProjectBuildMap = std::unordered_map; +struct ProjectBuildCommand : public ProjectBuildStep { + ProjectBuildKeyVal envs; + + ProjectBuildCommand( const ProjectBuildStep& step, const ProjectBuildKeyVal& envs ) : + ProjectBuildStep( step ), envs( envs ) {} +}; + +using ProjectBuildCommands = std::vector; + +struct ProjectBuildCommandsRes { + String errorMsg; + ProjectBuildCommands cmds; + + ProjectBuildCommandsRes() {} + + ProjectBuildCommandsRes( const String& errMsg ) : errorMsg( errMsg ) {} + + ProjectBuildCommandsRes( ProjectBuildCommands&& cmds ) : cmds( cmds ) {} + + bool isValid() { return errorMsg.empty(); } +}; + class ProjectBuildManager { public: ProjectBuildManager( const std::string& projectRoot, std::shared_ptr pool ); - void run( const std::string& buildName ); + ProjectBuildCommandsRes generateBuildCommands( + const std::string& buildName, + std::function i18n, + const std::string& buildType = "" ); const ProjectBuildMap& getBuilds() const { return mBuilds; }