mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
eterm: Added scrolling history support.
This commit is contained in:
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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!" );
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user