diff --git a/src/tools/eterm/eterm.cpp b/src/tools/eterm/eterm.cpp index 2705f3eef..9f883bc03 100644 --- a/src/tools/eterm/eterm.cpp +++ b/src/tools/eterm/eterm.cpp @@ -96,7 +96,7 @@ EE_MAIN_FUNC int main( int, char*[] ) { if ( !terminal || terminal->hasTerminated() ) { terminal = TerminalDisplay::create( win, fontMono, PixelDensity::dpToPx( 11 ), - win->getSize().asFloat() ); + win->getSize().asFloat(), "", {}, "", 10000 ); } win->getInput()->pushCallback( &inputCallback ); diff --git a/src/tools/eterm/terminal/terminaldisplay.cpp b/src/tools/eterm/terminal/terminaldisplay.cpp index e9cce2d31..e8a629e94 100644 --- a/src/tools/eterm/terminal/terminaldisplay.cpp +++ b/src/tools/eterm/terminal/terminaldisplay.cpp @@ -7,9 +7,31 @@ #include #include +#define BETWEEN( x, a, b ) ( ( a ) <= ( x ) && ( x ) <= ( b ) ) +#define IS_SET( flag ) ( ( mMode & ( flag ) ) != 0 ) +#define DIV( n, d ) ( ( ( n ) + ( d ) / 2.0f ) / ( d ) ) +#define DIVI( n, d ) ( ( ( n ) + ( d ) / 2 ) / ( d ) ) + +static Uint32 sanitizeMod( const Uint32& mod ) { + Uint32 smod = 0; + if ( mod & KEYMOD_CTRL ) + smod |= KEYMOD_CTRL; + if ( mod & KEYMOD_SHIFT ) + smod |= KEYMOD_SHIFT; + if ( mod & KEYMOD_META ) + smod |= KEYMOD_META; + if ( mod & KEYMOD_LALT ) + smod |= KEYMOD_LALT; + if ( mod & KEYMOD_RALT ) + smod |= KEYMOD_RALT; + return smod; +} + TerminalKeyMap::TerminalKeyMap( const TerminalKey keys[], size_t keysLen, const TerminalScancode platformKeys[], size_t platformKeysLen, - const TerminalShortcut shortcuts[], size_t shortcutsLen ) { + const TerminalShortcut shortcuts[], size_t shortcutsLen, + const TerminalMouseShortcut mouseShortcuts[], + size_t mouseShortcutsLen ) { for ( size_t i = 0; i < keysLen; i++ ) { auto& e = mKeyMap[keys[i].keysym]; e.push_back( { keys[i].mask, keys[i].string, keys[i].appkey, keys[i].appcursor } ); @@ -24,14 +46,32 @@ TerminalKeyMap::TerminalKeyMap( const TerminalKey keys[], size_t keysLen, for ( size_t i = 0; i < shortcutsLen; i++ ) { auto& e = mShortcuts[shortcuts[i].keysym]; e.push_back( { shortcuts[i].mask, shortcuts[i].action, shortcuts[i].appkey, - shortcuts[i].appcursor } ); + shortcuts[i].appcursor, shortcuts[i].altscrn } ); + } + + for ( size_t i = 0; i < mouseShortcutsLen; i++ ) { + auto& e = mMouseShortcuts[mouseShortcuts[i].button]; + e.push_back( { mouseShortcuts[i].mask, mouseShortcuts[i].action, mouseShortcuts[i].appkey, + mouseShortcuts[i].appcursor, mouseShortcuts[i].altscrn } ); } } static TerminalShortcut shortcuts[] = { { KEY_INSERT, KEYMOD_SHIFT, TerminalShortcutAction::PASTE, 0, 0 }, { KEY_V, KEYMOD_SHIFT | KEYMOD_CTRL, TerminalShortcutAction::PASTE, 0, 0 }, - { KEY_C, KEYMOD_SHIFT | KEYMOD_CTRL, TerminalShortcutAction::COPY, 0, 0 } }; + { KEY_C, KEYMOD_SHIFT | KEYMOD_CTRL, TerminalShortcutAction::COPY, 0, 0 }, + { KEY_PAGEUP, KEYMOD_SHIFT, TerminalShortcutAction::SCROLLUP_SCREEN, 0, 0, -1 }, + { KEY_PAGEDOWN, KEYMOD_SHIFT, TerminalShortcutAction::SCROLLDOWN_SCREEN, 0, 0, -1 }, + { KEY_UP, KEYMOD_SHIFT, TerminalShortcutAction::SCROLLUP_ROW, 0, 0, -1 }, + { KEY_DOWN, KEYMOD_SHIFT, TerminalShortcutAction::SCROLLDOWN_ROW, 0, 0, -1 } }; + +static TerminalMouseShortcut mouseShortcuts[] = { + { EE_BUTTON_WUMASK, KEYMOD_SHIFT, TerminalShortcutAction::SCROLLUP_SCREEN, 0, 0, -1 }, + { EE_BUTTON_WDMASK, KEYMOD_SHIFT, TerminalShortcutAction::SCROLLDOWN_SCREEN, 0, 0, -1 }, + { EE_BUTTON_WUMASK, KEYMOD_CTRL_SHIFT_ALT_META, TerminalShortcutAction::SCROLLUP_ROW, 0, 0, + -1 }, + { EE_BUTTON_WDMASK, KEYMOD_CTRL_SHIFT_ALT_META, TerminalShortcutAction::SCROLLDOWN_ROW, 0, 0, + -1 } }; static TerminalKey keys[] = { /* keysym mask string appkey appcursor */ @@ -214,9 +254,9 @@ static TerminalScancode platformKeys[] = { { SCANCODE_KP_8, KEYMOD_CTRL_SHIFT_ALT_META, "\033Ox", +2, 0 }, { SCANCODE_KP_9, KEYMOD_CTRL_SHIFT_ALT_META, "\033Oy", +2, 0 } }; -TerminalKeyMap terminalKeyMap{ keys, eeARRAY_SIZE( keys ), - platformKeys, eeARRAY_SIZE( platformKeys ), - shortcuts, eeARRAY_SIZE( shortcuts ) }; +TerminalKeyMap terminalKeyMap{ + keys, eeARRAY_SIZE( keys ), platformKeys, eeARRAY_SIZE( platformKeys ), + shortcuts, eeARRAY_SIZE( shortcuts ), mouseShortcuts, eeARRAY_SIZE( mouseShortcuts ) }; /* Terminal colors (16 first used in escape sequence) */ // This is the customizable colorscheme @@ -337,7 +377,7 @@ 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, - IProcessFactory* processFactory ) { + const size_t& historySize, IProcessFactory* processFactory ) { if ( program.empty() ) { #ifdef _WIN32 program = "cmd.exe"; @@ -374,8 +414,8 @@ TerminalDisplay::create( EE::Window::Window* window, Font* font, const Float& fo std::shared_ptr terminal = std::shared_ptr( new TerminalDisplay( window, font, fontSize, pixelsSize ) ); - terminal->mTerminal = - TerminalEmulator::create( std::move( pseudoTerminal ), std::move( process ), terminal ); + terminal->mTerminal = TerminalEmulator::create( std::move( pseudoTerminal ), + std::move( process ), terminal, historySize ); terminal->mProgram = program; terminal->mArgs = args; terminal->mWorkingDir = workingDir; @@ -482,6 +522,26 @@ void TerminalDisplay::action( TerminalShortcutAction action ) { setClipboard( selection.c_str() ); break; } + case TerminalShortcutAction::SCROLLUP_SCREEN: { + TerminalArg arg( (int)-1 ); + mTerminal->kscrollup( &arg ); + break; + } + case TerminalShortcutAction::SCROLLDOWN_SCREEN: { + TerminalArg arg( (int)-1 ); + mTerminal->kscrolldown( &arg ); + break; + } + case TerminalShortcutAction::SCROLLUP_ROW: { + TerminalArg arg( (int)1 ); + mTerminal->kscrollup( &arg ); + break; + } + case TerminalShortcutAction::SCROLLDOWN_ROW: { + TerminalArg arg( (int)1 ); + mTerminal->kscrolldown( &arg ); + break; + } } } @@ -579,6 +639,30 @@ void TerminalDisplay::onMouseMotion( const Vector2i& pos, const Uint32& flags ) void TerminalDisplay::onMouseDown( const Vector2i& pos, const Uint32& flags ) { auto gridPos{ positionToGrid( pos ) }; + + Uint32 smod = sanitizeMod( mWindow->getInput()->getModState() ); + + auto scIt = terminalKeyMap.MouseShortcuts().find( flags ); + if ( scIt != terminalKeyMap.MouseShortcuts().end() ) { + for ( auto& k : scIt->second ) { + if ( k.mask == 0 || k.mask == KEYMOD_CTRL_SHIFT_ALT_META || k.mask == smod ) { + if ( IS_SET( MODE_APPKEYPAD ) ? k.appkey < 0 : k.appkey > 0 ) + continue; + + if ( IS_SET( MODE_NUMLOCK ) && k.appkey == 2 ) + continue; + + if ( IS_SET( MODE_APPCURSOR ) ? k.appcursor < 0 : k.appcursor > 0 ) + continue; + + if ( !k.altscrn || ( k.altscrn == ( mEmulator->tisaltscr() ? 1 : -1 ) ) ) { + action( k.action ); + return; + } + } + } + } + if ( ( flags & EE_BUTTON_LMASK ) && mLastDoubleClick.getElapsedTime() < Milliseconds( 300.f ) ) { mTerminal->selstart( gridPos.x, gridPos.y, SNAP_LINE ); @@ -621,11 +705,6 @@ static inline Color termColor( unsigned int terminalColor, terminalColor & 0xFF, ( ~( ( terminalColor >> 25 ) & 0xFF ) ) & 0xFF ); } -#define BETWEEN( x, a, b ) ( ( a ) <= ( x ) && ( x ) <= ( b ) ) -#define IS_SET( flag ) ( ( mMode & ( flag ) ) != 0 ) -#define DIV( n, d ) ( ( ( n ) + ( d ) / 2.0f ) / ( d ) ) -#define DIVI( n, d ) ( ( ( n ) + ( d ) / 2 ) / ( d ) ) - inline static void drawrect( const Color& col, const float& x, const float& y, const float& w, const float& h, Primitives& p ) { p.setColor( col ); @@ -910,7 +989,7 @@ void TerminalDisplay::draw( const Vector2f& pos ) { y += lineHeight; } - if ( !IS_SET( MODE_HIDE ) ) { + if ( !mEmulator->isScrolling() && !IS_SET( MODE_HIDE ) ) { Color drawcol; if ( IS_SET( MODE_REVERSE ) ) { if ( mEmulator->isSelected( mCursor.x, mCursor.y ) ) { @@ -1050,22 +1129,7 @@ void TerminalDisplay::onTextInput( const Uint32& chr ) { String input; input.push_back( chr ); std::string utf8Input( input.toUtf8() ); - mTerminal->write( utf8Input.c_str(), utf8Input.size() ); -} - -static Uint32 sanitizeMod( const Uint32& mod ) { - Uint32 smod = 0; - if ( mod & KEYMOD_CTRL ) - smod |= KEYMOD_CTRL; - if ( mod & KEYMOD_SHIFT ) - smod |= KEYMOD_SHIFT; - if ( mod & KEYMOD_META ) - smod |= KEYMOD_META; - if ( mod & KEYMOD_LALT ) - smod |= KEYMOD_LALT; - if ( mod & KEYMOD_RALT ) - smod |= KEYMOD_RALT; - return smod; + mTerminal->ttywrite( utf8Input.c_str(), utf8Input.size(), 1 ); } void TerminalDisplay::onKeyDown( const Keycode& keyCode, const Uint32& /*chr*/, const Uint32& mod, @@ -1085,8 +1149,10 @@ void TerminalDisplay::onKeyDown( const Keycode& keyCode, const Uint32& /*chr*/, if ( IS_SET( MODE_APPCURSOR ) ? k.appcursor < 0 : k.appcursor > 0 ) continue; - action( k.action ); - return; + if ( !k.altscrn || ( k.altscrn == ( mEmulator->tisaltscr() ? 1 : -1 ) ) ) { + action( k.action ); + return; + } } } } diff --git a/src/tools/eterm/terminal/terminaldisplay.hpp b/src/tools/eterm/terminal/terminaldisplay.hpp index 66ce735ab..0d66104ba 100644 --- a/src/tools/eterm/terminal/terminaldisplay.hpp +++ b/src/tools/eterm/terminal/terminaldisplay.hpp @@ -21,10 +21,13 @@ using namespace EE::Terminal; using namespace EE::Window; using namespace EE::System; -enum class TerminalShortcutAction { PASTE, COPY }; - -struct TerminalConfig { - int options; +enum class TerminalShortcutAction { + PASTE, + COPY, + SCROLLUP_ROW, + SCROLLDOWN_ROW, + SCROLLUP_SCREEN, + SCROLLDOWN_SCREEN }; struct TerminalKey { @@ -49,6 +52,16 @@ struct TerminalShortcut { TerminalShortcutAction action; int appkey; int appcursor; + int altscrn{ 0 }; /* 0: don't care, -1: not alt screen, 1: alt screen */ +}; + +struct TerminalMouseShortcut { + MouseButtonsMask button; + Uint32 mask; + TerminalShortcutAction action; + int appkey; + int appcursor; + int altscrn{ 0 }; /* 0: don't care, -1: not alt screen, 1: alt screen */ }; struct TerminalKeyMapEntry { @@ -63,6 +76,7 @@ struct TerminalKeyMapShortcut { TerminalShortcutAction action; int appkey; int appcursor; + int altscrn{ 0 }; /* 0: don't care, -1: not alt screen, 1: alt screen */ }; class TerminalKeyMap { @@ -70,11 +84,12 @@ class TerminalKeyMap { std::unordered_map> mKeyMap; std::unordered_map> mPlatformKeyMap; std::unordered_map> mShortcuts; + std::unordered_map> mMouseShortcuts; public: TerminalKeyMap( const TerminalKey keys[], size_t keysLen, const TerminalScancode platformKeys[], - size_t platformKeysLen, const TerminalShortcut shortcuts[], - size_t shortcutsLen ); + size_t platformKeysLen, const TerminalShortcut shortcuts[], size_t shortcutsLen, + const TerminalMouseShortcut mouseShortcuts[], size_t mouseShortcutsLen ); inline const std::unordered_map>& KeyMap() const { return mKeyMap; @@ -89,6 +104,11 @@ class TerminalKeyMap { Shortcuts() const { return mShortcuts; } + + inline const std::unordered_map>& + MouseShortcuts() const { + return mMouseShortcuts; + } }; constexpr int TerminalKeyModFlags_Any = 0xFFFFFFFF; @@ -111,7 +131,8 @@ class TerminalDisplay : public ITerminalDisplay { static std::shared_ptr create( EE::Window::Window* window, Font* font, const Float& fontSize, const Sizef& pixelsSize, std::string program = "", const std::vector& args = {}, - const std::string& workingDir = "", IProcessFactory* processFactory = nullptr ); + const std::string& workingDir = "", const size_t& historySize = 1000, + IProcessFactory* processFactory = nullptr ); virtual void resetColors(); virtual int resetColor( int index, const char* name ); diff --git a/src/tools/eterm/terminal/terminalemulator.cpp b/src/tools/eterm/terminal/terminalemulator.cpp index 9d3fce16e..d8096d873 100644 --- a/src/tools/eterm/terminal/terminalemulator.cpp +++ b/src/tools/eterm/terminal/terminalemulator.cpp @@ -106,6 +106,10 @@ static const unsigned int tabspaces = 4; #define ISCONTROLC1( c ) ( BETWEEN( c, 0x80, 0x9f ) ) #define ISCONTROL( c ) ( ISCONTROLC0( c ) || ISCONTROLC1( c ) ) #define ISDELIM( u ) ( u && _wcschr( worddelimiters, u ) ) +#define TLINE( y ) \ + ( ( y ) < mTerm.scr \ + ? mTerm.hist[( ( y ) + mTerm.histi - mTerm.scr + mTerm.histsize + 1 ) % mTerm.histsize] \ + : mTerm.line[(y)-mTerm.scr] ) using namespace EE::Terminal; @@ -365,10 +369,10 @@ void TerminalEmulator::selinit( void ) { int TerminalEmulator::tlinelen( int y ) const { int i = mTerm.col; - if ( mTerm.line[y][i - 1].mode & ATTR_WRAP ) + if ( TLINE( y )[i - 1].mode & ATTR_WRAP ) return i; - while ( i > 0 && mTerm.line[y][i - 1].u == ' ' ) + while ( i > 0 && TLINE( y )[i - 1].u == ' ' ) --i; return i; @@ -546,13 +550,13 @@ char* TerminalEmulator::getsel( void ) const { } if ( mSel.type == SEL_RECTANGULAR ) { - gp = &mTerm.line[y][mSel.nb.x]; + gp = &TLINE( y )[mSel.nb.x]; lastx = mSel.ne.x; } else { - gp = &mTerm.line[y][mSel.nb.y == y ? mSel.nb.x : 0]; + gp = &TLINE( y )[mSel.nb.y == y ? mSel.nb.x : 0]; lastx = ( mSel.ne.y == y ) ? mSel.ne.x : mTerm.col - 1; } - last = &mTerm.line[y][MIN( lastx, linelen - 1 )]; + last = &TLINE( y )[MIN( lastx, linelen - 1 )]; while ( last >= gp && last->u == ' ' ) --last; @@ -635,9 +639,55 @@ size_t TerminalEmulator::ttyread( void ) { return 0; } +void TerminalEmulator::kscrolldown( const TerminalArg* a ) { + int n = a->i; + + if ( n < 0 ) + n = mTerm.row + n; + + if ( n > mTerm.scr ) + n = mTerm.scr; + + if ( mTerm.scr > 0 ) { + mTerm.scr -= n; + selscroll( 0, -n ); + tfulldirt(); + } +} + +void TerminalEmulator::kscrollup( const TerminalArg* a ) { + int n = a->i; + + if ( n < 0 ) + n = mTerm.row + n; + + if ( mTerm.scr + n > mTerm.histi ) + n = mTerm.histi - mTerm.scr; + + if ( n == 0 ) + return; + + if ( mTerm.scr <= mTerm.histsize - n && mTerm.scr + n <= mTerm.histi ) { + mTerm.scr += n; + selscroll( 0, n ); + tfulldirt(); + } +} + +int TerminalEmulator::tisaltscr() { + return IS_SET( MODE_ALTSCREEN ); +} + +bool TerminalEmulator::isScrolling() const { + return mTerm.scr != 0; +} + void TerminalEmulator::ttywrite( const char* s, size_t n, int may_echo ) { const char* next; + TerminalArg arg = { (int)mTerm.scr }; + kscrolldown( &arg ); + if ( may_echo && IS_SET( MODE_ECHO ) ) twrite( s, (int)n, 1 ); @@ -753,12 +803,13 @@ void TerminalEmulator::treset( void ) { } } -void TerminalEmulator::tnew( int col, int row ) { +void TerminalEmulator::tnew( int col, int row, size_t historySize ) { mTerm = Term{}; mTerm.c = TerminalCursor{}; mTerm.c.attr = TerminalGlyph{}; mTerm.c.attr.fg = mDefaultFg; mTerm.c.attr.bg = mDefaultBg; + mTerm.histsize = historySize; tresize( col, row ); treset(); @@ -773,11 +824,17 @@ void TerminalEmulator::tswapscreen( void ) { tfulldirt(); } -void TerminalEmulator::tscrolldown( int orig, int n ) { +void TerminalEmulator::tscrolldown( int orig, int n, int copyhist ) { int i; Line temp; LIMIT( n, 0, mTerm.bot - orig + 1 ); + if ( copyhist ) { + mTerm.histi = ( mTerm.histi - 1 + mTerm.histsize ) % mTerm.histsize; + temp = mTerm.hist[mTerm.histi]; + mTerm.hist[mTerm.histi] = mTerm.line[mTerm.bot]; + mTerm.line[mTerm.bot] = temp; + } tsetdirt( orig, mTerm.bot - n ); tclearregion( 0, mTerm.bot - n + 1, mTerm.col - 1, mTerm.bot ); @@ -788,15 +845,26 @@ void TerminalEmulator::tscrolldown( int orig, int n ) { mTerm.line[i - n] = temp; } - selscroll( orig, n ); + if ( mTerm.scr == 0 ) + selscroll( orig, n ); } -void TerminalEmulator::tscrollup( int orig, int n ) { +void TerminalEmulator::tscrollup( int orig, int n, int copyhist ) { int i; Line temp; LIMIT( n, 0, mTerm.bot - orig + 1 ); + if ( copyhist ) { + mTerm.histi = ( mTerm.histi + 1 ) % mTerm.histsize; + temp = mTerm.hist[mTerm.histi]; + mTerm.hist[mTerm.histi] = mTerm.line[orig]; + mTerm.line[orig] = temp; + } + + if ( mTerm.scr > 0 && mTerm.scr < mTerm.histsize ) + mTerm.scr = MIN( mTerm.scr + n, mTerm.histsize - 1 ); + tclearregion( 0, orig, mTerm.col - 1, orig + n - 1 ); tsetdirt( orig + n, mTerm.bot ); @@ -806,7 +874,8 @@ void TerminalEmulator::tscrollup( int orig, int n ) { mTerm.line[i + n] = temp; } - selscroll( orig, -n ); + if ( mTerm.scr == 0 ) + selscroll( orig, -n ); } void TerminalEmulator::selscroll( int orig, int n ) { @@ -831,7 +900,7 @@ void TerminalEmulator::tnewline( int first_col ) { int y = mTerm.c.y; if ( y == mTerm.bot ) { - tscrollup( mTerm.top, 1 ); + tscrollup( mTerm.top, 1, 1 ); } else { y++; } @@ -906,23 +975,23 @@ void TerminalEmulator::tsetchar( Rune u, TerminalGlyph* attr, int x, int y ) { vt100_0[u - 0x41] ) utf8decode( vt100_0[u - 0x41], &u, UTF_SIZ ); - if ( mTerm.line[y][x].mode & ATTR_WIDE ) { + if ( TLINE( y )[x].mode & ATTR_WIDE ) { if ( x + 1 < mTerm.col ) { - mTerm.line[y][x + 1].u = ' '; - mTerm.line[y][x + 1].mode &= ~ATTR_WDUMMY; + TLINE( y )[x + 1].u = ' '; + TLINE( y )[x + 1].mode &= ~ATTR_WDUMMY; } - } else if ( mTerm.line[y][x].mode & ATTR_WDUMMY ) { - mTerm.line[y][x - 1].u = ' '; - mTerm.line[y][x - 1].mode &= ~ATTR_WIDE; + } else if ( TLINE( y )[x].mode & ATTR_WDUMMY ) { + TLINE( y )[x - 1].u = ' '; + TLINE( y )[x - 1].mode &= ~ATTR_WIDE; } mTerm.dirty[y] = 1; - mTerm.line[y][x] = *attr; - mTerm.line[y][x].u = u; + TLINE( y )[x] = *attr; + TLINE( y )[x].u = u; mDirty = true; if ( isboxdraw( u ) ) - mTerm.line[y][x].mode |= ATTR_BOXDRAW; + TLINE( y )[x].mode |= ATTR_BOXDRAW; } void TerminalEmulator::tclearregion( int x1, int y1, int x2, int y2 ) { @@ -943,7 +1012,7 @@ void TerminalEmulator::tclearregion( int x1, int y1, int x2, int y2 ) { mTerm.dirty[y] = 1; mDirty = true; for ( x = x1; x <= x2; x++ ) { - gp = &mTerm.line[y][x]; + gp = &TLINE( y )[x]; if ( selected( x, y ) ) selclear(); gp->fg = mTerm.c.attr.fg; @@ -986,12 +1055,12 @@ void TerminalEmulator::tinsertblank( int n ) { void TerminalEmulator::tinsertblankline( int n ) { if ( BETWEEN( mTerm.c.y, mTerm.top, mTerm.bot ) ) - tscrolldown( mTerm.c.y, n ); + tscrolldown( mTerm.c.y, n, 0 ); } void TerminalEmulator::tdeleteline( int n ) { if ( BETWEEN( mTerm.c.y, mTerm.top, mTerm.bot ) ) - tscrollup( mTerm.c.y, n ); + tscrollup( mTerm.c.y, n, 0 ); } int32_t TerminalEmulator::tdefcolor( int* attr, int* npar, int l ) { @@ -1398,11 +1467,11 @@ void TerminalEmulator::csihandle( void ) { break; case 'S': /* SU -- Scroll line up */ DEFAULT( mCsiescseq.arg[0], 1 ); - tscrollup( mTerm.top, mCsiescseq.arg[0] ); + tscrollup( mTerm.top, mCsiescseq.arg[0], 1 ); break; case 'T': /* SD -- Scroll line down */ DEFAULT( mCsiescseq.arg[0], 1 ); - tscrolldown( mTerm.top, mCsiescseq.arg[0] ); + tscrolldown( mTerm.top, mCsiescseq.arg[0], 1 ); break; case 'L': /* IL -- Insert blank lines */ DEFAULT( mCsiescseq.arg[0], 1 ); @@ -1880,7 +1949,7 @@ int TerminalEmulator::eschandle( uchar ascii ) { return 0; case 'D': /* IND -- Linefeed */ if ( mTerm.c.y == mTerm.bot ) { - tscrollup( mTerm.top, 1 ); + tscrollup( mTerm.top, 1, 1 ); } else { tmoveto( mTerm.c.x, mTerm.c.y + 1 ); } @@ -1893,7 +1962,7 @@ int TerminalEmulator::eschandle( uchar ascii ) { break; case 'M': /* RI -- Reverse index */ if ( mTerm.c.y == mTerm.top ) { - tscrolldown( mTerm.top, 1 ); + tscrolldown( mTerm.top, 1, 1 ); } else { tmoveto( mTerm.c.x, mTerm.c.y - 1 ); } @@ -2137,7 +2206,7 @@ int TerminalEmulator::twrite( const char* buf, int buflen, int show_ctrl ) { } void TerminalEmulator::tresize( int col, int row ) { - int i; + int i, j; int minrow = MIN( row, mTerm.row ); int mincol = MIN( col, mTerm.col ); int* bp; @@ -2173,6 +2242,15 @@ void TerminalEmulator::tresize( int col, int row ) { mTerm.dirty = (int*)xrealloc( mTerm.dirty, row * sizeof( *mTerm.dirty ) ); mTerm.tabs = (int*)xrealloc( mTerm.tabs, col * sizeof( *mTerm.tabs ) ); + mTerm.hist.resize( mTerm.histsize, nullptr ); + for ( i = 0; i < mTerm.histsize; i++ ) { + mTerm.hist[i] = (TerminalGlyph*)xrealloc( mTerm.hist[i], col * sizeof( TerminalGlyph ) ); + for ( j = mincol; j < col; j++ ) { + mTerm.hist[i][j] = mTerm.c.attr; + mTerm.hist[i][j].u = ' '; + } + } + /* resize each row to new width, zero-pad if needed */ for ( i = 0; i < minrow; i++ ) { mTerm.line[i] = (Line)xrealloc( mTerm.line[i], col * sizeof( TerminalGlyph ) ); @@ -2231,7 +2309,7 @@ void TerminalEmulator::drawregion( ITerminalDisplay& dpy, int x1, int y1, int x2 mTerm.dirty[y] = 0; - dpy.drawLine( mTerm.line[y], x1, y, x2 ); + dpy.drawLine( TLINE( y ), x1, y, x2 ); } mDirty = false; @@ -2257,8 +2335,9 @@ void TerminalEmulator::draw() { drawregion( *dpy, 0, 0, mTerm.col, mTerm.row ); - dpy->drawCursor( cx, mTerm.c.y, mTerm.line[mTerm.c.y][cx], mTerm.ocx, mTerm.ocy, - mTerm.line[mTerm.ocy][mTerm.ocx] ); + if ( mTerm.scr == 0 ) + dpy->drawCursor( cx, mTerm.c.y, mTerm.line[mTerm.c.y][cx], mTerm.ocx, mTerm.ocy, + mTerm.line[mTerm.ocy][mTerm.ocx] ); mTerm.ocx = cx; mTerm.ocy = mTerm.c.y; @@ -2376,18 +2455,20 @@ void TerminalEmulator::xsetpointermotion( int ) { std::unique_ptr TerminalEmulator::create( PtyPtr&& pty, ProcPtr&& process, - const std::shared_ptr& display ) { + const std::shared_ptr& display, + const size_t& historySize ) { if ( !pty || !process ) { fprintf( stderr, "Must provide valid pseudoterminal and process" ); return nullptr; } return std::unique_ptr( - new TerminalEmulator( std::move( pty ), std::move( process ), display ) ); + new TerminalEmulator( std::move( pty ), std::move( process ), display, historySize ) ); } TerminalEmulator::TerminalEmulator( PtyPtr&& pty, ProcPtr&& process, - const std::shared_ptr& display ) : + const std::shared_ptr& display, + const size_t& historySize ) : mDpy( display ), mPty( std::move( pty ) ), mProcess( std::move( process ) ), @@ -2402,7 +2483,6 @@ TerminalEmulator::TerminalEmulator( PtyPtr&& pty, ProcPtr&& process, mAllowAltScreen( 1 ), mAllowWindowOps( 1 ) { memset( mBuf, 0, sizeof( mBuf ) ); - memset( &mTerm, 0, sizeof( mTerm ) ); memset( &mSel, 0, sizeof( mSel ) ); memset( &mCsiescseq, 0, sizeof( mCsiescseq ) ); memset( &mStrescseq, 0, sizeof( mStrescseq ) ); @@ -2410,7 +2490,7 @@ TerminalEmulator::TerminalEmulator( PtyPtr&& pty, ProcPtr&& process, int col = mPty->getNumColumns(); int row = mPty->getNumRows(); - tnew( col, row ); + tnew( col, row, historySize ); if ( display ) { display->setCursorMode( TerminalCursorMode::SteadyUnderline ); display->attach( this ); @@ -2479,6 +2559,10 @@ int TerminalEmulator::getExitCode() const { return mExitCode; } +int TerminalEmulator::write( const char* buf, size_t buflen ) { + return mPty->write( buf, (int)buflen ); +} + void TerminalEmulator::resize( int columns, int rows ) { if ( !mPty->resize( columns, rows ) ) { _die( "Failed to resize pty!" ); diff --git a/src/tools/eterm/terminal/terminalemulator.hpp b/src/tools/eterm/terminal/terminalemulator.hpp index 6d4e0868b..6a52b0ca3 100644 --- a/src/tools/eterm/terminal/terminalemulator.hpp +++ b/src/tools/eterm/terminal/terminalemulator.hpp @@ -59,23 +59,27 @@ constexpr int STR_ARG_SIZ = ESC_ARG_SIZ; /* Internal representation of the screen */ struct Term { - int row; /* nb row */ - int col; /* nb col */ - Line* line; /* screen */ - Line* alt; /* alternate screen */ - int* dirty; /* dirtyness of lines */ - TerminalCursor c; /* cursor */ - int ocx; /* old cursor col */ - int ocy; /* old cursor row */ - int top; /* top scroll limit */ - int bot; /* bottom scroll limit */ - int mode; /* terminal mode flags */ - int esc; /* escape state flags */ - char trantbl[4]; /* charset table translation */ - int charset; /* current charset */ - int icharset; /* selected charset for sequence */ - int* tabs; - Rune lastc; /* last printed char outside of sequence, 0 if control */ + int row{ 0 }; /* nb row */ + int col{ 0 }; /* nb col */ + Line* line{ nullptr }; /* screen */ + Line* alt{ nullptr }; /* alternate screen */ + std::vector hist; /* history buffer */ + int histsize{ 0 }; /* history size */ + int histi{ 0 }; /* history index */ + int scr{ 0 }; /* scroll back */ + int* dirty{ nullptr }; /* dirtyness of lines */ + TerminalCursor c{}; /* cursor */ + int ocx{ 0 }; /* old cursor col */ + int ocy{ 0 }; /* old cursor row */ + int top{ 0 }; /* top scroll limit */ + int bot{ 0 }; /* bottom scroll limit */ + int mode{ 0 }; /* terminal mode flags */ + int esc{ 0 }; /* escape state flags */ + char trantbl[4]{ 0, 0, 0, 0 }; /* charset table translation */ + int charset{ 0 }; /* current charset */ + int icharset{ 0 }; /* selected charset for sequence */ + int* tabs{ nullptr }; + Rune lastc{ 0 }; /* last printed char outside of sequence, 0 if control */ }; /* CSI Escape sequence structs */ @@ -121,7 +125,8 @@ class TerminalEmulator final { TerminalEmulator& operator=( TerminalEmulator&& ) = delete; static std::unique_ptr - create( PtyPtr&& pty, ProcPtr&& process, const std::shared_ptr& display ); + create( PtyPtr&& pty, ProcPtr&& process, const std::shared_ptr& display, + const size_t& historySize = 1000 ); void resize( int columns, int rows ); @@ -151,7 +156,7 @@ class TerminalEmulator final { inline int getNumRows() const { return mTerm.row; } - inline int write( const char* buf, size_t buflen ) { return mPty->write( buf, (int)buflen ); } + int write( const char* buf, size_t buflen ); void printscreen( const TerminalArg* ); @@ -184,6 +189,16 @@ class TerminalEmulator final { void setPtyAndProcess( PtyPtr&& pty, ProcPtr&& process ); + void kscrolldown( const TerminalArg* a ); + + void kscrollup( const TerminalArg* a ); + + bool isScrolling() const; + + void ttywrite( const char*, size_t, int ); + + int tisaltscr(); + private: DpyPtr mDpy; PtyPtr mPty; @@ -247,8 +262,8 @@ class TerminalEmulator final { void tputtab( int ); void tputc( Rune ); void treset(); - void tscrollup( int, int ); - void tscrolldown( int, int ); + void tscrollup( int, int, int ); + void tscrolldown( int, int, int ); void tsetattr( int*, int ); void tsetchar( Rune, TerminalGlyph*, int, int ); void tsetdirt( int, int ); @@ -273,13 +288,12 @@ class TerminalEmulator final { void draw(); int tattrset( int ); - void tnew( int, int ); + void tnew( int, int, size_t ); void tresize( int, int ); void tsetdirtattr( int ); void ttyhangup(); size_t ttyread(); - void ttywrite( const char*, size_t, int ); void ttywriteraw( const char*, size_t ); void resettitle(); @@ -299,7 +313,8 @@ class TerminalEmulator final { void xximspot( int, int ); TerminalEmulator( PtyPtr&& pty, ProcPtr&& process, - const std::shared_ptr& display ); + const std::shared_ptr& display, + const size_t& historySize = 1000 ); }; }} // namespace EE::Terminal diff --git a/src/tools/eterm/terminal/types.hpp b/src/tools/eterm/terminal/types.hpp index b078c4763..3f293dc2d 100644 --- a/src/tools/eterm/terminal/types.hpp +++ b/src/tools/eterm/terminal/types.hpp @@ -92,10 +92,10 @@ typedef unsigned short ushort; typedef uint_least32_t Rune; struct TerminalGlyph { - Rune u; /* character code */ - ushort mode; /* attribute flags */ - uint32_t fg; /* foreground */ - uint32_t bg; /* background */ + Rune u{ 0 }; /* character code */ + ushort mode{ 0 }; /* attribute flags */ + uint32_t fg{ 0 }; /* foreground */ + uint32_t bg{ 0 }; /* background */ bool operator==( const TerminalGlyph& r ) { return u == r.u && mode == r.mode && fg == r.fg && bg == r.bg; @@ -149,9 +149,9 @@ enum TerminalEscapeState { struct TerminalCursor { TerminalGlyph attr; /* current char attributes */ - int x; - int y; - char state; + int x{ 0 }; + int y{ 0 }; + char state{ 0 }; }; struct TerminalSelection {