Minor Terminal Emulator improvements.

Minor fix in FunctionString.
This commit is contained in:
Martín Lucas Golini
2022-08-13 04:30:24 -03:00
parent cefb0e0a7c
commit 335b472002
11 changed files with 167 additions and 119 deletions

View File

@@ -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() {

View File

@@ -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 );

View File

@@ -267,7 +267,7 @@ void SyntaxDefinitionManager::addMarkdown() {
void SyntaxDefinitionManager::addC() {
add( { "C",
{ "%.c$", "%.h$" },
{ "%.c$", "%.h$", "%.icc" },
{
{ { "//.-\n" }, "comment" },
{ { "/%*", "%*/" }, "comment" },

View File

@@ -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<std::string>& 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<TerminalGlyph> 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 };

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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> TerminalDisplay::create(
EE::Window::Window* window, Font* font, const Float& fontSize, const Sizef& pixelsSize,
std::string program, const std::vector<std::string>& args, const std::string& workingDir,
const size_t& historySize, IProcessFactory* processFactory, const bool& useFrameBuffer ) {
std::shared_ptr<TerminalDisplay>
TerminalDisplay::create( EE::Window::Window* window, Font* font, const Float& fontSize,
const Sizef& pixelsSize, std::string program,
const std::vector<std::string>& 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> 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, () );

View File

@@ -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

View File

@@ -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 {

View File

@@ -443,7 +443,8 @@ void App::onFileDropped( String file ) {
if ( node && node->isType( UI_TYPE_CODEEDITOR ) ) {
codeEditor = node->asType<UICodeEditor>();
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<void( UICodeEditor* codeEditor, const std::string& path )> onLoaded ) {
if ( Image::isImageExtension( path ) && Image::isImage( path ) ) {
if ( Image::isImageExtension( path ) && Image::isImage( path ) &&
FileSystem::fileExtension( path ) != "svg" ) {
UIImage* imageView = mImageLayout->findByType<UIImage>( UI_TYPE_IMAGE );
UILoader* loaderView = mImageLayout->findByType<UILoader>( 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<std::string, Uint32> 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<std::string, Uint32> 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 ) );
}

View File

@@ -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<Float> pixelDenstiyConf( parser, "pixel-density",
"Set default application pixel density",
{ 'd', "pixel-density" } );
args::Positional<std::string> wd( parser, "wording-dir", "Working Directory" );
args::Positional<std::string> 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<std::string> 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();
}