mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
ecode: Project Build WIP.
This commit is contained in:
@@ -27,9 +27,6 @@
|
||||
"clear_sys_env": false,
|
||||
"enabled": true
|
||||
},
|
||||
"env": {
|
||||
"SHELL": "fish"
|
||||
},
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
@@ -39,7 +36,29 @@
|
||||
},
|
||||
"error": [
|
||||
{
|
||||
"pattern": "([^:]*):(%d+):(%d+):%s?[%w%s]*error:%s?([^\n]*)",
|
||||
"pattern": "([^:]+):(%d+):(%d+):%s?[%w%s]*error:%s?(.*)",
|
||||
"pattern_order": {
|
||||
"col": 3,
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"message": 4
|
||||
}
|
||||
}
|
||||
],
|
||||
"notice": [
|
||||
{
|
||||
"pattern": "([^:]+):(%d+):(%d+):%s?[%w%s]*notice:%s?(.*)",
|
||||
"pattern_order": {
|
||||
"col": 3,
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"message": 4
|
||||
}
|
||||
}
|
||||
],
|
||||
"warning": [
|
||||
{
|
||||
"pattern": "([^:]+):(%d+):(%d+):%s?[%w%s]*warning:%s?(.*)",
|
||||
"pattern_order": {
|
||||
"col": 3,
|
||||
"file": 1,
|
||||
|
||||
@@ -594,8 +594,13 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client {
|
||||
Vector2f getRelativeScreenPosition( const TextPosition& pos );
|
||||
|
||||
bool getShowLinesRelativePosition() const;
|
||||
|
||||
void showLinesRelativePosition( bool showLinesRelativePosition );
|
||||
|
||||
UIScrollBar* getVScrollBar() const;
|
||||
|
||||
UIScrollBar* getHScrollBar() const;
|
||||
|
||||
protected:
|
||||
struct LastXOffset {
|
||||
TextPosition position{ 0, 0 };
|
||||
|
||||
@@ -207,6 +207,8 @@ const SyntaxColorScheme::Style& SyntaxColorScheme::getSyntaxStyle( const std::st
|
||||
return getSyntaxStyle( "symbol" );
|
||||
else if ( type == "link" || type == "link_hover" )
|
||||
return getSyntaxStyle( "function" );
|
||||
else if ( type == "error" || type == "warning" || type == "notice" )
|
||||
return getEditorSyntaxStyle( type );
|
||||
else {
|
||||
auto foundIt = mStyleCache.find( type );
|
||||
if ( foundIt != mStyleCache.end() )
|
||||
|
||||
@@ -1392,6 +1392,14 @@ void UICodeEditor::showLinesRelativePosition( bool showLinesRelativePosition ) {
|
||||
mShowLinesRelativePosition = showLinesRelativePosition;
|
||||
}
|
||||
|
||||
UIScrollBar* UICodeEditor::getVScrollBar() const {
|
||||
return mVScrollBar;
|
||||
}
|
||||
|
||||
UIScrollBar* UICodeEditor::getHScrollBar() const {
|
||||
return mHScrollBar;
|
||||
}
|
||||
|
||||
void UICodeEditor::drawCursor( const Vector2f& startScroll, const Float& lineHeight,
|
||||
const TextPosition& cursor ) {
|
||||
if ( mCursorVisible && !mLocked && isTextSelectionEnabled() ) {
|
||||
|
||||
@@ -70,7 +70,10 @@ UISlider::UISlider( const std::string& tag, const UIOrientation& orientation ) :
|
||||
mSlider->setDragEnabled( true );
|
||||
mSlider->setSize( 4, 4 );
|
||||
mSlider->setPosition( 0, 0 );
|
||||
mSlider->addEventListener( Event::OnPositionChange, [&]( const Event* ) { fixSliderPos(); } );
|
||||
mSlider->addEventListener( Event::OnPositionChange, [&]( const Event* ) {
|
||||
if ( !mUpdating && !mOnPosChange )
|
||||
fixSliderPos();
|
||||
} );
|
||||
|
||||
if ( UIOrientation::Horizontal == mOrientation )
|
||||
mSlider->centerVertical();
|
||||
|
||||
@@ -748,6 +748,10 @@ void App::showStatusBar( bool show ) {
|
||||
mStatusBar->setVisible( show );
|
||||
}
|
||||
|
||||
ProjectBuildManager* App::getProjectBuildManager() const {
|
||||
return mProjectBuildManager.get();
|
||||
}
|
||||
|
||||
void App::switchSidePanel() {
|
||||
mConfig.ui.showSidePanel = !mConfig.ui.showSidePanel;
|
||||
mSettings->getWindowMenu()
|
||||
@@ -1725,6 +1729,8 @@ std::vector<std::string> App::getUnlockedCommands() {
|
||||
"open-locatebar",
|
||||
"open-command-palette",
|
||||
"open-global-search",
|
||||
"project-build-start",
|
||||
"project-build-cancel",
|
||||
"toggle-locatebar",
|
||||
"toggle-global-search",
|
||||
"toggle-status-build-output",
|
||||
|
||||
@@ -234,6 +234,17 @@ class App : public UICodeEditorSplitter::Client {
|
||||
t.setCommand( "open-locatebar", [&] { mUniversalLocator->showLocateBar(); } );
|
||||
t.setCommand( "toggle-locatebar", [&] { mUniversalLocator->toggleLocateBar(); } );
|
||||
t.setCommand( "open-command-palette", [&] { mUniversalLocator->showCommandPalette(); } );
|
||||
t.setCommand( "project-build-start", [&] {
|
||||
if ( mProjectBuildManager && !mProjectBuildManager->isBuilding() ) {
|
||||
mStatusBuildOutputController->run(
|
||||
"ecode", "debug", mProjectBuildManager->getOutputParser( "ecode" ) );
|
||||
}
|
||||
} );
|
||||
t.setCommand( "project-build-cancel", [&] {
|
||||
if ( mProjectBuildManager && mProjectBuildManager->isBuilding() ) {
|
||||
mProjectBuildManager->cancelBuild();
|
||||
}
|
||||
} );
|
||||
t.setCommand( "open-workspace-symbol-search",
|
||||
[&] { mUniversalLocator->showWorkspaceSymbol(); } );
|
||||
t.setCommand( "open-document-symbol-search",
|
||||
@@ -378,6 +389,8 @@ class App : public UICodeEditorSplitter::Client {
|
||||
|
||||
void showStatusBar( bool show );
|
||||
|
||||
ProjectBuildManager* getProjectBuildManager() const;
|
||||
|
||||
protected:
|
||||
std::vector<std::string> mArgs;
|
||||
EE::Window::Window* mWindow{ nullptr };
|
||||
|
||||
@@ -59,17 +59,18 @@ ProjectBuildManager::ProjectBuildManager( const std::string& projectRoot,
|
||||
|
||||
ProjectBuildManager::~ProjectBuildManager() {
|
||||
mShuttingDown = true;
|
||||
mCancelBuild = true;
|
||||
while ( mLoading )
|
||||
Sys::sleep( Milliseconds( 0.1f ) );
|
||||
while ( mBuilding )
|
||||
Sys::sleep( Milliseconds( 0.1f ) );
|
||||
}
|
||||
|
||||
ProjectBuildCommandsRes
|
||||
ProjectBuildManager::run( const std::string& buildName,
|
||||
std::function<String( const std::string&, const String& )> i18n,
|
||||
const std::string& buildType, const ProjectBuildProgressFn& progressFn,
|
||||
const ProjectBuildDoneFn& doneFn ) {
|
||||
ProjectBuildCommandsRes ProjectBuildManager::run( const std::string& buildName,
|
||||
const ProjectBuildi18nFn& i18n,
|
||||
const std::string& buildType,
|
||||
const ProjectBuildProgressFn& progressFn,
|
||||
const ProjectBuildDoneFn& doneFn ) {
|
||||
ProjectBuildCommandsRes res = generateBuildCommands( buildName, i18n, buildType );
|
||||
if ( !res.isValid() )
|
||||
return res;
|
||||
@@ -78,7 +79,9 @@ ProjectBuildManager::run( const std::string& buildName,
|
||||
return res;
|
||||
}
|
||||
|
||||
mThreadPool->run( [this, res, progressFn, doneFn]() { runBuild( res, progressFn, doneFn ); } );
|
||||
mThreadPool->run( [this, res, progressFn, doneFn, i18n, buildName, buildType]() {
|
||||
runBuild( buildName, buildType, i18n, res, progressFn, doneFn );
|
||||
} );
|
||||
|
||||
return res;
|
||||
};
|
||||
@@ -222,10 +225,9 @@ bool ProjectBuildManager::load() {
|
||||
return true;
|
||||
}
|
||||
|
||||
ProjectBuildCommandsRes ProjectBuildManager::generateBuildCommands(
|
||||
const std::string& buildName,
|
||||
std::function<String( const std::string& /*key*/, const String& /*defaultvalue*/ )> i18n,
|
||||
const std::string& buildType ) {
|
||||
ProjectBuildCommandsRes ProjectBuildManager::generateBuildCommands( const std::string& buildName,
|
||||
const ProjectBuildi18nFn& i18n,
|
||||
const std::string& buildType ) {
|
||||
if ( !mLoaded )
|
||||
return { i18n( "project_build_not_loaded", "No project build loaded!" ) };
|
||||
|
||||
@@ -261,17 +263,66 @@ ProjectBuildCommandsRes ProjectBuildManager::generateBuildCommands(
|
||||
return res;
|
||||
}
|
||||
|
||||
void ProjectBuildManager::runBuild( const ProjectBuildCommandsRes& res,
|
||||
ProjectBuildOutputParser ProjectBuildManager::getOutputParser( const std::string& buildName ) {
|
||||
auto buildIt = mBuilds.find( buildName );
|
||||
if ( buildIt != mBuilds.end() )
|
||||
return buildIt->second.mOutputParser;
|
||||
return {};
|
||||
}
|
||||
|
||||
void ProjectBuildManager::cancelBuild() {
|
||||
mCancelBuild = true;
|
||||
}
|
||||
|
||||
void ProjectBuildManager::runBuild( const std::string& buildName, const std::string& buildType,
|
||||
const ProjectBuildi18nFn& i18n,
|
||||
const ProjectBuildCommandsRes& res,
|
||||
const ProjectBuildProgressFn& progressFn,
|
||||
const ProjectBuildDoneFn& doneFn ) {
|
||||
ScopedOp scopedOp( [this]() { mBuilding = true; }, [this]() { mBuilding = false; } );
|
||||
Clock clock;
|
||||
|
||||
auto printElapsed = [&clock, &i18n, &progressFn]() {
|
||||
if ( progressFn ) {
|
||||
progressFn(
|
||||
100, Sys::getDateTimeStr() + ": " +
|
||||
String::format(
|
||||
i18n( "build_elapsed_time", "Elapsed Time: %s.\n" ).toUtf8().c_str(),
|
||||
clock.getElapsedTime().toString().c_str() ) );
|
||||
}
|
||||
};
|
||||
|
||||
if ( progressFn ) {
|
||||
progressFn( 0, Sys::getDateTimeStr() + ": " +
|
||||
String::format( i18n( "running_steps_for_project",
|
||||
"Running steps for project %s...\n" )
|
||||
.toUtf8()
|
||||
.c_str(),
|
||||
buildName.c_str() ) );
|
||||
|
||||
if ( !buildType.empty() )
|
||||
progressFn(
|
||||
0, Sys::getDateTimeStr() + ": " +
|
||||
String::format(
|
||||
i18n( "using_build_type", "Using build type: %s.\n" ).toUtf8().c_str(),
|
||||
buildType.c_str() ) );
|
||||
}
|
||||
|
||||
int c = 0;
|
||||
for ( const auto& cmd : res.cmds ) {
|
||||
int progress = c > 0 ? c / (Float)res.cmds.size() : 0;
|
||||
Process process;
|
||||
auto options = Process::SearchUserPath | Process::NoWindow | Process::CombinedStdoutStderr;
|
||||
if ( !cmd.config.clearSysEnv )
|
||||
options |= Process::InheritEnvironment;
|
||||
if ( process.create( cmd.cmd, cmd.args, options, cmd.envs, cmd.workingDir ) ) {
|
||||
if ( progressFn )
|
||||
progressFn( progress,
|
||||
Sys::getDateTimeStr() + ": " +
|
||||
String::format(
|
||||
i18n( "starting_process", "Starting %s %s\n" ).toUtf8().c_str(),
|
||||
cmd.cmd.c_str(), cmd.args.c_str() ) );
|
||||
|
||||
std::string buffer( 1024, '\0' );
|
||||
unsigned bytesRead = 0;
|
||||
int returnCode;
|
||||
@@ -279,30 +330,57 @@ void ProjectBuildManager::runBuild( const ProjectBuildCommandsRes& res,
|
||||
bytesRead = process.readStdOut( buffer );
|
||||
std::string data( buffer.substr( 0, bytesRead ) );
|
||||
if ( progressFn )
|
||||
progressFn( 50, std::move( data ) );
|
||||
} while ( bytesRead != 0 && process.isAlive() && !mShuttingDown );
|
||||
progressFn( progress, std::move( data ) );
|
||||
} while ( bytesRead != 0 && process.isAlive() && !mShuttingDown && !mCancelBuild );
|
||||
|
||||
if ( mShuttingDown ) {
|
||||
if ( mShuttingDown || mCancelBuild ) {
|
||||
process.kill();
|
||||
doneFn( EXIT_FAILURE );
|
||||
mCancelBuild = false;
|
||||
printElapsed();
|
||||
if ( doneFn )
|
||||
doneFn( EXIT_FAILURE );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( progressFn )
|
||||
progressFn( 90, {} );
|
||||
|
||||
process.join( &returnCode );
|
||||
process.destroy();
|
||||
|
||||
if ( doneFn && returnCode != EXIT_SUCCESS ) {
|
||||
progressFn( 100, {} );
|
||||
doneFn( returnCode );
|
||||
if ( returnCode != EXIT_SUCCESS ) {
|
||||
if ( progressFn ) {
|
||||
progressFn( 100,
|
||||
String::format( i18n( "process_exited_with_errors",
|
||||
"The process \"%s\" exited with errors.\n" )
|
||||
.toUtf8()
|
||||
.c_str(),
|
||||
cmd.cmd.c_str() ) );
|
||||
}
|
||||
printElapsed();
|
||||
if ( doneFn )
|
||||
doneFn( returnCode );
|
||||
return;
|
||||
} else {
|
||||
if ( progressFn ) {
|
||||
progressFn( progress,
|
||||
String::format( i18n( "process_exited_normally",
|
||||
"The process \"%s\" exited normally.\n" )
|
||||
.toUtf8()
|
||||
.c_str(),
|
||||
cmd.cmd.c_str() ) );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printElapsed();
|
||||
if ( doneFn )
|
||||
doneFn( EXIT_FAILURE );
|
||||
return;
|
||||
}
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
doneFn( EXIT_SUCCESS );
|
||||
printElapsed();
|
||||
if ( doneFn )
|
||||
doneFn( EXIT_SUCCESS );
|
||||
}
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -100,6 +100,11 @@ struct ProjectBuildOutputParserConfig {
|
||||
};
|
||||
|
||||
class ProjectBuildOutputParser {
|
||||
public:
|
||||
const std::vector<ProjectBuildOutputParserConfig>& getConfig() const { return mConfig; }
|
||||
|
||||
bool useRelativeFilePaths() const { return mRelativeFilePaths; }
|
||||
|
||||
protected:
|
||||
friend class ProjectBuildManager;
|
||||
|
||||
@@ -160,6 +165,8 @@ struct ProjectBuildCommandsRes {
|
||||
|
||||
using ProjectBuildProgressFn = std::function<void( int curProgress, std::string buffer )>;
|
||||
using ProjectBuildDoneFn = std::function<void( int exitCode )>;
|
||||
using ProjectBuildi18nFn =
|
||||
std::function<String( const std::string& /*key*/, const String& /*defaultvalue*/ )>;
|
||||
|
||||
class ProjectBuildManager {
|
||||
public:
|
||||
@@ -167,16 +174,16 @@ class ProjectBuildManager {
|
||||
|
||||
~ProjectBuildManager();
|
||||
|
||||
ProjectBuildCommandsRes
|
||||
run( const std::string& buildName,
|
||||
std::function<String( const std::string& /*key*/, const String& /*defaultvalue*/ )> i18n,
|
||||
const std::string& buildType = "", const ProjectBuildProgressFn& progressFn = {},
|
||||
const ProjectBuildDoneFn& doneFn = {} );
|
||||
ProjectBuildCommandsRes run( const std::string& buildName, const ProjectBuildi18nFn& i18n,
|
||||
const std::string& buildType = "",
|
||||
const ProjectBuildProgressFn& progressFn = {},
|
||||
const ProjectBuildDoneFn& doneFn = {} );
|
||||
|
||||
ProjectBuildCommandsRes generateBuildCommands(
|
||||
const std::string& buildName,
|
||||
std::function<String( const std::string& /*key*/, const String& /*defaultvalue*/ )> i18n,
|
||||
const std::string& buildType = "" );
|
||||
ProjectBuildCommandsRes generateBuildCommands( const std::string& buildName,
|
||||
const ProjectBuildi18nFn& i18n,
|
||||
const std::string& buildType = "" );
|
||||
|
||||
ProjectBuildOutputParser getOutputParser( const std::string& buildName );
|
||||
|
||||
const ProjectBuildMap& getBuilds() const { return mBuilds; }
|
||||
|
||||
@@ -190,6 +197,8 @@ class ProjectBuildManager {
|
||||
|
||||
bool isBuilding() const { return mBuilding; }
|
||||
|
||||
void cancelBuild();
|
||||
|
||||
protected:
|
||||
std::string mProjectRoot;
|
||||
std::string mProjectFile;
|
||||
@@ -199,8 +208,10 @@ class ProjectBuildManager {
|
||||
bool mLoading{ false };
|
||||
bool mBuilding{ false };
|
||||
bool mShuttingDown{ false };
|
||||
bool mCancelBuild{ false };
|
||||
|
||||
void runBuild( const ProjectBuildCommandsRes& res,
|
||||
void runBuild( const std::string& buildName, const std::string& buildType,
|
||||
const ProjectBuildi18nFn& i18n, const ProjectBuildCommandsRes& res,
|
||||
const ProjectBuildProgressFn& progressFn = {},
|
||||
const ProjectBuildDoneFn& doneFn = {} );
|
||||
|
||||
|
||||
@@ -60,6 +60,83 @@ void StatusBuildOutputController::show() {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getProjectOutputParserTypeToString( const ProjectOutputParserTypes& type ) {
|
||||
switch ( type ) {
|
||||
case ProjectOutputParserTypes::Error:
|
||||
return "error";
|
||||
case ProjectOutputParserTypes::Warning:
|
||||
return "warning";
|
||||
case ProjectOutputParserTypes::Notice:
|
||||
return "notice";
|
||||
}
|
||||
return "notice";
|
||||
}
|
||||
|
||||
void StatusBuildOutputController::run( const std::string& buildName, const std::string& buildType,
|
||||
const ProjectBuildOutputParser& outputParser ) {
|
||||
if ( !mApp->getProjectBuildManager() )
|
||||
return;
|
||||
|
||||
auto pbm = mApp->getProjectBuildManager();
|
||||
|
||||
show();
|
||||
|
||||
mContainer->getDocument().reset();
|
||||
mContainer->setScrollY( mContainer->getMaxScroll().y );
|
||||
|
||||
std::vector<SyntaxPattern> patterns;
|
||||
|
||||
for ( const auto& parser : outputParser.getConfig() ) {
|
||||
SyntaxPattern ptn( { parser.pattern }, getProjectOutputParserTypeToString( parser.type ) );
|
||||
patterns.emplace_back( std::move( ptn ) );
|
||||
}
|
||||
|
||||
patterns.emplace_back(
|
||||
SyntaxPattern( { "%d%d%d%d%-%d%d%-%d%d%s%d%d%:%d%d%:%d%d%:.*error.*[^\n]+" }, "error" ) );
|
||||
patterns.emplace_back(
|
||||
SyntaxPattern( { "%d%d%d%d%-%d%d%-%d%d%s%d%d%:%d%d%:%d%d%:.*warning.*[^\n]+" }, "error" ) );
|
||||
patterns.emplace_back(
|
||||
SyntaxPattern( { "%d%d%d%d%-%d%d%-%d%d%s%d%d%:%d%d%:%d%d%:[^\n]+" }, "notice" ) );
|
||||
|
||||
SyntaxDefinition synDef( "custom_build", {}, patterns );
|
||||
mContainer->getDocument().setSyntaxDefinition( synDef );
|
||||
mContainer->getVScrollBar()->setValue( 1.f );
|
||||
|
||||
auto res = pbm->run(
|
||||
buildName, [this]( const auto& key, const auto& def ) { return mApp->i18n( key, def ); },
|
||||
buildType,
|
||||
[this]( auto, auto buffer ) {
|
||||
mContainer->runOnMainThread( [this, buffer]() {
|
||||
bool scrollToBottom = mContainer->getVScrollBar()->getValue() == 1.f;
|
||||
mContainer->getDocument().textInput( buffer );
|
||||
if ( scrollToBottom )
|
||||
mContainer->setScrollY( mContainer->getMaxScroll().y );
|
||||
} );
|
||||
},
|
||||
[this]( auto exitCode ) {
|
||||
String buffer;
|
||||
|
||||
if ( EXIT_SUCCESS == exitCode ) {
|
||||
buffer = Sys::getDateTimeStr() + ": " +
|
||||
mApp->i18n( "build_successful", "Build run successfully\n" );
|
||||
} else {
|
||||
buffer = Sys::getDateTimeStr() + ": " +
|
||||
mApp->i18n( "build_failed", "Build run with errors\n" );
|
||||
}
|
||||
|
||||
mContainer->runOnMainThread( [this, buffer]() {
|
||||
bool scrollToBottom = mContainer->getVScrollBar()->getValue() == 1.f;
|
||||
mContainer->getDocument().textInput( buffer );
|
||||
if ( scrollToBottom )
|
||||
mContainer->setScrollY( mContainer->getMaxScroll().y );
|
||||
} );
|
||||
} );
|
||||
|
||||
if ( !res.isValid() ) {
|
||||
mApp->getNotificationCenter()->addNotification( res.errorMsg );
|
||||
}
|
||||
}
|
||||
|
||||
UICodeEditor* StatusBuildOutputController::createContainer() {
|
||||
UICodeEditor* editor = UICodeEditor::NewOpt( true, true );
|
||||
editor->setLocked( true );
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef ECODE_STATUSBUILDOUTPUTCONTROLLER_HPP
|
||||
#define ECODE_STATUSBUILDOUTPUTCONTROLLER_HPP
|
||||
|
||||
#include "projectbuild.hpp"
|
||||
#include <eepp/ui/tools/uicodeeditorsplitter.hpp>
|
||||
#include <eepp/ui/uicodeeditor.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
@@ -24,6 +25,9 @@ class StatusBuildOutputController {
|
||||
|
||||
void show();
|
||||
|
||||
void run( const std::string& buildName, const std::string& buildType,
|
||||
const ProjectBuildOutputParser& outputParser = {} );
|
||||
|
||||
protected:
|
||||
UISplitter* mMainSplitter{ nullptr };
|
||||
UISceneNode* mUISceneNode{ nullptr };
|
||||
|
||||
Reference in New Issue
Block a user