eterm: Added scrolling history support.

This commit is contained in:
Martín Lucas Golini
2022-06-26 03:11:15 -03:00
parent dfde262ec1
commit 716eaea2c0
6 changed files with 294 additions and 108 deletions

View File

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

View File

@@ -7,9 +7,31 @@
#include <eepp/window.hpp>
#include <eepp/window/clipboard.hpp>
#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>
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,
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<TerminalDisplay> terminal = std::shared_ptr<TerminalDisplay>(
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;
}
}
}
}

View File

@@ -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<Keycode, std::vector<TerminalKeyMapEntry>> mKeyMap;
std::unordered_map<Scancode, std::vector<TerminalKeyMapEntry>> mPlatformKeyMap;
std::unordered_map<Keycode, std::vector<TerminalKeyMapShortcut>> mShortcuts;
std::unordered_map<Uint32, std::vector<TerminalKeyMapShortcut>> 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<Keycode, std::vector<TerminalKeyMapEntry>>& KeyMap() const {
return mKeyMap;
@@ -89,6 +104,11 @@ class TerminalKeyMap {
Shortcuts() const {
return mShortcuts;
}
inline const std::unordered_map<Uint32, std::vector<TerminalKeyMapShortcut>>&
MouseShortcuts() const {
return mMouseShortcuts;
}
};
constexpr int TerminalKeyModFlags_Any = 0xFFFFFFFF;
@@ -111,7 +131,8 @@ class TerminalDisplay : public ITerminalDisplay {
static std::shared_ptr<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 = "", 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 );

View File

@@ -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 <n> 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 <n> 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 <n> 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>
TerminalEmulator::create( PtyPtr&& pty, ProcPtr&& process,
const std::shared_ptr<ITerminalDisplay>& display ) {
const std::shared_ptr<ITerminalDisplay>& display,
const size_t& historySize ) {
if ( !pty || !process ) {
fprintf( stderr, "Must provide valid pseudoterminal and process" );
return nullptr;
}
return std::unique_ptr<TerminalEmulator>(
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<ITerminalDisplay>& display ) :
const std::shared_ptr<ITerminalDisplay>& 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!" );

View File

@@ -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<Line> 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<TerminalEmulator>
create( PtyPtr&& pty, ProcPtr&& process, const std::shared_ptr<ITerminalDisplay>& display );
create( PtyPtr&& pty, ProcPtr&& process, const std::shared_ptr<ITerminalDisplay>& 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<ITerminalDisplay>& display );
const std::shared_ptr<ITerminalDisplay>& display,
const size_t& historySize = 1000 );
};
}} // namespace EE::Terminal

View File

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