mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-01 18:50:16 +03:00
Rename TerminalController to TerminalSession.
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
#include <eepp/window/window.hpp>
|
||||
#include <eterm/system/iprocessfactory.hpp>
|
||||
#include <eterm/terminal/terminalcolorscheme.hpp>
|
||||
#include <eterm/terminal/terminalcontroller.hpp>
|
||||
#include <eterm/terminal/terminalsession.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
@@ -242,7 +242,7 @@ class TerminalDisplay {
|
||||
|
||||
void setPadding( const Rectf& padding );
|
||||
|
||||
const std::shared_ptr<TerminalController>& getController() const;
|
||||
const std::shared_ptr<TerminalSession>& getSession() const;
|
||||
|
||||
std::string getSelection();
|
||||
|
||||
@@ -313,7 +313,7 @@ class TerminalDisplay {
|
||||
protected:
|
||||
EE::Window::Window* mWindow;
|
||||
std::vector<Color> mColors;
|
||||
std::shared_ptr<TerminalController> mController;
|
||||
std::shared_ptr<TerminalSession> mSession;
|
||||
std::shared_ptr<const TerminalSnapshot> mSnapshot;
|
||||
mutable std::string mClipboardUtf8;
|
||||
Uint32 mNumCallBacks{ 0 };
|
||||
@@ -382,7 +382,7 @@ class TerminalDisplay {
|
||||
|
||||
void consumeSnapshot();
|
||||
|
||||
void drainControllerEvents();
|
||||
void drainSessionEvents();
|
||||
|
||||
TerminalColorPalette makeColorPalette() const;
|
||||
|
||||
|
||||
+16
-16
@@ -1,5 +1,5 @@
|
||||
#ifndef ETERM_TERMINALCONTROLLER_HPP
|
||||
#define ETERM_TERMINALCONTROLLER_HPP
|
||||
#ifndef ETERM_TERMINALSESSION_HPP
|
||||
#define ETERM_TERMINALSESSION_HPP
|
||||
|
||||
#include <eepp/math/vector2.hpp>
|
||||
#include <eepp/window/keycodes.hpp>
|
||||
@@ -69,13 +69,13 @@ struct TerminalColorPalette {
|
||||
};
|
||||
|
||||
/**
|
||||
* Per-terminal worker/controller.
|
||||
* Per-terminal worker/session.
|
||||
*
|
||||
* After create() returns, the worker thread exclusively owns the emulator, PTY, process, parser,
|
||||
* history, selection, and cursor. UI code may only enqueue commands, drain events, or retain an
|
||||
* immutable snapshot returned by snapshot(). No controller callback is invoked by the worker.
|
||||
* immutable snapshot returned by snapshot(). No session callback is invoked by the worker.
|
||||
*/
|
||||
class TerminalController final : public std::enable_shared_from_this<TerminalController> {
|
||||
class TerminalSession final : public std::enable_shared_from_this<TerminalSession> {
|
||||
public:
|
||||
using PtyPtr = std::unique_ptr<IPseudoTerminal>;
|
||||
using ProcPtr = std::unique_ptr<IProcess>;
|
||||
@@ -104,16 +104,16 @@ class TerminalController final : public std::enable_shared_from_this<TerminalCon
|
||||
PromptState promptState{ PromptState::Unknown };
|
||||
};
|
||||
|
||||
static std::shared_ptr<TerminalController> create( PtyPtr&& pty, ProcPtr&& process,
|
||||
size_t historySize,
|
||||
TerminalColorPalette palette = {} );
|
||||
static std::shared_ptr<TerminalSession> create( PtyPtr&& pty, ProcPtr&& process,
|
||||
size_t historySize,
|
||||
TerminalColorPalette palette = {} );
|
||||
|
||||
~TerminalController();
|
||||
~TerminalSession();
|
||||
|
||||
TerminalController( const TerminalController& ) = delete;
|
||||
TerminalController( TerminalController&& ) = delete;
|
||||
TerminalController& operator=( const TerminalController& ) = delete;
|
||||
TerminalController& operator=( TerminalController&& ) = delete;
|
||||
TerminalSession( const TerminalSession& ) = delete;
|
||||
TerminalSession( TerminalSession&& ) = delete;
|
||||
TerminalSession& operator=( const TerminalSession& ) = delete;
|
||||
TerminalSession& operator=( TerminalSession&& ) = delete;
|
||||
|
||||
void write( std::string data, bool mayEcho = true );
|
||||
void writeRaw( std::string data );
|
||||
@@ -218,8 +218,8 @@ class TerminalController final : public std::enable_shared_from_this<TerminalCon
|
||||
PromptEventsCommand, TerminateCommand, RestartCommand, ResetCommand,
|
||||
SelectionRequestCommand>;
|
||||
|
||||
TerminalController( PtyPtr&& pty, ProcPtr&& process, size_t historySize,
|
||||
TerminalColorPalette palette );
|
||||
TerminalSession( PtyPtr&& pty, ProcPtr&& process, size_t historySize,
|
||||
TerminalColorPalette palette );
|
||||
|
||||
void start();
|
||||
bool enqueue( Command&& command );
|
||||
@@ -246,4 +246,4 @@ class TerminalController final : public std::enable_shared_from_this<TerminalCon
|
||||
|
||||
}} // namespace eterm::Terminal
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -450,15 +450,15 @@ std::shared_ptr<TerminalDisplay> TerminalDisplay::create(
|
||||
std::shared_ptr<TerminalDisplay> terminal = std::shared_ptr<TerminalDisplay>(
|
||||
new TerminalDisplay( window, font, fontSize, pixelsSize, useFrameBuffer ) );
|
||||
|
||||
terminal->mController =
|
||||
TerminalController::create( std::move( pseudoTerminal ), std::move( process ), historySize,
|
||||
terminal->makeColorPalette() );
|
||||
if ( !terminal->mController ) {
|
||||
terminal->mSession =
|
||||
TerminalSession::create( std::move( pseudoTerminal ), std::move( process ), historySize,
|
||||
terminal->makeColorPalette() );
|
||||
if ( !terminal->mSession ) {
|
||||
if ( freeProcessFactory )
|
||||
eeSAFE_DELETE( processFactory );
|
||||
return nullptr;
|
||||
}
|
||||
terminal->mController->setPresentationRate( presentationRateForWindow( window ) );
|
||||
terminal->mSession->setPresentationRate( presentationRateForWindow( window ) );
|
||||
terminal->mProgram = program;
|
||||
terminal->mArgs = args;
|
||||
terminal->mEnv = env;
|
||||
@@ -473,8 +473,8 @@ std::shared_ptr<TerminalDisplay> TerminalDisplay::create(
|
||||
}
|
||||
|
||||
TerminalDisplay::~TerminalDisplay() {
|
||||
if ( mController )
|
||||
mController->shutdown();
|
||||
if ( mSession )
|
||||
mSession->shutdown();
|
||||
}
|
||||
|
||||
TerminalDisplay::TerminalDisplay( EE::Window::Window* window, Font* font, const Float& fontSize,
|
||||
@@ -621,8 +621,8 @@ void TerminalDisplay::setPadding( const Rectf& padding ) {
|
||||
}
|
||||
}
|
||||
|
||||
const std::shared_ptr<TerminalController>& TerminalDisplay::getController() const {
|
||||
return mController;
|
||||
const std::shared_ptr<TerminalSession>& TerminalDisplay::getSession() const {
|
||||
return mSession;
|
||||
}
|
||||
|
||||
int TerminalDisplay::scrollSize() const {
|
||||
@@ -638,7 +638,7 @@ int TerminalDisplay::scrollPosition() const {
|
||||
}
|
||||
|
||||
Uint64 TerminalDisplay::scrollTo( int position ) {
|
||||
return mController ? mController->scrollTo( position ) : 0;
|
||||
return mSession ? mSession->scrollTo( position ) : 0;
|
||||
}
|
||||
|
||||
Uint64 TerminalDisplay::lastAppliedScrollCommand() const {
|
||||
@@ -679,13 +679,13 @@ const TerminalColorScheme& TerminalDisplay::getColorScheme() const {
|
||||
void TerminalDisplay::setColorScheme( const TerminalColorScheme& colorScheme ) {
|
||||
mColorScheme = colorScheme;
|
||||
resetColors();
|
||||
if ( mController )
|
||||
mController->setColorPalette( makeColorPalette() );
|
||||
if ( mSession )
|
||||
mSession->setColorPalette( makeColorPalette() );
|
||||
invalidateLines();
|
||||
}
|
||||
|
||||
bool TerminalDisplay::isAppCapturingMouse() const {
|
||||
return mController &&
|
||||
return mSession &&
|
||||
( mMode & ( MODE_MOUSEX10 | MODE_MOUSEBTN | MODE_MOUSEMOTION | MODE_MOUSEMANY ) );
|
||||
}
|
||||
|
||||
@@ -711,7 +711,7 @@ void TerminalDisplay::setKeepAlive( bool keepAlive ) {
|
||||
|
||||
bool TerminalDisplay::update( bool isMouseOverMe ) {
|
||||
consumeSnapshot();
|
||||
drainControllerEvents();
|
||||
drainSessionEvents();
|
||||
if ( mFocus && isBlinkingCursor() && mClock.getElapsedTime().asSeconds() > 0.7 ) {
|
||||
mMode ^= MODE_BLINK;
|
||||
mClock.restart();
|
||||
@@ -730,9 +730,9 @@ bool TerminalDisplay::update( bool isMouseOverMe ) {
|
||||
}
|
||||
|
||||
void TerminalDisplay::consumeSnapshot() {
|
||||
if ( !mController )
|
||||
if ( !mSession )
|
||||
return;
|
||||
auto snapshot = mController->snapshot();
|
||||
auto snapshot = mSession->snapshot();
|
||||
if ( !snapshot || snapshot->generation == mSnapshotGeneration )
|
||||
return;
|
||||
|
||||
@@ -781,56 +781,56 @@ void TerminalDisplay::consumeSnapshot() {
|
||||
mDirty = true;
|
||||
}
|
||||
|
||||
void TerminalDisplay::drainControllerEvents() {
|
||||
if ( !mController )
|
||||
void TerminalDisplay::drainSessionEvents() {
|
||||
if ( !mSession )
|
||||
return;
|
||||
for ( auto& event : mController->drainEvents() ) {
|
||||
for ( auto& event : mSession->drainEvents() ) {
|
||||
switch ( event.type ) {
|
||||
case TerminalController::EventType::Title:
|
||||
case TerminalSession::EventType::Title:
|
||||
sendEvent( { EventType::TITLE, std::move( event.data ) } );
|
||||
break;
|
||||
case TerminalController::EventType::IconTitle:
|
||||
case TerminalSession::EventType::IconTitle:
|
||||
sendEvent( { EventType::ICON_TITLE, std::move( event.data ) } );
|
||||
break;
|
||||
case TerminalController::EventType::ScrollPosition:
|
||||
case TerminalSession::EventType::ScrollPosition:
|
||||
sendEvent( { EventType::SCROLL_HISTORY } );
|
||||
break;
|
||||
case TerminalController::EventType::Bell:
|
||||
case TerminalSession::EventType::Bell:
|
||||
sendEvent( { EventType::BELL } );
|
||||
break;
|
||||
case TerminalController::EventType::Clipboard:
|
||||
case TerminalSession::EventType::Clipboard:
|
||||
setClipboard( event.data.c_str() );
|
||||
sendEvent( { EventType::CLIPBOARD } );
|
||||
break;
|
||||
case TerminalController::EventType::ProcessExit:
|
||||
case TerminalSession::EventType::ProcessExit:
|
||||
onProcessExit( event.value );
|
||||
break;
|
||||
case TerminalController::EventType::RestartFailure:
|
||||
case TerminalSession::EventType::RestartFailure:
|
||||
sendEvent( { EventType::RESTART_FAILURE, std::move( event.data ) } );
|
||||
break;
|
||||
case TerminalController::EventType::Data:
|
||||
case TerminalSession::EventType::Data:
|
||||
if ( mDataCallback )
|
||||
mDataCallback( event.data.data(), event.data.size() );
|
||||
break;
|
||||
case TerminalController::EventType::PromptState:
|
||||
case TerminalSession::EventType::PromptState:
|
||||
if ( mPromptStateChangedCallback )
|
||||
mPromptStateChangedCallback( event.promptState, event.data );
|
||||
break;
|
||||
case TerminalController::EventType::Color:
|
||||
case TerminalSession::EventType::Color:
|
||||
if ( event.value < 0 )
|
||||
resetColors();
|
||||
else
|
||||
resetColor( event.value, event.data.empty() ? nullptr : event.data.c_str() );
|
||||
invalidateLines();
|
||||
break;
|
||||
case TerminalController::EventType::Error:
|
||||
case TerminalSession::EventType::Error:
|
||||
Log::error( "Terminal worker error: %s", event.data.c_str() );
|
||||
sendEvent( { EventType::WORKER_ERROR, std::move( event.data ) } );
|
||||
break;
|
||||
case TerminalController::EventType::HistoryLength:
|
||||
case TerminalSession::EventType::HistoryLength:
|
||||
sendEvent( { EventType::HISTORY_LENGTH_CHANGE } );
|
||||
break;
|
||||
case TerminalController::EventType::SnapshotReady:
|
||||
case TerminalSession::EventType::SnapshotReady:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -848,8 +848,8 @@ TerminalColorPalette TerminalDisplay::makeColorPalette() const {
|
||||
}
|
||||
|
||||
std::string TerminalDisplay::getSelection() {
|
||||
if ( mController ) {
|
||||
if ( auto selection = mController->requestSelection() )
|
||||
if ( mSession ) {
|
||||
if ( auto selection = mSession->requestSelection() )
|
||||
return std::move( *selection );
|
||||
}
|
||||
return mSnapshot ? mSnapshot->selection : std::string{};
|
||||
@@ -872,33 +872,33 @@ int TerminalDisplay::getExitCode() const {
|
||||
}
|
||||
|
||||
void TerminalDisplay::terminate() {
|
||||
if ( mController )
|
||||
mController->terminate();
|
||||
if ( mSession )
|
||||
mSession->terminate();
|
||||
}
|
||||
|
||||
void TerminalDisplay::setAllowMemoryTrimming( bool allow ) {
|
||||
if ( mController )
|
||||
mController->setAllowMemoryTrimming( allow );
|
||||
if ( mSession )
|
||||
mSession->setAllowMemoryTrimming( allow );
|
||||
}
|
||||
|
||||
void TerminalDisplay::setDataCallback( DataFunc callback ) {
|
||||
mDataCallback = std::move( callback );
|
||||
if ( mController )
|
||||
mController->setDataEventsEnabled( static_cast<bool>( mDataCallback ) );
|
||||
if ( mSession )
|
||||
mSession->setDataEventsEnabled( static_cast<bool>( mDataCallback ) );
|
||||
}
|
||||
|
||||
void TerminalDisplay::setPromptStateChangedCallback( PromptStateChangedFunc callback ) {
|
||||
mPromptStateChangedCallback = std::move( callback );
|
||||
if ( mController )
|
||||
mController->setPromptEventsEnabled( static_cast<bool>( mPromptStateChangedCallback ) );
|
||||
if ( mSession )
|
||||
mSession->setPromptEventsEnabled( static_cast<bool>( mPromptStateChangedCallback ) );
|
||||
}
|
||||
|
||||
void TerminalDisplay::setCursorMode( TerminalCursorMode mode ) {
|
||||
if ( mCursorMode == mode )
|
||||
return;
|
||||
mCursorMode = mode;
|
||||
if ( mController )
|
||||
mController->setCursorMode( mode );
|
||||
if ( mSession )
|
||||
mSession->setCursorMode( mode );
|
||||
invalidateCursor();
|
||||
}
|
||||
|
||||
@@ -907,29 +907,29 @@ TerminalCursorMode TerminalDisplay::getCursorMode() const {
|
||||
}
|
||||
|
||||
void TerminalDisplay::executeFile( const std::string& cmd ) {
|
||||
if ( mController ) {
|
||||
if ( mSession ) {
|
||||
std::string rcmd;
|
||||
#if EE_PLATFORM != EE_PLATFORM_WIN
|
||||
rcmd.push_back( 0x15 );
|
||||
#endif
|
||||
rcmd.append( cmd ).push_back( '\r' );
|
||||
mController->write( std::move( rcmd ) );
|
||||
mSession->write( std::move( rcmd ) );
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalDisplay::executeBinary( const std::string& binaryPath, const std::string& args ) {
|
||||
if ( mController ) {
|
||||
if ( mSession ) {
|
||||
std::string rcmd;
|
||||
#if EE_PLATFORM != EE_PLATFORM_WIN
|
||||
rcmd.push_back( 0x15 );
|
||||
#endif
|
||||
rcmd.append( "\"" ).append( binaryPath ).append( "\" " ).append( args ).push_back( '\r' );
|
||||
mController->write( std::move( rcmd ) );
|
||||
mSession->write( std::move( rcmd ) );
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalDisplay::action( TerminalShortcutAction action ) {
|
||||
if ( !mController && action != TerminalShortcutAction::FONTSIZE_GROW &&
|
||||
if ( !mSession && action != TerminalShortcutAction::FONTSIZE_GROW &&
|
||||
action != TerminalShortcutAction::FONTSIZE_SHRINK )
|
||||
return;
|
||||
switch ( action ) {
|
||||
@@ -937,11 +937,11 @@ void TerminalDisplay::action( TerminalShortcutAction action ) {
|
||||
getClipboard();
|
||||
if ( !mClipboardUtf8.empty() ) {
|
||||
if ( mMode & MODE_BRCKTPASTE ) {
|
||||
mController->writeRaw( "\033[200~" );
|
||||
mController->writeRaw( std::move( mClipboardUtf8 ) );
|
||||
mController->writeRaw( "\033[201~" );
|
||||
mSession->writeRaw( "\033[200~" );
|
||||
mSession->writeRaw( std::move( mClipboardUtf8 ) );
|
||||
mSession->writeRaw( "\033[201~" );
|
||||
} else {
|
||||
mController->writeRaw( std::move( mClipboardUtf8 ) );
|
||||
mSession->writeRaw( std::move( mClipboardUtf8 ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -955,11 +955,11 @@ void TerminalDisplay::action( TerminalShortcutAction action ) {
|
||||
sanitizeInput( selection );
|
||||
if ( !selection.empty() ) {
|
||||
if ( mMode & MODE_BRCKTPASTE ) {
|
||||
mController->writeRaw( "\033[200~" );
|
||||
mController->writeRaw( std::move( selection ) );
|
||||
mController->writeRaw( "\033[201~" );
|
||||
mSession->writeRaw( "\033[200~" );
|
||||
mSession->writeRaw( std::move( selection ) );
|
||||
mSession->writeRaw( "\033[201~" );
|
||||
} else {
|
||||
mController->writeRaw( std::move( selection ) );
|
||||
mSession->writeRaw( std::move( selection ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -971,27 +971,27 @@ void TerminalDisplay::action( TerminalShortcutAction action ) {
|
||||
break;
|
||||
}
|
||||
case TerminalShortcutAction::SCROLLUP_SCREEN: {
|
||||
mController->scrollUp( -(int)mClickStep );
|
||||
mSession->scrollUp( -(int)mClickStep );
|
||||
break;
|
||||
}
|
||||
case TerminalShortcutAction::SCROLLDOWN_SCREEN: {
|
||||
mController->scrollDown( -(int)mClickStep );
|
||||
mSession->scrollDown( -(int)mClickStep );
|
||||
break;
|
||||
}
|
||||
case TerminalShortcutAction::SCROLLUP_ROW: {
|
||||
mController->scrollUp( mClickStep );
|
||||
mSession->scrollUp( mClickStep );
|
||||
break;
|
||||
}
|
||||
case TerminalShortcutAction::SCROLLDOWN_ROW: {
|
||||
mController->scrollDown( mClickStep );
|
||||
mSession->scrollDown( mClickStep );
|
||||
break;
|
||||
}
|
||||
case TerminalShortcutAction::SCROLLUP_HISTORY: {
|
||||
mController->scrollUp( INT_MAX );
|
||||
mSession->scrollUp( INT_MAX );
|
||||
break;
|
||||
}
|
||||
case TerminalShortcutAction::SCROLLDOWN_HISTORY: {
|
||||
mController->scrollDown( INT_MAX );
|
||||
mSession->scrollDown( INT_MAX );
|
||||
break;
|
||||
}
|
||||
case TerminalShortcutAction::FONTSIZE_GROW: {
|
||||
@@ -1055,7 +1055,7 @@ void TerminalDisplay::onMouseDoubleClick( const Vector2i& pos, const Uint32& fla
|
||||
if ( !isAppCapturingMouse() && ( flags & EE_BUTTON_LMASK ) &&
|
||||
( getSelectionMode() == SEL_EMPTY || getSelectionMode() == SEL_IDLE ) ) {
|
||||
auto gridPos{ positionToGrid( pos ) };
|
||||
mController->selectionStart( gridPos.x, gridPos.y, SNAP_WORD );
|
||||
mSession->selectionStart( gridPos.x, gridPos.y, SNAP_WORD );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1083,13 +1083,13 @@ void TerminalDisplay::onMouseMove( const Vector2i& pos, const Uint32& flags ) {
|
||||
if ( !isCapturingMouse && ( flags & EE_BUTTON_LMASK ) &&
|
||||
( mDraggingSel || getSelectionMode() == SEL_EMPTY || getSelectionMode() == SEL_READY ) ) {
|
||||
auto gridPos{ positionToGrid( pos ) };
|
||||
mController->selectionExtend(
|
||||
mSession->selectionExtend(
|
||||
gridPos.x, gridPos.y,
|
||||
mWindow->getInput()->getModState() & KEYMOD_SHIFT ? SEL_RECTANGULAR : SEL_REGULAR,
|
||||
false );
|
||||
}
|
||||
mController->mouseReport( TerminalMouseEventType::MouseMotion, positionToGrid( pos ), flags,
|
||||
mWindow->getInput()->getModState() );
|
||||
mSession->mouseReport( TerminalMouseEventType::MouseMotion, positionToGrid( pos ), flags,
|
||||
mWindow->getInput()->getModState() );
|
||||
}
|
||||
|
||||
void TerminalDisplay::onMouseDown( const Vector2i& pos, const Uint32& flags ) {
|
||||
@@ -1103,10 +1103,10 @@ void TerminalDisplay::onMouseDown( const Vector2i& pos, const Uint32& flags ) {
|
||||
|
||||
if ( !isCapturingMouse && ( flags & EE_BUTTON_LMASK ) &&
|
||||
mLastDoubleClick.getElapsedTime() < Milliseconds( 300.f ) ) {
|
||||
mController->selectionStart( gridPos.x, gridPos.y, SNAP_LINE );
|
||||
mSession->selectionStart( gridPos.x, gridPos.y, SNAP_LINE );
|
||||
} else if ( !isCapturingMouse && ( flags & EE_BUTTON_LMASK ) ) {
|
||||
if ( !mDraggingSel ) {
|
||||
mController->selectionStart( gridPos.x, gridPos.y, 0 );
|
||||
mSession->selectionStart( gridPos.x, gridPos.y, 0 );
|
||||
mDraggingSel = true;
|
||||
invalidateLines();
|
||||
mWindow->getInput()->captureMouse( true );
|
||||
@@ -1129,8 +1129,8 @@ void TerminalDisplay::onMouseDown( const Vector2i& pos, const Uint32& flags ) {
|
||||
}
|
||||
}
|
||||
|
||||
mController->mouseReport( TerminalMouseEventType::MouseButtonDown, positionToGrid( pos ), flags,
|
||||
mWindow->getInput()->getModState() );
|
||||
mSession->mouseReport( TerminalMouseEventType::MouseButtonDown, positionToGrid( pos ), flags,
|
||||
mWindow->getInput()->getModState() );
|
||||
}
|
||||
|
||||
void TerminalDisplay::onMouseUp( const Vector2i& pos, const Uint32& flags ) {
|
||||
@@ -1176,8 +1176,8 @@ void TerminalDisplay::onMouseUp( const Vector2i& pos, const Uint32& flags ) {
|
||||
}
|
||||
}
|
||||
|
||||
mController->mouseReport( TerminalMouseEventType::MouseButtonRelease, positionToGrid( pos ),
|
||||
flags, mWindow->getInput()->getModState() );
|
||||
mSession->mouseReport( TerminalMouseEventType::MouseButtonRelease, positionToGrid( pos ), flags,
|
||||
mWindow->getInput()->getModState() );
|
||||
}
|
||||
|
||||
static inline Color termColor( unsigned int terminalColor, const std::vector<Color>& colors ) {
|
||||
@@ -1713,7 +1713,7 @@ void TerminalDisplay::drawBg( bool toFBO ) {
|
||||
}
|
||||
|
||||
void TerminalDisplay::draw( const Vector2f& pos ) {
|
||||
if ( !mController || !mSnapshot )
|
||||
if ( !mSession || !mSnapshot )
|
||||
return;
|
||||
|
||||
mDrawing = true;
|
||||
@@ -1777,9 +1777,9 @@ void TerminalDisplay::onSizeChange() {
|
||||
mFont, mFontSize,
|
||||
mSize - Vector2f( mPadding.Left + mPadding.Right, mPadding.Top + mPadding.Bottom ) ) );
|
||||
|
||||
if ( mController && ( !mSnapshot || gridSize.getWidth() != mSnapshot->columns ||
|
||||
gridSize.getHeight() != mSnapshot->rows ) ) {
|
||||
mController->resize( gridSize.getWidth(), gridSize.getHeight() );
|
||||
if ( mSession && ( !mSnapshot || gridSize.getWidth() != mSnapshot->columns ||
|
||||
gridSize.getHeight() != mSnapshot->rows ) ) {
|
||||
mSession->resize( gridSize.getWidth(), gridSize.getHeight() );
|
||||
mDirtyLines.resize( gridSize.getHeight(), 1 );
|
||||
}
|
||||
|
||||
@@ -1798,7 +1798,7 @@ void TerminalDisplay::onSizeChange() {
|
||||
void TerminalDisplay::onProcessExit( int exitCode ) {
|
||||
sendEvent( { EventType::PROCESS_EXIT, String::toString( exitCode ) } );
|
||||
|
||||
if ( !mController || mProgram.empty() || exitCode != 0 || !mKeepAlive )
|
||||
if ( !mSession || mProgram.empty() || exitCode != 0 || !mKeepAlive )
|
||||
return;
|
||||
|
||||
auto processFactory = eeNew( ProcessFactory, () );
|
||||
@@ -1824,23 +1824,23 @@ void TerminalDisplay::onProcessExit( int exitCode ) {
|
||||
return;
|
||||
}
|
||||
|
||||
mController->restart( std::move( pseudoTerminal ), std::move( process ) );
|
||||
mSession->restart( std::move( pseudoTerminal ), std::move( process ) );
|
||||
|
||||
eeSAFE_DELETE( processFactory );
|
||||
}
|
||||
|
||||
void TerminalDisplay::onTextInput( const Uint32& chr ) {
|
||||
if ( !mController )
|
||||
if ( !mSession )
|
||||
return;
|
||||
String input;
|
||||
input.push_back( chr );
|
||||
std::string utf8Input( input.toUtf8() );
|
||||
mController->write( std::move( utf8Input ) );
|
||||
mSession->write( std::move( utf8Input ) );
|
||||
mDirty = true;
|
||||
}
|
||||
|
||||
void TerminalDisplay::onTextEditing( const String&, const Int32&, const Int32& ) {
|
||||
if ( !mController )
|
||||
if ( !mSession )
|
||||
return;
|
||||
invalidateCursor();
|
||||
updateIMELocation();
|
||||
@@ -1910,7 +1910,7 @@ void TerminalDisplay::onKeyDown( const Keycode& keyCode, const Uint32& /*chr*/,
|
||||
}
|
||||
}
|
||||
|
||||
mController->write( std::string( 1, tmp ) );
|
||||
mSession->write( std::string( 1, tmp ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1929,7 +1929,7 @@ void TerminalDisplay::onKeyDown( const Keycode& keyCode, const Uint32& /*chr*/,
|
||||
continue;
|
||||
|
||||
if ( k.string.size() > 0 ) {
|
||||
mController->write( k.string );
|
||||
mSession->write( k.string );
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -1951,7 +1951,7 @@ void TerminalDisplay::onKeyDown( const Keycode& keyCode, const Uint32& /*chr*/,
|
||||
continue;
|
||||
|
||||
if ( k.string.size() > 0 ) {
|
||||
mController->write( k.string );
|
||||
mSession->write( k.string );
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -2069,8 +2069,8 @@ void TerminalDisplay::setFocus( bool focus ) {
|
||||
} else {
|
||||
mMode &= ~MODE_FOCUSED;
|
||||
}
|
||||
if ( mController )
|
||||
mController->setFocus( focus );
|
||||
if ( mSession )
|
||||
mSession->setFocus( focus );
|
||||
invalidateCursor();
|
||||
}
|
||||
|
||||
|
||||
+59
-64
@@ -1,4 +1,4 @@
|
||||
#include <eterm/terminal/terminalcontroller.hpp>
|
||||
#include <eterm/terminal/terminalsession.hpp>
|
||||
|
||||
#include <eepp/system/color.hpp>
|
||||
#include <eepp/system/log.hpp>
|
||||
@@ -10,19 +10,17 @@ using namespace EE::System;
|
||||
|
||||
namespace eterm { namespace Terminal {
|
||||
|
||||
struct TerminalController::SelectionResponse {
|
||||
struct TerminalSession::SelectionResponse {
|
||||
std::mutex mutex;
|
||||
std::condition_variable condition;
|
||||
std::string selection;
|
||||
bool ready{ false };
|
||||
};
|
||||
|
||||
class TerminalController::WorkerDisplay final : public ITerminalDisplay {
|
||||
class TerminalSession::WorkerDisplay final : public ITerminalDisplay {
|
||||
public:
|
||||
WorkerDisplay( TerminalController& controller, TerminalColorPalette palette ) :
|
||||
mController( controller ),
|
||||
mInitialPalette( std::move( palette ) ),
|
||||
mPalette( mInitialPalette ) {
|
||||
WorkerDisplay( TerminalSession& session, TerminalColorPalette palette ) :
|
||||
mSession( session ), mInitialPalette( std::move( palette ) ), mPalette( mInitialPalette ) {
|
||||
mMode |= MODE_FOCUSED;
|
||||
}
|
||||
|
||||
@@ -96,18 +94,18 @@ class TerminalController::WorkerDisplay final : public ITerminalDisplay {
|
||||
mLastHistoryLength = snapshot->historyLength;
|
||||
Event event{ EventType::HistoryLength };
|
||||
event.value = mLastHistoryLength;
|
||||
mController.enqueueEvent( std::move( event ), true );
|
||||
mSession.enqueueEvent( std::move( event ), true );
|
||||
}
|
||||
mController.publishSnapshot( std::move( snapshot ) );
|
||||
mSession.publishSnapshot( std::move( snapshot ) );
|
||||
}
|
||||
|
||||
void bell() { mController.enqueueEvent( { EventType::Bell }, false ); }
|
||||
void bell() { mSession.enqueueEvent( { EventType::Bell }, false ); }
|
||||
|
||||
void resetColors() {
|
||||
mPalette = mInitialPalette;
|
||||
Event event{ EventType::Color };
|
||||
event.value = -1;
|
||||
mController.enqueueEvent( std::move( event ), false );
|
||||
mSession.enqueueEvent( std::move( event ), false );
|
||||
}
|
||||
|
||||
int resetColor( const Uint32& index, const char* name ) {
|
||||
@@ -149,7 +147,7 @@ class TerminalController::WorkerDisplay final : public ITerminalDisplay {
|
||||
Event event{ EventType::Color };
|
||||
event.data = name ? name : "";
|
||||
event.value = static_cast<int>( index );
|
||||
mController.enqueueEvent( std::move( event ), false );
|
||||
mSession.enqueueEvent( std::move( event ), false );
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -174,27 +172,25 @@ class TerminalController::WorkerDisplay final : public ITerminalDisplay {
|
||||
|
||||
void setTitle( const char* title ) {
|
||||
mTitle = title ? title : "";
|
||||
mController.enqueueEvent( { EventType::Title, mTitle }, true );
|
||||
mSession.enqueueEvent( { EventType::Title, mTitle }, true );
|
||||
}
|
||||
|
||||
void setIconTitle( const char* title ) {
|
||||
mController.enqueueEvent( { EventType::IconTitle, title ? title : "" }, true );
|
||||
mSession.enqueueEvent( { EventType::IconTitle, title ? title : "" }, true );
|
||||
}
|
||||
|
||||
void setClipboard( const char* text ) {
|
||||
if ( text )
|
||||
mController.enqueueEvent( { EventType::Clipboard, text }, false );
|
||||
mSession.enqueueEvent( { EventType::Clipboard, text }, false );
|
||||
}
|
||||
|
||||
void onProcessExit( int exitCode ) {
|
||||
Event event{ EventType::ProcessExit };
|
||||
event.value = exitCode;
|
||||
mController.enqueueEvent( std::move( event ), false );
|
||||
mSession.enqueueEvent( std::move( event ), false );
|
||||
}
|
||||
|
||||
void onScrollPositionChange() {
|
||||
mController.enqueueEvent( { EventType::ScrollPosition }, true );
|
||||
}
|
||||
void onScrollPositionChange() { mSession.enqueueEvent( { EventType::ScrollPosition }, true ); }
|
||||
|
||||
void setPalette( TerminalColorPalette palette ) {
|
||||
mInitialPalette = palette;
|
||||
@@ -224,7 +220,7 @@ class TerminalController::WorkerDisplay final : public ITerminalDisplay {
|
||||
mPalette.background = color;
|
||||
}
|
||||
|
||||
TerminalController& mController;
|
||||
TerminalSession& mSession;
|
||||
TerminalColorPalette mInitialPalette;
|
||||
TerminalColorPalette mPalette;
|
||||
std::vector<TerminalGlyph> mCells;
|
||||
@@ -241,35 +237,35 @@ class TerminalController::WorkerDisplay final : public ITerminalDisplay {
|
||||
bool mCursorVisible{ false };
|
||||
};
|
||||
|
||||
std::shared_ptr<TerminalController> TerminalController::create( PtyPtr&& pty, ProcPtr&& process,
|
||||
size_t historySize,
|
||||
TerminalColorPalette palette ) {
|
||||
std::shared_ptr<TerminalSession> TerminalSession::create( PtyPtr&& pty, ProcPtr&& process,
|
||||
size_t historySize,
|
||||
TerminalColorPalette palette ) {
|
||||
if ( !pty || !process )
|
||||
return nullptr;
|
||||
auto controller = std::shared_ptr<TerminalController>( new TerminalController(
|
||||
auto session = std::shared_ptr<TerminalSession>( new TerminalSession(
|
||||
std::move( pty ), std::move( process ), historySize, std::move( palette ) ) );
|
||||
controller->start();
|
||||
return controller;
|
||||
session->start();
|
||||
return session;
|
||||
}
|
||||
|
||||
TerminalController::TerminalController( PtyPtr&& pty, ProcPtr&& process, size_t historySize,
|
||||
TerminalColorPalette palette ) {
|
||||
TerminalSession::TerminalSession( PtyPtr&& pty, ProcPtr&& process, size_t historySize,
|
||||
TerminalColorPalette palette ) {
|
||||
mWorkerDisplay = std::make_shared<WorkerDisplay>( *this, std::move( palette ) );
|
||||
mEmulator = TerminalEmulator::create( std::move( pty ), std::move( process ), mWorkerDisplay,
|
||||
historySize );
|
||||
// Establish a complete generation before the controller becomes concurrently visible.
|
||||
// Establish a complete generation before the session becomes concurrently visible.
|
||||
mEmulator->redraw();
|
||||
}
|
||||
|
||||
TerminalController::~TerminalController() {
|
||||
TerminalSession::~TerminalSession() {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
void TerminalController::start() {
|
||||
void TerminalSession::start() {
|
||||
mWorker = std::thread( [this] { workerLoop(); } );
|
||||
}
|
||||
|
||||
void TerminalController::shutdown() {
|
||||
void TerminalSession::shutdown() {
|
||||
std::lock_guard<std::mutex> shutdownLock( mShutdownMutex );
|
||||
if ( !mShutdownRequested.exchange( true, std::memory_order_acq_rel ) )
|
||||
mCommandCondition.notify_all();
|
||||
@@ -277,7 +273,7 @@ void TerminalController::shutdown() {
|
||||
mWorker.join();
|
||||
}
|
||||
|
||||
bool TerminalController::enqueue( Command&& command ) {
|
||||
bool TerminalSession::enqueue( Command&& command ) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( mCommandMutex );
|
||||
|
||||
@@ -291,27 +287,27 @@ bool TerminalController::enqueue( Command&& command ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void TerminalController::write( std::string data, bool mayEcho ) {
|
||||
void TerminalSession::write( std::string data, bool mayEcho ) {
|
||||
enqueue( WriteCommand{ std::move( data ), mayEcho } );
|
||||
}
|
||||
|
||||
void TerminalController::writeRaw( std::string data ) {
|
||||
void TerminalSession::writeRaw( std::string data ) {
|
||||
enqueue( WriteRawCommand{ std::move( data ) } );
|
||||
}
|
||||
|
||||
void TerminalController::resize( int columns, int rows ) {
|
||||
void TerminalSession::resize( int columns, int rows ) {
|
||||
enqueue( ResizeCommand{ columns, rows } );
|
||||
}
|
||||
|
||||
void TerminalController::scrollUp( int amount ) {
|
||||
void TerminalSession::scrollUp( int amount ) {
|
||||
enqueue( ScrollCommand{ amount, -1 } );
|
||||
}
|
||||
|
||||
void TerminalController::scrollDown( int amount ) {
|
||||
void TerminalSession::scrollDown( int amount ) {
|
||||
enqueue( ScrollCommand{ amount, 1 } );
|
||||
}
|
||||
|
||||
Uint64 TerminalController::scrollTo( int position ) {
|
||||
Uint64 TerminalSession::scrollTo( int position ) {
|
||||
const Uint64 commandId = mNextScrollCommand.fetch_add( 1, std::memory_order_relaxed ) + 1;
|
||||
|
||||
if ( !enqueue( ScrollCommand{ position, 0, commandId } ) )
|
||||
@@ -320,60 +316,60 @@ Uint64 TerminalController::scrollTo( int position ) {
|
||||
return commandId;
|
||||
}
|
||||
|
||||
void TerminalController::selectionStart( int column, int row, int snap ) {
|
||||
void TerminalSession::selectionStart( int column, int row, int snap ) {
|
||||
enqueue( SelectionStartCommand{ column, row, snap } );
|
||||
}
|
||||
|
||||
void TerminalController::selectionExtend( int column, int row, int type, bool done ) {
|
||||
void TerminalSession::selectionExtend( int column, int row, int type, bool done ) {
|
||||
enqueue( SelectionExtendCommand{ column, row, type, done } );
|
||||
}
|
||||
|
||||
void TerminalController::selectionClear() {
|
||||
void TerminalSession::selectionClear() {
|
||||
enqueue( SelectionClearCommand{} );
|
||||
}
|
||||
|
||||
void TerminalController::mouseReport( TerminalMouseEventType type, Vector2i position, Uint32 flags,
|
||||
Uint32 modifiers ) {
|
||||
void TerminalSession::mouseReport( TerminalMouseEventType type, Vector2i position, Uint32 flags,
|
||||
Uint32 modifiers ) {
|
||||
enqueue( MouseCommand{ type, position, flags, modifiers } );
|
||||
}
|
||||
|
||||
void TerminalController::setFocus( bool focus ) {
|
||||
void TerminalSession::setFocus( bool focus ) {
|
||||
enqueue( FocusCommand{ { focus } } );
|
||||
}
|
||||
|
||||
void TerminalController::setCursorMode( TerminalCursorMode mode ) {
|
||||
void TerminalSession::setCursorMode( TerminalCursorMode mode ) {
|
||||
enqueue( CursorModeCommand{ mode } );
|
||||
}
|
||||
|
||||
void TerminalController::setColorPalette( TerminalColorPalette palette ) {
|
||||
void TerminalSession::setColorPalette( TerminalColorPalette palette ) {
|
||||
enqueue( PaletteCommand{ std::move( palette ) } );
|
||||
}
|
||||
|
||||
void TerminalController::setAllowMemoryTrimming( bool allow ) {
|
||||
void TerminalSession::setAllowMemoryTrimming( bool allow ) {
|
||||
enqueue( AllowTrimCommand{ { allow } } );
|
||||
}
|
||||
|
||||
void TerminalController::setPresentationRate( Uint32 framesPerSecond ) {
|
||||
void TerminalSession::setPresentationRate( Uint32 framesPerSecond ) {
|
||||
enqueue( PresentationRateCommand{ framesPerSecond } );
|
||||
}
|
||||
|
||||
void TerminalController::setDataEventsEnabled( bool enabled ) {
|
||||
void TerminalSession::setDataEventsEnabled( bool enabled ) {
|
||||
enqueue( DataEventsCommand{ { enabled } } );
|
||||
}
|
||||
|
||||
void TerminalController::setPromptEventsEnabled( bool enabled ) {
|
||||
void TerminalSession::setPromptEventsEnabled( bool enabled ) {
|
||||
enqueue( PromptEventsCommand{ { enabled } } );
|
||||
}
|
||||
|
||||
void TerminalController::reset() {
|
||||
void TerminalSession::reset() {
|
||||
enqueue( ResetCommand{} );
|
||||
}
|
||||
|
||||
void TerminalController::terminate() {
|
||||
void TerminalSession::terminate() {
|
||||
enqueue( TerminateCommand{} );
|
||||
}
|
||||
|
||||
void TerminalController::restart( PtyPtr&& pty, ProcPtr&& process ) {
|
||||
void TerminalSession::restart( PtyPtr&& pty, ProcPtr&& process ) {
|
||||
if ( !pty || !process ) {
|
||||
enqueueEvent( { EventType::RestartFailure, "Invalid PTY or process" }, false );
|
||||
return;
|
||||
@@ -381,13 +377,12 @@ void TerminalController::restart( PtyPtr&& pty, ProcPtr&& process ) {
|
||||
enqueue( RestartCommand{ std::move( pty ), std::move( process ) } );
|
||||
}
|
||||
|
||||
std::shared_ptr<const TerminalSnapshot> TerminalController::snapshot() const {
|
||||
std::shared_ptr<const TerminalSnapshot> TerminalSession::snapshot() const {
|
||||
std::lock_guard<std::mutex> lock( mPublishedSnapshotMutex );
|
||||
return mPublishedSnapshot;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
TerminalController::requestSelection( std::chrono::milliseconds timeout ) {
|
||||
std::optional<std::string> TerminalSession::requestSelection( std::chrono::milliseconds timeout ) {
|
||||
if ( mShutdownRequested.load( std::memory_order_acquire ) )
|
||||
return std::nullopt;
|
||||
auto response = std::make_shared<SelectionResponse>();
|
||||
@@ -398,7 +393,7 @@ TerminalController::requestSelection( std::chrono::milliseconds timeout ) {
|
||||
return std::move( response->selection );
|
||||
}
|
||||
|
||||
std::vector<TerminalController::Event> TerminalController::drainEvents() {
|
||||
std::vector<TerminalSession::Event> TerminalSession::drainEvents() {
|
||||
std::vector<Event> events;
|
||||
std::lock_guard<std::mutex> lock( mEventMutex );
|
||||
events.reserve( mEvents.size() );
|
||||
@@ -409,7 +404,7 @@ std::vector<TerminalController::Event> TerminalController::drainEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
void TerminalController::enqueueEvent( Event event, bool coalescable ) {
|
||||
void TerminalSession::enqueueEvent( Event event, bool coalescable ) {
|
||||
std::lock_guard<std::mutex> lock( mEventMutex );
|
||||
if ( coalescable ) {
|
||||
for ( auto it = mEvents.rbegin(); it != mEvents.rend(); ++it ) {
|
||||
@@ -428,7 +423,7 @@ void TerminalController::enqueueEvent( Event event, bool coalescable ) {
|
||||
mEvents.emplace_back( std::move( event ) );
|
||||
}
|
||||
|
||||
void TerminalController::publishSnapshot( std::shared_ptr<const TerminalSnapshot> snapshot ) {
|
||||
void TerminalSession::publishSnapshot( std::shared_ptr<const TerminalSnapshot> snapshot ) {
|
||||
const Uint64 generation = snapshot->generation;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( mPublishedSnapshotMutex );
|
||||
@@ -439,7 +434,7 @@ void TerminalController::publishSnapshot( std::shared_ptr<const TerminalSnapshot
|
||||
enqueueEvent( std::move( event ), true );
|
||||
}
|
||||
|
||||
void TerminalController::workerLoop() {
|
||||
void TerminalSession::workerLoop() {
|
||||
while ( !mShutdownRequested.load( std::memory_order_acquire ) ) {
|
||||
processCommands();
|
||||
if ( mShutdownRequested.load( std::memory_order_acquire ) )
|
||||
@@ -458,7 +453,7 @@ void TerminalController::workerLoop() {
|
||||
mWorkerDisplay.reset();
|
||||
}
|
||||
|
||||
void TerminalController::processCommands() {
|
||||
void TerminalSession::processCommands() {
|
||||
std::deque<Command> commands;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock( mCommandMutex );
|
||||
@@ -470,7 +465,7 @@ void TerminalController::processCommands() {
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalController::processCommand( Command&& command ) {
|
||||
void TerminalSession::processCommand( Command&& command ) {
|
||||
std::visit(
|
||||
[this]( auto&& value ) {
|
||||
using T = std::decay_t<decltype( value )>;
|
||||
@@ -559,4 +554,4 @@ void TerminalController::processCommand( Command&& command ) {
|
||||
std::move( command ) );
|
||||
}
|
||||
|
||||
}} // namespace eterm::Terminal
|
||||
}} // namespace eterm::Terminal
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <eterm/system/iprocess.hpp>
|
||||
#include <eterm/terminal/ipseudoterminal.hpp>
|
||||
#include <eterm/terminal/iterminaldisplay.hpp>
|
||||
#include <eterm/terminal/terminalcontroller.hpp>
|
||||
#include <eterm/terminal/terminalemulator.hpp>
|
||||
#include <eterm/terminal/terminalsession.hpp>
|
||||
#include <limits>
|
||||
#include <thread>
|
||||
|
||||
@@ -59,12 +59,12 @@ class MockProcess : public IProcess {
|
||||
};
|
||||
|
||||
static std::shared_ptr<const TerminalSnapshot>
|
||||
waitForSnapshot( const std::shared_ptr<TerminalController>& controller,
|
||||
waitForSnapshot( const std::shared_ptr<TerminalSession>& session,
|
||||
const std::function<bool( const TerminalSnapshot& )>& predicate,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds( 1000 ) ) {
|
||||
const auto deadline = std::chrono::steady_clock::now() + timeout;
|
||||
while ( std::chrono::steady_clock::now() < deadline ) {
|
||||
auto snapshot = controller->snapshot();
|
||||
auto snapshot = session->snapshot();
|
||||
if ( snapshot && predicate( *snapshot ) )
|
||||
return snapshot;
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) );
|
||||
@@ -72,60 +72,59 @@ waitForSnapshot( const std::shared_ptr<TerminalController>& controller,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, command_wakeup_and_snapshot_immutability ) {
|
||||
UTEST( eterm_session, command_wakeup_and_snapshot_immutability ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
auto controller = TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
ASSERT_TRUE( controller != nullptr );
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
ASSERT_TRUE( session != nullptr );
|
||||
|
||||
controller->writeRaw( "ABC" );
|
||||
auto first = waitForSnapshot( controller, []( const TerminalSnapshot& snapshot ) {
|
||||
session->writeRaw( "ABC" );
|
||||
auto first = waitForSnapshot( session, []( const TerminalSnapshot& snapshot ) {
|
||||
return snapshot.cells.size() >= 3 && snapshot.cells[0].u == 'A' &&
|
||||
snapshot.cells[1].u == 'B' && snapshot.cells[2].u == 'C';
|
||||
} );
|
||||
ASSERT_TRUE( first != nullptr );
|
||||
const Uint64 firstGeneration = first->generation;
|
||||
|
||||
controller->writeRaw( "\rXYZ" );
|
||||
auto second =
|
||||
waitForSnapshot( controller, [firstGeneration]( const TerminalSnapshot& snapshot ) {
|
||||
return snapshot.generation > firstGeneration && snapshot.cells[0].u == 'X';
|
||||
} );
|
||||
session->writeRaw( "\rXYZ" );
|
||||
auto second = waitForSnapshot( session, [firstGeneration]( const TerminalSnapshot& snapshot ) {
|
||||
return snapshot.generation > firstGeneration && snapshot.cells[0].u == 'X';
|
||||
} );
|
||||
ASSERT_TRUE( second != nullptr );
|
||||
EXPECT_EQ( static_cast<Rune>( 'A' ), first->cells[0].u );
|
||||
EXPECT_TRUE( second->generation > first->generation );
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, skipped_snapshot_generation_requires_full_redraw ) {
|
||||
UTEST( eterm_session, skipped_snapshot_generation_requires_full_redraw ) {
|
||||
TerminalSnapshot snapshot;
|
||||
snapshot.generation = 42;
|
||||
EXPECT_TRUE( snapshot.dirtyRowsFollow( 41 ) );
|
||||
EXPECT_FALSE( snapshot.dirtyRowsFollow( 40 ) );
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, ordered_selection_request ) {
|
||||
UTEST( eterm_session, ordered_selection_request ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
pty->mBuffer = "ordered selection";
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
auto controller = TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
ASSERT_TRUE( waitForSnapshot( controller, []( const TerminalSnapshot& snapshot ) {
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
ASSERT_TRUE( waitForSnapshot( session, []( const TerminalSnapshot& snapshot ) {
|
||||
return !snapshot.cells.empty() && snapshot.cells[0].u == 'o';
|
||||
} ) != nullptr );
|
||||
|
||||
controller->selectionStart( 0, 0, 0 );
|
||||
controller->selectionExtend( 6, 0, SEL_REGULAR, false );
|
||||
auto selection = controller->requestSelection();
|
||||
session->selectionStart( 0, 0, 0 );
|
||||
session->selectionExtend( 6, 0, SEL_REGULAR, false );
|
||||
auto selection = session->requestSelection();
|
||||
ASSERT_TRUE( selection.has_value() );
|
||||
EXPECT_STDSTREQ( "ordered", *selection );
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, loaded_command_latency_stays_bounded ) {
|
||||
UTEST( eterm_session, loaded_command_latency_stays_bounded ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
pty->mBuffer.assign( 32 * 1024 * 1024, 'L' );
|
||||
pty->mMaxRead = 64;
|
||||
MockPty* ptyPtr = pty.get();
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
auto controller = TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
const auto readDeadline = std::chrono::steady_clock::now() + std::chrono::milliseconds( 100 );
|
||||
while ( ptyPtr->mBytesRead.load( std::memory_order_relaxed ) == 0 &&
|
||||
std::chrono::steady_clock::now() < readDeadline )
|
||||
@@ -133,19 +132,19 @@ UTEST( eterm_controller, loaded_command_latency_stays_bounded ) {
|
||||
ASSERT_TRUE( ptyPtr->mBytesRead.load( std::memory_order_relaxed ) > 0 );
|
||||
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
auto selection = controller->requestSelection();
|
||||
auto selection = session->requestSelection();
|
||||
const auto latency = std::chrono::steady_clock::now() - start;
|
||||
EXPECT_TRUE( selection.has_value() );
|
||||
EXPECT_TRUE( latency < std::chrono::milliseconds( 50 ) );
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, resize_and_output_are_serialized ) {
|
||||
UTEST( eterm_session, resize_and_output_are_serialized ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
auto controller = TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
controller->resize( 40, 12 );
|
||||
controller->writeRaw( "after resize" );
|
||||
auto snapshot = waitForSnapshot( controller, []( const TerminalSnapshot& value ) {
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
session->resize( 40, 12 );
|
||||
session->writeRaw( "after resize" );
|
||||
auto snapshot = waitForSnapshot( session, []( const TerminalSnapshot& value ) {
|
||||
return value.columns == 40 && value.rows == 12 && !value.cells.empty() &&
|
||||
value.cells[0].u == 'a';
|
||||
} );
|
||||
@@ -153,59 +152,59 @@ UTEST( eterm_controller, resize_and_output_are_serialized ) {
|
||||
EXPECT_EQ( static_cast<size_t>( 40 * 12 ), snapshot->cells.size() );
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, scroll_snapshots_acknowledge_the_latest_ordered_command ) {
|
||||
UTEST( eterm_session, scroll_snapshots_acknowledge_the_latest_ordered_command ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
for ( int line = 0; line < 80; ++line )
|
||||
pty->mBuffer += "history " + std::to_string( line ) + "\r\n";
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
auto controller = TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
ASSERT_TRUE( waitForSnapshot( controller, []( const TerminalSnapshot& snapshot ) {
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
ASSERT_TRUE( waitForSnapshot( session, []( const TerminalSnapshot& snapshot ) {
|
||||
return snapshot.historyLength >= 25;
|
||||
} ) != nullptr );
|
||||
|
||||
const Uint64 firstCommand = controller->scrollTo( 10 );
|
||||
const Uint64 secondCommand = controller->scrollTo( 25 );
|
||||
const Uint64 firstCommand = session->scrollTo( 10 );
|
||||
const Uint64 secondCommand = session->scrollTo( 25 );
|
||||
EXPECT_EQ( firstCommand + 1, secondCommand );
|
||||
auto acknowledged =
|
||||
waitForSnapshot( controller, [secondCommand]( const TerminalSnapshot& snapshot ) {
|
||||
waitForSnapshot( session, [secondCommand]( const TerminalSnapshot& snapshot ) {
|
||||
return snapshot.lastAppliedScrollCommand == secondCommand;
|
||||
} );
|
||||
ASSERT_TRUE( acknowledged != nullptr );
|
||||
EXPECT_EQ( 25, acknowledged->scrollPosition );
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, presentation_rate_is_applied_on_the_worker ) {
|
||||
UTEST( eterm_session, presentation_rate_is_applied_on_the_worker ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
auto controller = TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
controller->setPresentationRate( 120 );
|
||||
ASSERT_TRUE( waitForSnapshot( controller, []( const TerminalSnapshot& snapshot ) {
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
session->setPresentationRate( 120 );
|
||||
ASSERT_TRUE( waitForSnapshot( session, []( const TerminalSnapshot& snapshot ) {
|
||||
return snapshot.presentationRate == 120;
|
||||
} ) != nullptr );
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, focus_reporting_is_ordered_on_worker ) {
|
||||
UTEST( eterm_session, focus_reporting_is_ordered_on_worker ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
pty->mBuffer = "\033[?1004h";
|
||||
pty->mLoopWrites = false;
|
||||
MockPty* ptyPtr = pty.get();
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
auto controller = TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
auto enabled = waitForSnapshot( controller, []( const TerminalSnapshot& snapshot ) {
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
auto enabled = waitForSnapshot( session, []( const TerminalSnapshot& snapshot ) {
|
||||
return snapshot.windowMode & MODE_FOCUS;
|
||||
} );
|
||||
ASSERT_TRUE( enabled != nullptr );
|
||||
|
||||
controller->setFocus( false );
|
||||
auto unfocused = waitForSnapshot( controller, [enabled]( const TerminalSnapshot& snapshot ) {
|
||||
session->setFocus( false );
|
||||
auto unfocused = waitForSnapshot( session, [enabled]( const TerminalSnapshot& snapshot ) {
|
||||
return snapshot.generation > enabled->generation && !( snapshot.windowMode & MODE_FOCUSED );
|
||||
} );
|
||||
ASSERT_TRUE( unfocused != nullptr );
|
||||
ASSERT_TRUE( ptyPtr->mWrites.size() >= 3 );
|
||||
EXPECT_STDSTREQ( "\033[O", ptyPtr->mWrites.substr( ptyPtr->mWrites.size() - 3 ) );
|
||||
|
||||
controller->setFocus( true );
|
||||
ASSERT_TRUE( waitForSnapshot( controller, [unfocused]( const TerminalSnapshot& snapshot ) {
|
||||
session->setFocus( true );
|
||||
ASSERT_TRUE( waitForSnapshot( session, [unfocused]( const TerminalSnapshot& snapshot ) {
|
||||
return snapshot.generation > unfocused->generation &&
|
||||
snapshot.windowMode & MODE_FOCUSED;
|
||||
} ) != nullptr );
|
||||
@@ -213,20 +212,20 @@ UTEST( eterm_controller, focus_reporting_is_ordered_on_worker ) {
|
||||
EXPECT_STDSTREQ( "\033[I", ptyPtr->mWrites.substr( ptyPtr->mWrites.size() - 3 ) );
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, replaceable_events_coalesce_without_losing_ordered_events ) {
|
||||
UTEST( eterm_session, replaceable_events_coalesce_without_losing_ordered_events ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
auto controller = TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
controller->drainEvents();
|
||||
controller->writeRaw( "\033]0;first\a\033]0;second\a" );
|
||||
ASSERT_TRUE( waitForSnapshot( controller, []( const TerminalSnapshot& snapshot ) {
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
session->drainEvents();
|
||||
session->writeRaw( "\033]0;first\a\033]0;second\a" );
|
||||
ASSERT_TRUE( waitForSnapshot( session, []( const TerminalSnapshot& snapshot ) {
|
||||
return snapshot.title == "second";
|
||||
} ) != nullptr );
|
||||
|
||||
int titleEvents = 0;
|
||||
std::string title;
|
||||
for ( auto& event : controller->drainEvents() ) {
|
||||
if ( event.type == TerminalController::EventType::Title ) {
|
||||
for ( auto& event : session->drainEvents() ) {
|
||||
if ( event.type == TerminalSession::EventType::Title ) {
|
||||
++titleEvents;
|
||||
title = std::move( event.data );
|
||||
}
|
||||
@@ -235,54 +234,54 @@ UTEST( eterm_controller, replaceable_events_coalesce_without_losing_ordered_even
|
||||
EXPECT_STDSTREQ( "second", title );
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, ordered_events_are_coalescing_barriers ) {
|
||||
UTEST( eterm_session, ordered_events_are_coalescing_barriers ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
auto controller = TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
controller->drainEvents();
|
||||
controller->writeRaw( "\033]0;before\a\a\033]0;after\a" );
|
||||
ASSERT_TRUE( waitForSnapshot( controller, []( const TerminalSnapshot& snapshot ) {
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
session->drainEvents();
|
||||
session->writeRaw( "\033]0;before\a\a\033]0;after\a" );
|
||||
ASSERT_TRUE( waitForSnapshot( session, []( const TerminalSnapshot& snapshot ) {
|
||||
return snapshot.title == "after";
|
||||
} ) != nullptr );
|
||||
|
||||
std::vector<TerminalController::EventType> semanticEvents;
|
||||
for ( const auto& event : controller->drainEvents() ) {
|
||||
if ( event.type == TerminalController::EventType::Title ||
|
||||
event.type == TerminalController::EventType::Bell )
|
||||
std::vector<TerminalSession::EventType> semanticEvents;
|
||||
for ( const auto& event : session->drainEvents() ) {
|
||||
if ( event.type == TerminalSession::EventType::Title ||
|
||||
event.type == TerminalSession::EventType::Bell )
|
||||
semanticEvents.emplace_back( event.type );
|
||||
}
|
||||
ASSERT_EQ( static_cast<size_t>( 3 ), semanticEvents.size() );
|
||||
EXPECT_EQ( TerminalController::EventType::Title, semanticEvents[0] );
|
||||
EXPECT_EQ( TerminalController::EventType::Bell, semanticEvents[1] );
|
||||
EXPECT_EQ( TerminalController::EventType::Title, semanticEvents[2] );
|
||||
EXPECT_EQ( TerminalSession::EventType::Title, semanticEvents[0] );
|
||||
EXPECT_EQ( TerminalSession::EventType::Bell, semanticEvents[1] );
|
||||
EXPECT_EQ( TerminalSession::EventType::Title, semanticEvents[2] );
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, reset_is_ordered_and_publishes_immediately ) {
|
||||
UTEST( eterm_session, reset_is_ordered_and_publishes_immediately ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
pty->mBuffer = "content";
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
auto controller = TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
auto populated = waitForSnapshot( controller, []( const TerminalSnapshot& snapshot ) {
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
auto populated = waitForSnapshot( session, []( const TerminalSnapshot& snapshot ) {
|
||||
return !snapshot.cells.empty() && snapshot.cells[0].u == 'c';
|
||||
} );
|
||||
ASSERT_TRUE( populated != nullptr );
|
||||
controller->reset();
|
||||
auto reset = waitForSnapshot( controller, [populated]( const TerminalSnapshot& snapshot ) {
|
||||
session->reset();
|
||||
auto reset = waitForSnapshot( session, [populated]( const TerminalSnapshot& snapshot ) {
|
||||
return snapshot.generation > populated->generation && !snapshot.cells.empty() &&
|
||||
snapshot.cells[0].u == ' ';
|
||||
} );
|
||||
ASSERT_TRUE( reset != nullptr );
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, process_exit_follows_buffered_output_and_final_snapshot ) {
|
||||
UTEST( eterm_session, process_exit_follows_buffered_output_and_final_snapshot ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
pty->mMaxRead = 1;
|
||||
MockPty* ptyPtr = pty.get();
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
MockProcess* processPtr = process.get();
|
||||
auto controller = TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
controller->setDataEventsEnabled( true );
|
||||
controller->writeRaw( std::string( 3 * 1024, 'Q' ) );
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
session->setDataEventsEnabled( true );
|
||||
session->writeRaw( std::string( 3 * 1024, 'Q' ) );
|
||||
const auto readDeadline = std::chrono::steady_clock::now() + std::chrono::milliseconds( 100 );
|
||||
while ( ptyPtr->mBytesRead.load( std::memory_order_relaxed ) == 0 &&
|
||||
std::chrono::steady_clock::now() < readDeadline )
|
||||
@@ -291,51 +290,50 @@ UTEST( eterm_controller, process_exit_follows_buffered_output_and_final_snapshot
|
||||
processPtr->mExited.store( true );
|
||||
|
||||
auto finalSnapshot = waitForSnapshot(
|
||||
controller, []( const TerminalSnapshot& snapshot ) { return snapshot.processExited; } );
|
||||
session, []( const TerminalSnapshot& snapshot ) { return snapshot.processExited; } );
|
||||
ASSERT_TRUE( finalSnapshot != nullptr );
|
||||
EXPECT_EQ( 0, finalSnapshot->exitCode );
|
||||
|
||||
size_t bytesRead = 0;
|
||||
bool sawExit = false;
|
||||
for ( auto& event : controller->drainEvents() ) {
|
||||
if ( event.type == TerminalController::EventType::Data )
|
||||
for ( auto& event : session->drainEvents() ) {
|
||||
if ( event.type == TerminalSession::EventType::Data )
|
||||
bytesRead += event.data.size();
|
||||
else if ( event.type == TerminalController::EventType::ProcessExit )
|
||||
else if ( event.type == TerminalSession::EventType::ProcessExit )
|
||||
sawExit = true;
|
||||
}
|
||||
EXPECT_EQ( static_cast<size_t>( 3 * 1024 ), bytesRead );
|
||||
EXPECT_TRUE( sawExit );
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, repeated_create_destroy_and_concurrent_workers ) {
|
||||
UTEST( eterm_session, repeated_create_destroy_and_concurrent_workers ) {
|
||||
for ( int iteration = 0; iteration < 16; ++iteration ) {
|
||||
std::vector<std::shared_ptr<TerminalController>> controllers;
|
||||
std::vector<std::shared_ptr<TerminalSession>> sessions;
|
||||
for ( int terminal = 0; terminal < 4; ++terminal ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
auto controller =
|
||||
TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
controller->writeRaw( "worker" + std::to_string( terminal ) );
|
||||
controllers.emplace_back( std::move( controller ) );
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
session->writeRaw( "worker" + std::to_string( terminal ) );
|
||||
sessions.emplace_back( std::move( session ) );
|
||||
}
|
||||
for ( const auto& controller : controllers ) {
|
||||
EXPECT_TRUE( waitForSnapshot( controller, []( const TerminalSnapshot& snapshot ) {
|
||||
for ( const auto& session : sessions ) {
|
||||
EXPECT_TRUE( waitForSnapshot( session, []( const TerminalSnapshot& snapshot ) {
|
||||
return !snapshot.cells.empty() && snapshot.cells[0].u == 'w';
|
||||
} ) != nullptr );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UTEST( eterm_controller, concurrent_shutdown_is_idempotent ) {
|
||||
UTEST( eterm_session, concurrent_shutdown_is_idempotent ) {
|
||||
auto pty = std::make_unique<MockPty>();
|
||||
auto process = std::make_unique<MockProcess>();
|
||||
auto controller = TerminalController::create( std::move( pty ), std::move( process ), 100 );
|
||||
auto session = TerminalSession::create( std::move( pty ), std::move( process ), 100 );
|
||||
std::vector<std::thread> shutdownThreads;
|
||||
for ( int thread = 0; thread < 4; ++thread )
|
||||
shutdownThreads.emplace_back( [controller] { controller->shutdown(); } );
|
||||
shutdownThreads.emplace_back( [session] { session->shutdown(); } );
|
||||
for ( auto& thread : shutdownThreads )
|
||||
thread.join();
|
||||
controller->shutdown();
|
||||
session->shutdown();
|
||||
}
|
||||
|
||||
class MockDisplay : public ITerminalDisplay {
|
||||
|
||||
@@ -145,8 +145,8 @@ void queueExitedTabs() {
|
||||
auto* terminal = terminalFromTab( tab );
|
||||
if ( !terminal || !terminal->getTerm() )
|
||||
return;
|
||||
const auto& controller = terminal->getTerm()->getController();
|
||||
auto snapshot = controller ? controller->snapshot() : nullptr;
|
||||
const auto& session = terminal->getTerm()->getSession();
|
||||
auto snapshot = session ? session->snapshot() : nullptr;
|
||||
if ( snapshot && snapshot->processExited )
|
||||
queueExitCloseTab( tab );
|
||||
} );
|
||||
|
||||
Reference in New Issue
Block a user