diff --git a/src/eepp/graphics/image.cpp b/src/eepp/graphics/image.cpp index 3ede80a12..f6f62132f 100644 --- a/src/eepp/graphics/image.cpp +++ b/src/eepp/graphics/image.cpp @@ -358,11 +358,10 @@ bool Image::isImage( const std::string& path ) { } bool Image::isImageExtension( const std::string& path ) { - std::string Ext( FileSystem::fileExtension( path ) ); - - return ( Ext == "png" || Ext == "tga" || Ext == "bmp" || Ext == "jpg" || Ext == "gif" || - Ext == "jpeg" || Ext == "dds" || Ext == "psd" || Ext == "hdr" || Ext == "pic" || - Ext == "pvr" || Ext == "pkm" || Ext == "svg" ); + const std::string ext( FileSystem::fileExtension( path ) ); + return ( ext == "png" || ext == "tga" || ext == "bmp" || ext == "jpg" || ext == "gif" || + ext == "jpeg" || ext == "dds" || ext == "psd" || ext == "hdr" || ext == "pic" || + ext == "pvr" || ext == "pkm" || ext == "svg" ); } std::string Image::getLastFailureReason() { diff --git a/src/eepp/system/functionstring.cpp b/src/eepp/system/functionstring.cpp index 750b71780..2fc13960a 100644 --- a/src/eepp/system/functionstring.cpp +++ b/src/eepp/system/functionstring.cpp @@ -51,13 +51,12 @@ FunctionString FunctionString::parse( const std::string& function ) { typeStringData.push_back( true ); curParameter = ""; } - } else { - if ( '\\' == curChar ) - lastWasBackslash = !lastWasBackslash; - + } else if ( '\\' != curChar || lastWasBackslash ) { curParameter += curChar; } } + + lastWasBackslash = '\\' == curChar; } curParameter = String::trim( curParameter ); diff --git a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp index 40d12c73e..634590eb6 100644 --- a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp +++ b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp @@ -267,7 +267,7 @@ void SyntaxDefinitionManager::addMarkdown() { void SyntaxDefinitionManager::addC() { add( { "C", - { "%.c$", "%.h$" }, + { "%.c$", "%.h$", "%.icc" }, { { { "//.-\n" }, "comment" }, { { "/%*", "%*/" }, "comment" }, diff --git a/src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp b/src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp index 5faa39c19..1bdad8ba4 100644 --- a/src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp +++ b/src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp @@ -124,7 +124,14 @@ extern TerminalKeyMap terminalKeyMap; class TerminalDisplay : public ITerminalDisplay { public: - enum class EventType { TITLE, ICON_TITLE, SCROLL_HISTORY, HISTORY_LENGTH_CHANGE, UNKNOWN }; + enum class EventType { + TITLE, + ICON_TITLE, + SCROLL_HISTORY, + HISTORY_LENGTH_CHANGE, + PROCESS_EXIT, + UNKNOWN + }; struct Event { EventType type{ EventType::UNKNOWN }; @@ -142,7 +149,8 @@ class TerminalDisplay : public ITerminalDisplay { create( EE::Window::Window* window, Font* font, const Float& fontSize, const Sizef& pixelsSize, std::string program = "", const std::vector& args = {}, const std::string& workingDir = "", const size_t& historySize = 10000, - IProcessFactory* processFactory = nullptr, const bool& useFrameBuffer = false ); + IProcessFactory* processFactory = nullptr, const bool& useFrameBuffer = false, + const bool& keepAlive = true ); virtual ~TerminalDisplay(); @@ -160,7 +168,9 @@ class TerminalDisplay : public ITerminalDisplay { virtual void drawCursor( int cx, int cy, TerminalGlyph g, int ox, int oy, TerminalGlyph og ); virtual void drawEnd(); - virtual void update(); + virtual bool update(); + + void executeFile( const std::string& cmd ); void action( TerminalShortcutAction action ); @@ -241,6 +251,10 @@ class TerminalDisplay : public ITerminalDisplay { void setClickStep( const Uint32& clickStep ); + bool getKeepAlive() const; + + void setKeepAlive( bool keepAlive ); + protected: EE::Window::Window* mWindow; std::vector mBuffer; @@ -268,6 +282,7 @@ class TerminalDisplay : public ITerminalDisplay { bool mUseFrameBuffer{ true }; bool mAlreadyClickedLButton{ false }; bool mAlreadyClickedMButton{ false }; + bool mKeepAlive{ true }; Clock mClock; Clock mLastDoubleClick; int mColumns{ 0 }; diff --git a/src/modules/eterm/include/eterm/terminal/terminalemulator.hpp b/src/modules/eterm/include/eterm/terminal/terminalemulator.hpp index a33416fdc..3a74ad1ca 100644 --- a/src/modules/eterm/include/eterm/terminal/terminalemulator.hpp +++ b/src/modules/eterm/include/eterm/terminal/terminalemulator.hpp @@ -134,7 +134,8 @@ class TerminalEmulator final { void logError( const char* err ); - void update(); + /** @return If the tty read was completed or there's still buffer to read (true completed) */ + bool update(); void terminate(); diff --git a/src/modules/eterm/src/eterm/terminal/pseudoterminal.cpp b/src/modules/eterm/src/eterm/terminal/pseudoterminal.cpp index b121904c1..33957fad4 100644 --- a/src/modules/eterm/src/eterm/terminal/pseudoterminal.cpp +++ b/src/modules/eterm/src/eterm/terminal/pseudoterminal.cpp @@ -142,12 +142,11 @@ int PseudoTerminal::write( const char* s, size_t n ) { } int PseudoTerminal::read( char* s, size_t n, bool block ) { - struct pollfd pfd; - pfd.fd = (int)mMaster; - pfd.events = POLLIN; - pfd.revents = 0; - if ( !block ) { + struct pollfd pfd; + pfd.fd = mMaster.handle(); + pfd.events = POLLIN; + pfd.revents = 0; auto i = poll( &pfd, 1, 0 ); if ( i == 0 || !( pfd.revents & POLLIN ) ) { return 0; @@ -157,7 +156,7 @@ int PseudoTerminal::read( char* s, size_t n, bool block ) { return -1; } } - ssize_t r = ::read( (int)mMaster, s, n ); + ssize_t r = ::read( mMaster.handle(), s, n ); return (int)r; } diff --git a/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp b/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp index 6f1c33260..6248a6487 100644 --- a/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp +++ b/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp @@ -144,7 +144,7 @@ static TerminalKey keys[] = { { KEY_DELETE, KEYMOD_CTRL, "\033[3;5~", +1, 0 }, { KEY_DELETE, KEYMOD_SHIFT, "\033[2K", -1, 0 }, { KEY_DELETE, KEYMOD_SHIFT, "\033[3;2~", +1, 0 }, - { KEY_DELETE, KEYMOD_CTRL_SHIFT_ALT_META, "\033[P", -1, 0 }, + { KEY_DELETE, KEYMOD_CTRL_SHIFT_ALT_META, "\033[3~", -1, 0 }, { KEY_DELETE, KEYMOD_CTRL_SHIFT_ALT_META, "\033[3~", +1, 0 }, { KEY_BACKSPACE, KEYMOD_NONE, "\177", 0, 0 }, { KEY_BACKSPACE, KEYMOD_LALT, "\033\177", 0, 0 }, @@ -383,10 +383,12 @@ static Sizei gridSizeFromTermDimensions( Font* font, const Float& fontSize, return { clipColumns, clipRows }; } -std::shared_ptr TerminalDisplay::create( - EE::Window::Window* window, Font* font, const Float& fontSize, const Sizef& pixelsSize, - std::string program, const std::vector& args, const std::string& workingDir, - const size_t& historySize, IProcessFactory* processFactory, const bool& useFrameBuffer ) { +std::shared_ptr +TerminalDisplay::create( EE::Window::Window* window, Font* font, const Float& fontSize, + const Sizef& pixelsSize, std::string program, + const std::vector& args, const std::string& workingDir, + const size_t& historySize, IProcessFactory* processFactory, + const bool& useFrameBuffer, const bool& keepAlive ) { if ( program.empty() ) { #ifdef _WIN32 program = "cmd.exe"; @@ -435,6 +437,7 @@ std::shared_ptr TerminalDisplay::create( terminal->mProgram = program; terminal->mArgs = args; terminal->mWorkingDir = workingDir; + terminal->mKeepAlive = keepAlive; if ( freeProcessFactory ) eeSAFE_DELETE( processFactory ); @@ -570,7 +573,16 @@ void TerminalDisplay::setClickStep( const Uint32& clickStep ) { mClickStep = clickStep; } -void TerminalDisplay::update() { +bool TerminalDisplay::getKeepAlive() const { + return mKeepAlive; +} + +void TerminalDisplay::setKeepAlive( bool keepAlive ) { + mKeepAlive = keepAlive; +} + +bool TerminalDisplay::update() { + bool ret = true; if ( mFocus && isBlinkingCursor() && mClock.getElapsedTime().asSeconds() > 0.7 ) { mMode ^= MODE_BLINK; mClock.restart(); @@ -578,10 +590,20 @@ void TerminalDisplay::update() { } if ( mTerminal ) { int histi = mTerminal->getHistorySize(); - mTerminal->update(); + ret = mTerminal->update(); if ( histi != mTerminal->getHistorySize() ) sendEvent( { EventType::HISTORY_LENGTH_CHANGE } ); } + return ret; +} + +void TerminalDisplay::executeFile( const std::string& cmd ) { + if ( mTerminal ) { + std::string rcmd( cmd + "\r" ); + char clearLine = 0x15; + mTerminal->ttywrite( &clearLine, 1, 1 ); + mTerminal->ttywrite( rcmd.c_str(), rcmd.size(), 1 ); + } } void TerminalDisplay::action( TerminalShortcutAction action ) { @@ -1286,10 +1308,9 @@ void TerminalDisplay::onSizeChange() { } void TerminalDisplay::onProcessExit( int exitCode ) { - if ( !mTerminal || mProgram.empty() ) - return; + sendEvent( { EventType::PROCESS_EXIT, String::toString( exitCode ) } ); - if ( exitCode != 0 ) + if ( !mTerminal || mProgram.empty() || exitCode != 0 || !mKeepAlive ) return; auto processFactory = eeNew( ProcessFactory, () ); diff --git a/src/modules/eterm/src/eterm/terminal/terminalemulator.cpp b/src/modules/eterm/src/eterm/terminal/terminalemulator.cpp index 9050b1de8..beee2370c 100644 --- a/src/modules/eterm/src/eterm/terminal/terminalemulator.cpp +++ b/src/modules/eterm/src/eterm/terminal/terminalemulator.cpp @@ -2659,18 +2659,20 @@ void TerminalEmulator::resize( int columns, int rows ) { redraw(); } -void TerminalEmulator::update() { +#define MAX_TTY_READS ( 1024 * 40 ) + +bool TerminalEmulator::update() { if ( mStatus == TerminalEmulator::STARTING ) { mStatus = TerminalEmulator::RUNNING; } else if ( mStatus != TerminalEmulator::RUNNING ) { - return; + return true; } - int n = 1024; - while ( ttyread() > 0 && n > 0 ) - --n; + int read = MAX_TTY_READS; + while ( ttyread() > 0 && read--) + ; - if ( n != 1024 || mDirty ) + if ( read != MAX_TTY_READS || mDirty ) draw(); mProcess->checkExitStatus(); @@ -2680,6 +2682,8 @@ void TerminalEmulator::update() { mStatus = TERMINATED; onProcessExit( mExitCode ); } + + return read != 0; } }} // namespace eterm::Terminal diff --git a/src/modules/eterm/src/eterm/ui/uiterminal.cpp b/src/modules/eterm/src/eterm/ui/uiterminal.cpp index beae0fe2a..ddf3f0fcf 100644 --- a/src/modules/eterm/src/eterm/ui/uiterminal.cpp +++ b/src/modules/eterm/src/eterm/ui/uiterminal.cpp @@ -229,12 +229,8 @@ std::string UITerminal::getPropertyString( const PropertyDefinition* propertyDef } void UITerminal::executeFile( const std::string& cmd ) { - if ( mTerm && mTerm->getTerminal() ) { - std::string rcmd( cmd + "\r" ); - char clearLine = 0x15; - mTerm->getTerminal()->ttywrite( &clearLine, 1, 1 ); - mTerm->getTerminal()->ttywrite( rcmd.c_str(), rcmd.size(), 1 ); - } + if ( mTerm ) + mTerm->executeFile( cmd ); } const TerminalColorScheme& UITerminal::getColorScheme() const { diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 060b283db..daf5ed092 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -443,7 +443,8 @@ void App::onFileDropped( String file ) { if ( node && node->isType( UI_TYPE_CODEEDITOR ) ) { codeEditor = node->asType(); if ( ( codeEditor->getDocument().isLoading() || !codeEditor->getDocument().isEmpty() ) && - !Image::isImageExtension( file ) ) { + !Image::isImageExtension( file ) && + FileSystem::fileExtension( file.toUtf8() ) != "svg" ) { auto d = mSplitter->createCodeEditorInTabWidget( mSplitter->tabWidgetFromEditor( codeEditor ) ); codeEditor = d.second; @@ -2091,7 +2092,8 @@ void App::createDocAlert( UICodeEditor* editor ) { void App::loadFileFromPath( const std::string& path, bool inNewTab, UICodeEditor* codeEditor, std::function onLoaded ) { - if ( Image::isImageExtension( path ) && Image::isImage( path ) ) { + if ( Image::isImageExtension( path ) && Image::isImage( path ) && + FileSystem::fileExtension( path ) != "svg" ) { UIImage* imageView = mImageLayout->findByType( UI_TYPE_IMAGE ); UILoader* loaderView = mImageLayout->findByType( UI_TYPE_LOADER ); if ( imageView ) { @@ -3629,75 +3631,73 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe iconTheme->add( UIGlyphIcon::New( icon.first, iconFont, icon.second ) ); if ( mimeIconFont && mimeIconFont->loaded() ) { - std::unordered_map mimeIcons = { - { "filetype-lua", 61826 }, - { "filetype-c", 61718 }, - { "filetype-h", 61792 }, - { "filetype-cs", 61720 }, - { "filetype-cpp", 61719 }, - { "filetype-css", 61743 }, - { "filetype-conf", 61781 }, - { "filetype-cfg", 61781 }, - { "filetype-desktop", 61781 }, - { "filetype-service", 61781 }, - { "filetype-env", 61781 }, - { "filetype-properties", 61781 }, - { "filetype-ini", 61781 }, - { "filetype-dart", 61744 }, - { "filetype-diff", 61752 }, - { "filetype-zip", 61775 }, - { "filetype-go", 61789 }, - { "filetype-htm", 61799 }, - { "filetype-html", 61799 }, - { "filetype-java", 61809 }, - { "filetype-js", 61810 }, - { "filetype-json", 61811 }, - { "filetype-kt", 61814 }, - { "filetype-md", 61829 }, - { "filetype-perl", 61853 }, - { "filetype-php", 61855 }, - { "filetype-py", 61863 }, - { "filetype-pyc", 61863 }, - { "filetype-pyd", 61863 }, - { "filetype-swift", 61906 }, - { "filetype-rb", 61880 }, - { "filetype-rs", 61881 }, - { "filetype-ts", 61923 }, - { "filetype-yaml", 61945 }, - { "filetype-yml", 61945 }, - { "filetype-jpg", 61801 }, - { "filetype-png", 61801 }, - { "filetype-jpeg", 61801 }, - { "filetype-bmp", 61801 }, - { "filetype-tga", 61801 }, - { "filetype-sh", 61911 }, - { "filetype-bash", 61911 }, - { "filetype-fish", 61911 }, - { "filetype-scala", 61882 }, - { "filetype-r", 61866 }, - { "filetype-rake", 61880 }, - { "filetype-rss", 61879 }, - { "filetype-sql", 61746 }, - { "filetype-elm", 61763 }, - { "filetype-ex", 61971 }, - { "filetype-exs", 61971 }, - { "filetype-awk", 61971 }, - { "filetype-nim", 61734 }, - { "filetype-xml", 61769 }, - { "filetype-dockerfile", 61758 }, - { "filetype-ruby", 61880 }, - { "filetype-scala", 61882 }, - { "filetype-perl", 61853 }, - { "file", 61766 }, - { "file-symlink", 61774 }, - { "folder", 0xF23B }, - { "folder-open", 0xF23C }, - { "tree-expanded", 0xF11E }, - { "tree-contracted", 0xF120 }, - { "github", 0xF184 }, - { "package", 61846 }, - { "tab-close", 61944 } - }; + std::unordered_map mimeIcons = { { "filetype-lua", 61826 }, + { "filetype-c", 61718 }, + { "filetype-h", 61792 }, + { "filetype-cs", 61720 }, + { "filetype-cpp", 61719 }, + { "filetype-css", 61743 }, + { "filetype-conf", 61781 }, + { "filetype-cfg", 61781 }, + { "filetype-desktop", 61781 }, + { "filetype-service", 61781 }, + { "filetype-env", 61781 }, + { "filetype-properties", 61781 }, + { "filetype-ini", 61781 }, + { "filetype-dart", 61744 }, + { "filetype-diff", 61752 }, + { "filetype-zip", 61775 }, + { "filetype-go", 61789 }, + { "filetype-htm", 61799 }, + { "filetype-html", 61799 }, + { "filetype-java", 61809 }, + { "filetype-js", 61810 }, + { "filetype-json", 61811 }, + { "filetype-kt", 61814 }, + { "filetype-md", 61829 }, + { "filetype-perl", 61853 }, + { "filetype-php", 61855 }, + { "filetype-py", 61863 }, + { "filetype-pyc", 61863 }, + { "filetype-pyd", 61863 }, + { "filetype-swift", 61906 }, + { "filetype-rb", 61880 }, + { "filetype-rs", 61881 }, + { "filetype-ts", 61923 }, + { "filetype-yaml", 61945 }, + { "filetype-yml", 61945 }, + { "filetype-jpg", 61801 }, + { "filetype-png", 61801 }, + { "filetype-jpeg", 61801 }, + { "filetype-bmp", 61801 }, + { "filetype-tga", 61801 }, + { "filetype-sh", 61911 }, + { "filetype-bash", 61911 }, + { "filetype-fish", 61911 }, + { "filetype-scala", 61882 }, + { "filetype-r", 61866 }, + { "filetype-rake", 61880 }, + { "filetype-rss", 61879 }, + { "filetype-sql", 61746 }, + { "filetype-elm", 61763 }, + { "filetype-ex", 61971 }, + { "filetype-exs", 61971 }, + { "filetype-awk", 61971 }, + { "filetype-nim", 61734 }, + { "filetype-xml", 61769 }, + { "filetype-dockerfile", 61758 }, + { "filetype-ruby", 61880 }, + { "filetype-scala", 61882 }, + { "filetype-perl", 61853 }, + { "file", 61766 }, + { "file-symlink", 61774 }, + { "folder", 0xF23B }, + { "folder-open", 0xF23C }, + { "tree-expanded", 0xF11E }, + { "tree-contracted", 0xF120 }, + { "github", 0xF184 }, + { "package", 61846 }, + { "tab-close", 61944 } }; for ( const auto& icon : mimeIcons ) iconTheme->add( UIGlyphIcon::New( icon.first, mimeIconFont, icon.second ) ); } diff --git a/src/tools/eterm/eterm.cpp b/src/tools/eterm/eterm.cpp index 3aa065917..e23f08a56 100644 --- a/src/tools/eterm/eterm.cpp +++ b/src/tools/eterm/eterm.cpp @@ -75,16 +75,17 @@ void inputCallback( InputEvent* event ) { } void mainLoop() { + bool termNeedsUpdate = false; win->getInput()->update(); if ( terminal ) - terminal->update(); + termNeedsUpdate = !terminal->update(); if ( terminal && terminal->isDirty() ) { win->clear(); terminal->draw(); win->display(); - } else { + } else if ( !termNeedsUpdate ) { win->getInput()->waitEvent( Milliseconds( win->hasFocus() ? 16 : 100 ) ); } } @@ -111,7 +112,11 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { args::ValueFlag pixelDenstiyConf( parser, "pixel-density", "Set default application pixel density", { 'd', "pixel-density" } ); - args::Positional wd( parser, "wording-dir", "Working Directory" ); + args::Positional wd( parser, "wording-dir", "Working Directory / executable" ); + args::Flag closeOnExit( parser, "close-on-exit", + "close the application when the executable exits", { 'c', "close" } ); + args::ValueFlag executeInShell( + parser, "execute-in-shell", "execute program in shell", { 'e', "execute" }, "" ); try { parser.ParseCLI( argc, argv ); @@ -158,7 +163,7 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { WindowBackend::Default, 32, resPath + "icon/ee.png", pixelDenstiyConf ? pixelDenstiyConf.Get() : currentDisplay->getPixelDensity() ), - ContextSettings( true ) ); + ContextSettings( false ) ); if ( win->isOpen() ) { win->setClearColor( RGB( 0, 0, 0 ) ); @@ -185,15 +190,24 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { } if ( !terminal || terminal->hasTerminated() ) { + FileInfo file( wd ? wd.Get() : FileSystem::getCurrentWorkingDirectory() ); terminal = TerminalDisplay::create( win, fontMono, PixelDensity::dpToPx( fontSize.Get() ), win->getSize().asFloat(), - shell.Get(), {}, wd ? wd.Get() : FileSystem::getCurrentWorkingDirectory(), - historySize.Get(), nullptr, fb.Get() ); + file.isRegularFile() && file.isExecutable() ? file.getFilepath() : shell.Get(), {}, + file.getDirectoryPath(), historySize.Get(), nullptr, fb.Get(), + !( file.isRegularFile() && file.isExecutable() ) ); terminal->pushEventCallback( [&]( const TerminalDisplay::Event& event ) { if ( event.type == TerminalDisplay::EventType::TITLE ) win->setTitle( "eterm - " + event.eventData ); + else if ( event.type == TerminalDisplay::EventType::PROCESS_EXIT && + closeOnExit.Get() ) { + win->close(); + } } ); + if ( !executeInShell.Get().empty() ) + terminal->executeFile( executeInShell.Get() ); + win->startTextInput(); }