2022-05-18 23:12:52 +00:00
/***
Copyright ( C ) 2022 J Reece Wilson ( a / k / a " Reece " ) . All rights reserved .
File : ConsoleTTY . cpp
Date : 2022 - 5 - 11
Author : Reece
* * */
2022-06-12 13:53:35 +00:00
# define I_REALLY_NEED_WIDECHAR_PUBAPI // bc linux
2022-05-18 23:12:52 +00:00
# include <Source/RuntimeInternal.hpp>
# include <Source/Console/Console.hpp>
# include "ConsoleTTY.hpp"
# include <Source/Console/ConsoleStd/ConsoleStd.hpp>
# if defined(AURORA_IS_MODERNNT_DERIVED)
# include "ConsoleTTY.NT.hpp"
# endif
# if defined(AURORA_IS_POSIX_DERIVED)
# include "ConsoleTTY.Unix.hpp"
# endif
2023-08-27 11:41:51 +00:00
# if defined(AURORA_COMPILER_CLANG)
// warning: enumeration values 'kEnumCount' and 'kEnumInvalid' not handled in switch [-Wswitch
# pragma clang diagnostic ignored "-Wswitch"
// Yea, I don't give a shit.
# endif
2022-12-14 01:35:18 +00:00
# include "../ColorConvert.hpp"
2022-05-18 23:12:52 +00:00
namespace Aurora : : Console : : ConsoleTTY
{
2022-11-28 16:01:08 +00:00
static AuThreads : : ThreadUnique_t gConsoleTTYThread ;
static bool gMultiThreadTTY { true } ;
static bool gBuggyFastAppend { false } ;
2022-05-18 23:12:52 +00:00
# if 1
2023-02-17 19:42:30 +00:00
AuUInt32 GuessWidth ( const AuString & referenceLine )
{
return AuUInt32 ( AuLocale : : ConvertFromUTF8 ( referenceLine ) . size ( ) ) ;
}
TTYConsoleField : : TTYConsoleField ( TTYConsole * pParent ) :
pParent ( pParent )
{
}
void TTYConsoleField : : AddString ( const AuString & input )
{
2023-09-28 19:38:36 +00:00
if ( this - > highlightStartInBytes )
{
this - > Backspace ( ) ;
}
2023-02-17 19:42:30 +00:00
if ( this - > noncanonicalCursorPosInBytes = = this - > inputField . size ( ) )
{
this - > inputField + = input ;
}
else
{
auto itr = this - > inputField . begin ( ) ;
std : : advance ( itr , this - > noncanonicalCursorPosInBytes ) ;
this - > inputField . insert ( itr , input . begin ( ) , input . end ( ) ) ;
}
this - > noncanonicalCursorPos + = GuessWidth ( input ) ;
this - > noncanonicalCursorPosInBytes + = ( int ) input . size ( ) ;
}
void TTYConsoleField : : DoUnselectTick ( )
{
2023-02-17 20:44:01 +00:00
auto lastState = this - > highlightStartInBytes . HasValue ( ) ;
2023-02-17 19:42:30 +00:00
this - > bIsSelecting = false ;
AuResetMember ( this - > highlightEndInBytes ) ;
AuResetMember ( this - > highlightEndInPos ) ;
AuResetMember ( this - > highlightStartInBytes ) ;
AuResetMember ( this - > highlightStart ) ;
2023-02-17 20:44:01 +00:00
if ( lastState )
{
this - > pParent - > SignalRedraw ( ) ;
}
2023-02-17 19:42:30 +00:00
}
void TTYConsoleField : : WriteBuffered ( TTYConsole * pConsole , AuPair < AuUInt32 , AuUInt32 > pos )
{
if ( this - > highlightStartInBytes )
{
2023-02-17 22:27:24 +00:00
auto sViewZero = this - > highlightStartInBytes . value ( ) > = this - > inputField . size ( ) ?
this - > inputField :
this - > inputField . substr ( 0 , this - > highlightStartInBytes . value ( ) ) ;
auto sViewOne = this - > highlightStartInBytes . value ( ) > = this - > inputField . size ( ) ? " " :
this - > highlightEndInBytes . value ( ) > this - > inputField . size ( ) ? " " :
this - > inputField . substr ( this - > highlightStartInBytes . value ( ) ,
this - > highlightEndInBytes . value ( ) - this - > highlightStartInBytes . value ( ) ) ;
2023-02-17 19:42:30 +00:00
auto sViewTwo = this - > highlightEndInBytes . value ( ) < this - > inputField . size ( ) ?
this - > inputField . substr ( this - > highlightEndInBytes . value ( ) ) :
" " ;
pConsole - > WriteBufferedEx ( { pos . first , pos . second } , AuConsole : : EAnsiColor : : eWhite , sViewZero ) ;
pConsole - > WriteBufferedEx ( { pos . first + GuessWidth ( sViewZero ) , pos . second } , AuConsole : : EAnsiColor : : eGreen , sViewOne ) ;
pConsole - > WriteBufferedEx ( { pos . first + GuessWidth ( sViewZero ) + GuessWidth ( sViewOne ) , pos . second } , AuConsole : : EAnsiColor : : eWhite , sViewTwo ) ;
}
else
{
pConsole - > WriteBuffered ( pos , this - > inputField ) ;
}
}
void TTYConsoleField : : Clear ( )
{
AuResetMember ( this - > highlightStartInBytes ) ;
AuResetMember ( this - > highlightEndInBytes ) ;
AuResetMember ( this - > highlightEndInPos ) ;
AuResetMember ( this - > highlightStart ) ;
AuResetMember ( this - > highlightChars ) ;
this - > inputField . clear ( ) ;
this - > noncanonicalCursorPos = 0 ;
this - > noncanonicalCursorPosInBytes = 0 ;
}
bool TTYConsoleField : : Backspace ( )
{
if ( this - > highlightStartInBytes )
{
int idx = highlightStartInBytes . value ( ) ;
int endCnt = highlightEndInBytes . value ( ) - idx ;
auto sViewZero = this - > inputField . substr ( 0 , this - > highlightStartInBytes . value ( ) ) ;
auto sViewTwo = this - > highlightEndInBytes . value ( ) < this - > inputField . size ( ) ?
this - > inputField . substr ( this - > highlightEndInBytes . value ( ) ) :
" " ;
this - > inputField = sViewZero + sViewTwo ;
this - > noncanonicalCursorPos = this - > highlightStart . value ( ) ;
this - > noncanonicalCursorPosInBytes = this - > highlightStartInBytes . value ( ) ;
DoUnselectTick ( ) ;
}
else
{
if ( this - > noncanonicalCursorPosInBytes < = 0 )
{
return false ;
}
int idx = AuLocale : : Encoding : : CountUTF8Length ( { this - > inputField . data ( ) , AuUInt ( this - > noncanonicalCursorPosInBytes - 1 ) } , true ) ;
int endCnt = AuLocale : : Encoding : : CountUTF8Length ( { this - > inputField . data ( ) + idx , this - > inputField . size ( ) - idx } , true ) ;
if ( ! endCnt )
{
this - > inputField . resize ( idx ) ;
}
else
{
auto suffix = inputField . substr ( noncanonicalCursorPosInBytes ) ;
this - > inputField . resize ( idx ) ;
this - > inputField + = suffix ;
}
this - > noncanonicalCursorPos - - ;
this - > noncanonicalCursorPosInBytes = idx ;
}
return true ;
}
void TTYConsoleField : : DirectionalArrow ( int iDirection , bool bShift , bool bControl )
{
if ( this - > bIsSelecting )
{
if ( this - > iLastDirection ! = iDirection )
{
this - > iLastDirection = iDirection ;
DoUnselectTick ( ) ;
}
}
else if ( bShift )
{
this - > iLastDirection = iDirection ;
}
this - > bIsSelecting = bShift ;
auto noncanonicalCursorPos = this - > highlightStart ? this - > highlightStart . value ( ) : this - > noncanonicalCursorPos ;
auto noncanonicalCursorPosInBytes = this - > highlightStart ? this - > highlightStartInBytes . value ( ) : this - > noncanonicalCursorPosInBytes ;
2023-02-17 20:44:01 +00:00
auto getCurrentChar = [ = ] ( int iOffset ) - > int
2023-02-17 19:42:30 +00:00
{
2023-02-17 20:44:01 +00:00
auto uIndex = this - > noncanonicalCursorPosInBytes + iOffset ;
2023-02-17 19:42:30 +00:00
if ( uIndex > = this - > inputField . size ( ) ) return 4 ;
if ( ! ( bool ) isascii ( this - > inputField [ uIndex ] ) )
{
return 2 ;
}
if ( ( bool ) : : isupper ( this - > inputField [ uIndex ] ) )
{
return 1 ;
}
if ( this - > inputField [ uIndex ] = = ' ' | |
this - > inputField [ uIndex ] = = ' ( ' | |
this - > inputField [ uIndex ] = = ' ) ' | |
this - > inputField [ uIndex ] = = ' , ' )
{
return 0 ;
}
if ( ( bool ) : : isalpha ( this - > inputField [ uIndex ] ) )
{
return 6 ;
}
return 5 ;
} ;
bool bTickAgain { } ;
do
{
int iCurState ;
int iNextState ;
if ( iDirection = = 1 )
{
iCurState = getCurrentChar ( 0 ) ;
Right ( ) ;
iNextState = getCurrentChar ( 0 ) ;
}
else
{
iCurState = getCurrentChar ( - 1 ) ;
Left ( ) ;
iNextState = getCurrentChar ( - 1 ) ;
}
if ( bControl )
{
bTickAgain = iNextState = = iCurState ;
bTickAgain & = ( ( ( bool ) this - > noncanonicalCursorPos ) & &
( this - > noncanonicalCursorPosInBytes < this - > inputField . size ( ) ) ) ;
}
}
while ( bTickAgain ) ;
if ( this - > bIsSelecting )
{
auto uEnd1 = AuMax ( this - > noncanonicalCursorPos , noncanonicalCursorPos ) ;
auto uEnd2 = AuMax ( this - > noncanonicalCursorPosInBytes , noncanonicalCursorPosInBytes ) ;
if ( this - > highlightEndInPos )
{
uEnd1 = AuMax ( uEnd1 , this - > highlightEndInPos . value ( ) ) ;
}
if ( this - > highlightEndInBytes )
{
uEnd2 = AuMax ( uEnd1 , this - > highlightEndInBytes . value ( ) ) ;
}
auto uStart1 = AuMin ( this - > noncanonicalCursorPos , noncanonicalCursorPos ) ;
auto uStart2 = AuMin ( this - > noncanonicalCursorPosInBytes , noncanonicalCursorPosInBytes ) ;
this - > highlightStartInBytes = uStart2 ;
this - > highlightEndInBytes = uEnd2 ;
this - > highlightEndInPos = uEnd1 ;
this - > highlightStart = uStart1 ;
this - > highlightChars = AuLocale : : Encoding : : CountUTF8Length ( { this - > inputField . data ( ) + uStart2 , ( AuUInt ) uEnd2 - uStart2 } , false ) ;
2023-02-17 20:44:01 +00:00
this - > pParent - > SignalRedraw ( ) ;
2023-02-17 19:42:30 +00:00
}
else
{
DoUnselectTick ( ) ;
}
}
void TTYConsoleField : : Left ( )
{
if ( this - > noncanonicalCursorPosInBytes = = 0 )
{
return ;
}
int idx = AuLocale : : Encoding : : CountUTF8Length ( { this - > inputField . data ( ) , AuUInt ( this - > noncanonicalCursorPosInBytes - 1 ) } ,
true ) ;
this - > noncanonicalCursorPos - - ;
this - > noncanonicalCursorPosInBytes = idx ;
}
void TTYConsoleField : : Right ( )
{
if ( this - > inputField . size ( ) < = this - > noncanonicalCursorPosInBytes )
{
return ;
}
auto uAddend = AuLocale : : Encoding : : IterateUTF8 ( { & this - > inputField [ this - > noncanonicalCursorPosInBytes ] ,
this - > inputField . size ( ) - this - > noncanonicalCursorPosInBytes } ) ;
this - > noncanonicalCursorPos + + ;
this - > noncanonicalCursorPosInBytes + = uAddend ;
}
TTYConsole : : TTYConsole ( ) :
inputField ( this )
{
}
2022-05-18 23:12:52 +00:00
bool TTYConsole : : IsShowingHintLine ( )
{
2023-02-17 19:42:30 +00:00
return false ;
//return this->inputField.inputField.size();
2022-05-18 23:12:52 +00:00
}
void TTYConsole : : Init ( )
{
2022-06-06 21:34:26 +00:00
this - > HistorySetFile ( ) ;
this - > HistoryLoad ( ) ;
2022-05-18 23:12:52 +00:00
}
void TTYConsole : : Deinit ( )
{
2022-08-14 13:41:19 +00:00
this - > End ( ) ;
2022-06-06 21:34:26 +00:00
this - > HistoryAppendChanges ( ) ;
2022-05-18 23:12:52 +00:00
}
bool TTYConsole : : Start ( )
{
2022-07-21 00:25:38 +00:00
if ( ! ConsoleStd : : IsStdOutTTY ( ) )
{
return false ;
}
2022-05-18 23:12:52 +00:00
gTTYConsoleEnabled = true ;
2024-04-14 22:11:15 +00:00
//#if defined(AURORA_IS_MODERNNT_DERIVED)
# if defined(AURORA_PLATFORM_WIN32)
2022-05-18 23:12:52 +00:00
this - > oldCP = GetConsoleOutputCP ( ) ;
SetConsoleOutputCP ( CP_UTF8 ) ;
# endif
2022-08-04 19:29:41 +00:00
# if defined(AURORA_IS_POSIX_DERIVED)
TTYWrite ( " \033 [?1049h " ) ;
# endif
2022-05-18 23:12:52 +00:00
if ( NoncanonicalMode ( ) )
{
ConsoleStd : : EnterNoncanonicalMode ( ) ;
}
2022-05-23 15:10:19 +00:00
# if defined(AURORA_IS_MODERNNT_DERIVED)
if ( IsWin32UxMode ( ) )
{
UXModeStart ( ) ;
}
2023-12-18 04:52:39 +00:00
if ( AuSwInfo : : IsWindows11OrGreater ( ) )
{
AuLogWarn ( " Aurora's ConsoleTTY *logger* does not run under Windows Terminal. You must use conhost via cmd.exe or upgrade to Windows 7 or whichever version of 10/LTSC has the best drivers. " ) ;
}
2022-05-23 15:10:19 +00:00
# endif
2022-05-18 23:12:52 +00:00
return true ;
}
void TTYConsole : : End ( )
{
2024-04-14 22:11:15 +00:00
//#if defined(AURORA_IS_MODERNNT_DERIVED)
# if defined(AURORA_PLATFORM_WIN32)
if ( pSetConsoleActiveScreenBuffer )
{
pSetConsoleActiveScreenBuffer ( GetStdHandle ( STD_OUTPUT_HANDLE ) ) ;
}
2023-12-08 18:25:50 +00:00
# endif
2022-08-14 13:41:19 +00:00
if ( ! AuExchange ( gTTYConsoleEnabled , false ) )
{
2023-12-08 18:25:50 +00:00
# if defined(AURORA_IS_POSIX_DERIVED)
TTYWrite ( " \033 [?1049l " ) ;
# endif
2022-08-14 13:41:19 +00:00
return ;
}
2023-12-08 18:25:50 +00:00
if ( this - > NoncanonicalMode ( ) )
2022-08-14 13:41:19 +00:00
{
ConsoleStd : : LeaveNoncanonicalMode ( ) ;
}
2022-05-18 23:12:52 +00:00
2023-12-08 18:25:50 +00:00
if ( this - > PermitDoubleBuffering ( ) )
{
EndBuffering ( ) ;
}
2022-05-18 23:12:52 +00:00
TTYClearScreen ( ) ;
TTYClearLine ( EAnsiColor : : eReset ) ;
2022-08-04 19:29:41 +00:00
# if defined(AURORA_IS_POSIX_DERIVED)
TTYWrite ( " \033 [?1049l " ) ;
# endif
2024-04-14 22:11:15 +00:00
//#if defined(AURORA_IS_MODERNNT_DERIVED)
# if defined(AURORA_PLATFORM_WIN32)
2022-05-18 23:12:52 +00:00
SetConsoleOutputCP ( this - > oldCP ) ;
# endif
if ( ! UTF8 ( ) )
{
TTYWrite ( " \033 (B " ) ;
}
2022-08-14 13:41:19 +00:00
# if defined(AURORA_IS_POSIX_DERIVED)
ConsoleStd : : Unlock ( ) ; // just really making sure
# endif
ConsoleStd : : Flush ( ) ;
2022-05-18 23:12:52 +00:00
}
void TTYConsole : : BufferMessage ( const AuConsole : : ConsoleMessage & msg )
{
AU_LOCK_GUARD ( this - > messageLock ) ;
2022-12-14 20:08:52 +00:00
AuConsole : : ConsoleMessage msg2 ( msg ) ;
msg2 . line = msg . ToConsole ( ) ;
AuTryInsert ( this - > messagesPending , msg2 ) ; // TODO: !
2023-12-18 01:42:50 +00:00
if ( auto pEvent = ConsoleStd : : GetConTTYEvent ( ) )
{
pEvent - > Set ( ) ;
}
2022-12-14 20:08:52 +00:00
}
void TTYConsole : : BufferMessage ( const AuConsole : : ConsoleMessage & msg , const AuString & input )
{
AU_LOCK_GUARD ( this - > messageLock ) ;
AuConsole : : ConsoleMessage msg2 ( msg ) ;
msg2 . line = input ;
AuTryInsert ( this - > messagesPending , msg2 ) ; // TODO: !
2023-12-18 01:42:50 +00:00
if ( auto pEvent = ConsoleStd : : GetConTTYEvent ( ) )
{
pEvent - > Set ( ) ;
}
2022-05-18 23:12:52 +00:00
}
void TTYConsole : : NoncanonicalTick ( )
{
ConsoleStd : : NoncanonicalTick ( ) ;
auto inputs = ConsoleStd : : DequeueNoncanonicalInput ( ) ;
2022-05-19 03:21:34 +00:00
if ( inputs . size ( ) & & PermitDoubleBuffering ( ) )
2022-05-18 23:12:52 +00:00
{
BeginBuffering ( ) ;
}
for ( auto & input : inputs )
{
2022-08-13 17:32:14 +00:00
//AuLogDbg("[HANDLE] Key Stroke: {}, {}, {}. control: {}, alt: {}, shift: {}", ConsoleStd::ENoncanonicalInputToString(input.type), input.scrollDeltaY, input.string, input.isControlSequence, input.isAltSequence, input.isShiftSequence);
2022-08-04 19:29:41 +00:00
2022-05-18 23:12:52 +00:00
switch ( input . type )
{
case ConsoleStd : : ENoncanonicalInput : : eInput :
{
NoncanonicalOnString ( input . string ) ;
break ;
}
case ConsoleStd : : ENoncanonicalInput : : eBackspace :
{
NoncanonicalOnBackspace ( ) ;
break ;
}
case ConsoleStd : : ENoncanonicalInput : : eEnter :
{
NoncanonicalOnEnter ( ) ;
break ;
}
case ConsoleStd : : ENoncanonicalInput : : eArrowLeft :
{
2023-02-17 19:42:30 +00:00
NoncanonicalOnLeft ( input . bIsShiftSequence | | input . bIsAltSequence , input . bIsControlSequence ) ;
2022-05-18 23:12:52 +00:00
break ;
}
case ConsoleStd : : ENoncanonicalInput : : eArrowRight :
{
2023-02-17 19:42:30 +00:00
NoncanonicalOnRight ( input . bIsShiftSequence | | input . bIsAltSequence , input . bIsControlSequence ) ;
2022-05-18 23:12:52 +00:00
break ;
}
2022-05-24 05:58:06 +00:00
case ConsoleStd : : ENoncanonicalInput : : ePageDown :
{
NoncanonicalOnPageDown ( ) ;
break ;
}
case ConsoleStd : : ENoncanonicalInput : : ePageUp :
{
NoncanonicalOnPageUp ( ) ;
break ;
}
2022-05-18 23:12:52 +00:00
case ConsoleStd : : ENoncanonicalInput : : eArrowDown :
{
2022-05-19 03:21:34 +00:00
2023-02-17 19:42:30 +00:00
if ( this - > inputField . noncanonicalCursorPosInBytes = = 0 | |
2022-05-20 10:29:33 +00:00
this - > GetHintLines ( ) = = 0 | |
2023-02-17 19:42:30 +00:00
this - > inputField . noncanonicalCursorPosInBytes = = this - > inputField . inputField . size ( ) )
2022-05-19 03:21:34 +00:00
{
NoncanonicalOnHistoryDown ( ) ;
}
else
{
NoncanonicalOnMenuDown ( ) ;
}
2022-05-18 23:12:52 +00:00
break ;
}
case ConsoleStd : : ENoncanonicalInput : : eArrowUp :
{
2022-05-19 03:21:34 +00:00
2023-02-17 19:42:30 +00:00
if ( this - > inputField . noncanonicalCursorPosInBytes = = 0 | |
2022-05-20 10:29:33 +00:00
this - > GetHintLines ( ) = = 0 | |
2023-02-17 19:42:30 +00:00
this - > inputField . noncanonicalCursorPosInBytes = = this - > inputField . inputField . size ( ) )
2022-05-19 03:21:34 +00:00
{
NoncanonicalOnHistoryUp ( ) ;
}
else
{
NoncanonicalOnMenuUp ( ) ;
}
2022-05-18 23:12:52 +00:00
break ;
}
case ConsoleStd : : ENoncanonicalInput : : eScroll :
{
2023-06-24 03:47:06 +00:00
if ( abs ( input . iScrollDeltaY ) = = 1 )
{
input . iScrollDeltaY = input . iScrollDeltaY * 3 ;
}
2022-12-09 22:59:03 +00:00
Scroll ( input . iScrollDeltaY ) ;
2022-05-18 23:12:52 +00:00
break ;
}
default :
{
2022-12-09 22:59:03 +00:00
AuLogDbg ( " Key Stroke: {}, {}, {} " , ConsoleStd : : ENoncanonicalInputToString ( input . type ) , input . iScrollDeltaY , input . string ) ;
2022-05-18 23:12:52 +00:00
}
2022-08-04 19:29:41 +00:00
2022-05-18 23:12:52 +00:00
} ;
}
2022-05-19 03:21:34 +00:00
if ( inputs . size ( ) & & PermitDoubleBuffering ( ) )
2022-05-18 23:12:52 +00:00
{
EndBuffering ( ) ;
}
}
void TTYConsole : : NoncanonicalOnString ( const AuString & input )
{
2023-02-17 19:42:30 +00:00
inputField . AddString ( input ) ;
2022-05-18 23:12:52 +00:00
RedrawInput ( true ) ;
NoncanonicalSetCursor ( ) ;
}
2023-02-17 19:42:30 +00:00
void TTYConsole : : NoncanonicalOnLeft ( bool bShift , bool bControl )
2022-05-18 23:12:52 +00:00
{
2023-02-17 19:42:30 +00:00
inputField . DirectionalArrow ( - 1 , bShift , bControl ) ;
2022-05-18 23:12:52 +00:00
NoncanonicalSetCursor ( ) ;
}
2023-02-17 19:42:30 +00:00
void TTYConsole : : NoncanonicalOnRight ( bool bShift , bool bControl )
2022-05-18 23:12:52 +00:00
{
2023-02-17 19:42:30 +00:00
inputField . DirectionalArrow ( 1 , bShift , bControl ) ;
2022-05-18 23:12:52 +00:00
NoncanonicalSetCursor ( ) ;
}
void TTYConsole : : NoncanonicalOnBackspace ( )
{
2023-02-17 19:42:30 +00:00
if ( ! inputField . Backspace ( ) )
2022-05-18 23:12:52 +00:00
{
return ;
}
RedrawInput ( true ) ;
NoncanonicalSetCursor ( ) ;
}
2022-05-23 15:10:19 +00:00
bool TTYConsole : : IsWin32UxMode ( )
{
return true ;
}
void TTYConsole : : UXModeStart ( )
{
# if defined(AURORA_IS_MODERNNT_DERIVED)
2022-09-09 20:12:20 +00:00
LeaveScrollMode ( ) ;
2022-05-23 15:10:19 +00:00
# endif
}
void TTYConsole : : UXModeFlip ( )
{
if ( AuExchange ( uxModeFlipped , true ) )
{
return ;
}
if ( ! IsWin32UxMode ( ) )
{
return ;
}
# if defined(AURORA_IS_MODERNNT_DERIVED)
2022-09-09 20:12:20 +00:00
EnterScrollMode ( ) ;
2022-05-23 15:10:19 +00:00
# endif
}
2023-12-08 18:25:50 +00:00
2022-08-07 22:35:13 +00:00
void EnterScrollMode ( )
{
2022-08-09 00:55:18 +00:00
# if defined(AURORA_IS_MODERNNT_DERIVED)
2022-08-07 22:35:13 +00:00
DWORD mode ;
HANDLE stream = GetStdHandle ( STD_INPUT_HANDLE ) ;
2022-09-09 20:12:20 +00:00
HANDLE handles2 [ 2 ] ;
GetConsoleHandles ( handles2 ) ;
{
GetConsoleMode ( stream , & mode ) ;
mode & = ~ ( ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS ) ;
SetConsoleMode ( stream , mode ) ;
}
{
if ( handles2 [ 0 ] ! = INVALID_HANDLE_VALUE )
{
GetConsoleMode ( handles2 [ 0 ] , & mode ) ;
mode & = ~ ( ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS ) ;
SetConsoleMode ( handles2 [ 0 ] , mode ) ;
}
}
{
if ( handles2 [ 1 ] ! = INVALID_HANDLE_VALUE )
{
GetConsoleMode ( handles2 [ 1 ] , & mode ) ;
mode & = ~ ( ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS ) ;
SetConsoleMode ( handles2 [ 1 ] , mode ) ;
}
}
2023-12-08 18:25:50 +00:00
gTTYConsole . uxModeFlipped = true ;
2023-12-16 21:13:46 +00:00
// Paranoia
{
static AuInitOnce gInitOnce ;
gInitOnce . Call ( [ ] ( )
{
atexit ( [ ] ( )
{
LeaveScrollMode ( ) ;
Exit ( ) ;
} ) ;
} ) ;
}
2022-08-09 00:55:18 +00:00
# endif
2022-08-07 22:35:13 +00:00
}
void LeaveScrollMode ( )
{
2022-08-09 00:55:18 +00:00
# if defined(AURORA_IS_MODERNNT_DERIVED)
2022-08-07 22:35:13 +00:00
DWORD mode ;
HANDLE stream = GetStdHandle ( STD_INPUT_HANDLE ) ;
2022-09-09 20:12:20 +00:00
HANDLE handles2 [ 2 ] ;
GetConsoleHandles ( handles2 ) ;
{
GetConsoleMode ( stream , & mode ) ;
mode | = ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS ;
SetConsoleMode ( stream , mode ) ;
}
{
if ( handles2 [ 0 ] ! = INVALID_HANDLE_VALUE )
{
GetConsoleMode ( handles2 [ 0 ] , & mode ) ;
mode | = ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS ;
SetConsoleMode ( handles2 [ 0 ] , mode ) ;
}
}
{
if ( handles2 [ 1 ] ! = INVALID_HANDLE_VALUE )
{
GetConsoleMode ( handles2 [ 1 ] , & mode ) ;
mode | = ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS ;
SetConsoleMode ( handles2 [ 1 ] , mode ) ;
}
}
2023-12-08 18:25:50 +00:00
gTTYConsole . uxModeFlipped = false ;
gTTYConsole . uxFlipTime = AuTime : : SteadyClockNS ( ) ; // Auto timeout
# endif
}
void ScrollModeTick ( )
{
# if defined(AURORA_IS_MODERNNT_DERIVED)
if ( ! gTTYConsole . uxModeFlipped )
{
if ( gTTYConsole . uxFlipTime + AuMSToNS < AuUInt64 > ( AuSToMS < AuUInt64 > ( 8 ) ) < = AuTime : : SteadyClockNS ( ) )
{
EnterScrollMode ( ) ;
}
}
2022-08-09 00:55:18 +00:00
# endif
2022-08-07 22:35:13 +00:00
}
2022-05-18 23:12:52 +00:00
void TTYConsole : : NoncanonicalOnEnter ( )
{
2024-03-09 08:15:30 +00:00
AuString line ;
2022-05-18 23:12:52 +00:00
2024-03-09 08:15:30 +00:00
{
AU_LOCK_GUARD ( this - > historyLock - > AsWritable ( ) ) ;
if ( this - > inputField . inputField . size ( ) )
2022-05-18 23:12:52 +00:00
{
2024-03-09 08:15:30 +00:00
2022-05-18 23:12:52 +00:00
# if defined(AURORA_IS_MODERNNT_DERIVED)
2024-03-09 08:15:30 +00:00
if ( this - > inputField . inputField = = " !s " )
2022-05-18 23:12:52 +00:00
{
2024-03-09 08:15:30 +00:00
EnterScrollMode ( ) ;
2022-05-18 23:12:52 +00:00
}
2024-03-09 08:15:30 +00:00
else if ( this - > inputField . inputField = = " !c " )
2022-05-24 05:58:06 +00:00
{
2024-03-09 08:15:30 +00:00
LeaveScrollMode ( ) ;
2022-08-04 19:29:41 +00:00
}
2024-03-09 08:15:30 +00:00
else
2022-08-04 19:29:41 +00:00
# endif
2024-03-09 08:15:30 +00:00
if ( this - > inputField . inputField = = " !b " )
{
this - > iScrollPos = - 1 ;
this - > bTriggerRedraw = true ;
}
else if ( this - > inputField . inputField = = " !t " )
2022-08-04 19:29:41 +00:00
{
2024-03-09 08:15:30 +00:00
this - > iScrollPos = 0 ;
this - > bTriggerRedraw = true ;
}
else
{
# if defined(AURORA_IS_MODERNNT_DERIVED)
if ( this - > inputField . inputField = = " help " )
{
AuLogInfo ( " ConsoleTTY: Type !s to enter scroll mode, type !c to enter host-os controlled copy/paste mode (quick-edit) " ) ;
}
# endif
# if defined(AURORA_IS_POSIX_DERIVED)
if ( this - > inputField . inputField = = " help " )
{
AuLogInfo ( " ConsoleTTY: Hold control + arrow key up/down to scroll. " ) ;
}
# endif
if ( this - > inputField . inputField = = " help " )
{
AuLogInfo ( " ConsoleTTY: use the command !t to scroll to the top, the command !b to lock-scroll to the bottom. " ) ;
}
line = this - > inputField . inputField ;
2022-05-24 05:58:06 +00:00
}
2022-05-24 05:37:51 +00:00
2024-03-09 08:15:30 +00:00
AuTryInsert ( this - > history , this - > inputField . inputField ) ;
2022-05-18 23:12:52 +00:00
}
2024-03-09 08:15:30 +00:00
this - > inputField . Clear ( ) ;
OnEnter ( ) ;
}
2022-05-18 23:12:52 +00:00
2024-03-09 08:15:30 +00:00
AuConsole : : DispatchRawLine ( line ) ;
2022-05-18 23:12:52 +00:00
}
void TTYConsole : : NoncanonicalOnMenuLeft ( )
{
}
void TTYConsole : : NoncanonicalOnMenuRight ( )
{
}
void TTYConsole : : NoncanonicalOnMenuUp ( )
{
}
void TTYConsole : : NoncanonicalOnMenuDown ( )
{
2022-05-19 03:21:34 +00:00
}
void TTYConsole : : NoncanonicalOnHistoryUp ( )
{
2022-05-20 10:29:33 +00:00
bool locked { } ;
2022-05-24 06:09:42 +00:00
if ( this - > history . empty ( ) )
{
return ;
}
2023-02-17 19:42:30 +00:00
if ( this - > inputField . noncanonicalCursorPos = = 0 | |
this - > inputField . noncanonicalCursorPosInBytes = = this - > inputField . inputField . size ( ) )
2022-05-20 10:29:33 +00:00
{
locked = true ;
}
2022-05-19 03:21:34 +00:00
if ( this - > iHistoryPos = = - 1 )
{
this - > iHistoryPos = this - > history . size ( ) ;
}
this - > iHistoryPos - - ;
2022-05-18 23:12:52 +00:00
2022-05-19 03:21:34 +00:00
if ( this - > iHistoryPos < 0 )
{
this - > iHistoryPos = 0 ;
}
2022-05-24 06:09:42 +00:00
2023-02-17 19:42:30 +00:00
this - > inputField . inputField = this - > history [ this - > iHistoryPos ] ;
2022-05-19 03:32:23 +00:00
HistoryUpdateCursor ( ) ;
2022-05-20 10:29:33 +00:00
if ( locked )
{
2023-02-17 19:42:30 +00:00
this - > inputField . noncanonicalCursorPos = GuessWidth ( this - > inputField . inputField ) ;
this - > inputField . noncanonicalCursorPosInBytes = ( int ) this - > inputField . inputField . size ( ) ;
2022-05-20 10:29:33 +00:00
NoncanonicalSetCursor ( ) ;
}
2023-02-17 22:27:24 +00:00
this - > inputField . DoUnselectTick ( ) ;
2022-05-19 03:21:34 +00:00
}
void TTYConsole : : NoncanonicalOnHistoryDown ( )
{
2022-06-06 21:34:26 +00:00
AU_LOCK_GUARD ( this - > historyLock - > AsReadable ( ) ) ;
2022-05-20 10:29:33 +00:00
bool locked { } ;
2022-05-24 06:09:42 +00:00
if ( this - > history . empty ( ) )
{
return ;
}
2023-02-17 19:42:30 +00:00
if ( this - > inputField . noncanonicalCursorPos = = 0 | |
this - > inputField . noncanonicalCursorPosInBytes = = this - > inputField . inputField . size ( ) )
2022-05-20 10:29:33 +00:00
{
locked = true ;
}
2022-05-19 03:21:34 +00:00
if ( this - > iHistoryPos = = - 1 )
{
return ;
}
this - > iHistoryPos + + ;
if ( this - > iHistoryPos > = this - > history . size ( ) )
{
this - > iHistoryPos = - 1 ;
2023-02-17 19:42:30 +00:00
this - > inputField . inputField . clear ( ) ;
2022-05-19 03:21:34 +00:00
}
else
{
2023-02-17 19:42:30 +00:00
this - > inputField . inputField = this - > history [ this - > iHistoryPos ] ;
2022-05-19 03:21:34 +00:00
}
2022-05-19 03:32:23 +00:00
HistoryUpdateCursor ( ) ;
2022-05-20 10:29:33 +00:00
if ( locked )
{
2023-02-17 19:42:30 +00:00
this - > inputField . noncanonicalCursorPos = GuessWidth ( this - > inputField . inputField ) ;
this - > inputField . noncanonicalCursorPosInBytes = ( int ) this - > inputField . inputField . size ( ) ;
2022-05-20 10:29:33 +00:00
NoncanonicalSetCursor ( ) ;
}
2023-02-17 22:27:24 +00:00
this - > inputField . DoUnselectTick ( ) ;
2022-05-19 03:32:23 +00:00
}
void TTYConsole : : HistoryUpdateCursor ( )
{
2023-02-17 19:42:30 +00:00
this - > inputField . noncanonicalCursorPos = AuMin < AuUInt32 > ( this - > inputField . noncanonicalCursorPos , GuessWidth ( this - > inputField . inputField ) ) ;
this - > inputField . noncanonicalCursorPosInBytes = AuMin < AuUInt32 > ( this - > inputField . noncanonicalCursorPosInBytes , AuUInt32 ( this - > inputField . inputField . size ( ) ) ) ;
2022-05-19 03:21:34 +00:00
RedrawInput ( true ) ;
2022-05-19 03:32:23 +00:00
NoncanonicalSetCursor ( ) ;
2022-05-18 23:12:52 +00:00
}
2022-06-06 21:34:26 +00:00
void TTYConsole : : HistorySetFile ( )
{
2023-12-13 18:11:35 +00:00
auto pProcPath = Process : : GetProcessFullPath ( ) ;
auto hash = AuFnv1a64Runtime ( pProcPath ? pProcPath - > data ( ) : nullptr ,
pProcPath ? pProcPath - > size ( ) : 0 ) ;
2022-06-06 21:34:26 +00:00
AuIOFS : : NormalizePath ( this - > historyFileName , fmt : : format ( " ~/TTYHistory/{}.txt " , hash ) ) ;
}
AuString TTYConsole : : HistoryGetFile ( )
{
return this - > historyFileName ;
}
void TTYConsole : : HistoryAppendChanges ( )
{
if ( ! this - > historyLock )
{
return ;
}
AU_LOCK_GUARD ( this - > historyLock - > AsWritable ( ) ) ;
if ( this - > history . size ( ) < = this - > iHistoryWritePos )
{
return ;
}
auto file = AuIOFS : : OpenUnique ( this - > historyFileName , AuIOFS : : EFileOpenMode : : eReadWrite ) ;
if ( ! file )
{
2024-02-16 13:07:28 +00:00
SysPushErrorIO ( " {} " , this - > historyFileName ) ;
2022-06-06 21:34:26 +00:00
return ;
}
file - > SetOffset ( file - > GetLength ( ) ) ;
AuString buffer ;
auto line = AuLocale : : NewLine ( ) ;
line . reserve ( 4096 ) ;
for ( int i = this - > iHistoryWritePos ; i < this - > history . size ( ) ; i + + )
{
buffer + = ( i = = 0 ? " " : line ) ;
buffer + = this - > history [ i ] ;
}
AuUInt bytesWritten ;
file - > Write ( AuMemoryViewStreamRead ( AuMemory : : MemoryViewRead ( buffer ) , bytesWritten ) ) ;
this - > iHistoryWritePos = this - > history . size ( ) ;
}
void TTYConsole : : HistoryLoad ( )
{
AU_LOCK_GUARD ( this - > historyLock - > AsWritable ( ) ) ;
if ( this - > historyFileName . empty ( ) )
{
return ;
}
if ( ! AuIOFS : : FileExists ( this - > historyFileName ) )
{
return ;
}
AuString buffer ;
if ( ! AuIOFS : : ReadString ( this - > historyFileName , buffer ) )
{
return ;
}
2024-04-19 03:33:57 +00:00
AuParse : : SplitNewlines ( buffer , [ & ] ( const AuROString & in )
2022-06-06 21:34:26 +00:00
{
2024-04-19 03:33:57 +00:00
this - > history . push_back ( AuString ( in ) ) ;
2022-06-06 21:34:26 +00:00
} ) ;
2022-06-06 21:36:14 +00:00
this - > iHistoryWritePos = this - > history . size ( ) ;
2022-06-06 21:34:26 +00:00
}
2022-05-24 05:58:06 +00:00
void TTYConsole : : NoncanonicalOnPageUp ( )
{
this - > Scroll ( this - > GetLogBoxLines ( ) ) ;
}
void TTYConsole : : NoncanonicalOnPageDown ( )
{
this - > Scroll ( - this - > GetLogBoxLines ( ) ) ;
}
2022-05-18 23:12:52 +00:00
void TTYConsole : : Scroll ( int delta )
{
auto maxLines = GetLogBoxLines ( ) ;
if ( this - > screenBuffer . size ( ) < = maxLines )
{
this - > iScrollPos = - 1 ;
return ;
}
if ( this - > iScrollPos = = - 1 )
{
this - > iScrollPos = AuMax < AuUInt32 > ( this - > screenBuffer . size ( ) - maxLines , 0 ) ;
}
this - > iScrollPos - = delta ;
if ( this - > iScrollPos < 0 )
{
this - > iScrollPos = 0 ;
}
if ( this - > screenBuffer . size ( ) - maxLines < this - > iScrollPos )
{
this - > iScrollPos = - 1 ;
}
this - > bTriggerRedraw = true ;
}
2022-06-06 21:34:26 +00:00
void TTYConsole : : PumpHistory ( )
{
static Aurora : : Utility : : RateLimiter limiter ;
if ( ! limiter . nextTriggerTime )
{
limiter . noCatchUp = true ;
limiter . SetNextStep ( AuMSToNS < AuUInt64 > ( 10'000 ) ) ;
}
if ( ! limiter . CheckExchangePass ( ) )
{
return ;
}
HistoryAppendChanges ( ) ;
}
2022-05-18 23:12:52 +00:00
void TTYConsole : : Pump ( )
{
2022-11-28 16:01:08 +00:00
//SysBenchmark("Console TTY pump");
2022-05-18 23:12:52 +00:00
if ( ! gTTYConsoleEnabled )
{
return ;
}
if ( NoncanonicalMode ( ) )
{
2022-11-28 16:01:08 +00:00
//SysBenchmark("NoncanonicalTick");
2022-05-18 23:12:52 +00:00
NoncanonicalTick ( ) ;
}
2022-11-28 16:01:08 +00:00
{
//SysBenchmark("flush (redraw)");
Flush ( ) ;
}
{
//SysBenchmark("history");
PumpHistory ( ) ;
}
2023-12-08 18:25:50 +00:00
ScrollModeTick ( ) ;
2022-05-18 23:12:52 +00:00
}
void TTYConsole : : OnEnter ( )
{
2022-05-19 22:30:18 +00:00
this - > iHistoryPos = - 1 ;
2022-05-18 23:12:52 +00:00
auto line = this - > currentHeight ;
2023-02-17 19:42:30 +00:00
this - > inputField . Clear ( ) ;
2022-05-18 23:12:52 +00:00
this - > RedrawInput ( true ) ;
this - > NoncanonicalSetCursor ( ) ;
}
void TTYConsole : : Flush ( )
{
2022-05-19 22:28:11 +00:00
AU_LOCK_GUARD ( this - > messageLock ) ;
2022-05-18 23:12:52 +00:00
RedrawWindow ( ) ;
}
bool TTYConsole : : RegenerateBuffer ( bool resChanged , bool & forceRedrawIfFalse )
{
auto messagesPending = AuExchange ( this - > messagesPending , { } ) ;
bool bShouldRegenerateStringArary { } ;
bool widthChanged = this - > oldWidth ! = this - > currentWidth ;
bool sizeChanged = widthChanged | | this - > currentHeight ! = this - > oldHeight ;
// ew
auto maxLines = GetLogBoxLines ( ) ;
int maxWidth = this - > currentWidth - int ( GetRightBorder ( ) ) - int ( GetLeftBorder ( ) ) - int ( this - > leftLogPadding ) - this - > rightLogPadding ;
// Word-wrap cancer
if ( this - > bScreenBufferDoesntMap )
{
if ( resChanged )
{
bShouldRegenerateStringArary = widthChanged ;
}
}
else
{
if ( resChanged )
{
2022-12-14 01:35:18 +00:00
for ( auto & [ color , message ] : this - > screenBuffer )
2022-05-18 23:12:52 +00:00
{
int anyLineRemoveEsc = message . rfind ( ' \x1b ' , 0 ) = = 0 ;
if ( message . size ( ) - ( anyLineRemoveEsc * 7 ) > maxWidth )
{
bShouldRegenerateStringArary = true ;
break ;
}
}
}
}
// Unsafe insert
2023-06-27 11:40:47 +00:00
2022-05-18 23:12:52 +00:00
this - > messages . insert ( this - > messages . end ( ) , messagesPending . begin ( ) , messagesPending . end ( ) ) ;
2023-06-27 11:40:47 +00:00
if ( this - > messages . size ( ) > 10000 )
{
this - > messages . erase ( this - > messages . begin ( ) , this - > messages . end ( ) - 10000 ) ;
}
2022-05-18 23:12:52 +00:00
// Insert console message while attempting to preserve the intention of word-wrapping
auto addMessages = [ & ] ( const AuList < AuConsole : : ConsoleMessage > & messages )
{
for ( auto & message : messages )
{
2022-12-14 20:08:52 +00:00
auto str = message . line ; // Note: we replaced the line in BufferMessage
2022-05-18 23:12:52 +00:00
while ( str . size ( ) )
{
2022-05-19 22:28:11 +00:00
int XOffset = GetLeftBorder ( ) + this - > leftLogPadding ;
2022-11-28 16:01:08 +00:00
2022-06-14 15:59:37 +00:00
auto itr = str . npos ;
2022-06-22 13:42:17 +00:00
itr = str . find ( ' \t ' ) ;
2022-11-28 16:01:08 +00:00
2022-05-19 22:28:11 +00:00
while ( itr ! = str . npos )
{
auto suffix = str . substr ( itr + 1 ) ;
str = str . substr ( 0 , itr ) ;
2022-11-28 16:01:08 +00:00
2022-05-19 22:28:11 +00:00
AuString padding ( 4 - ( itr % 4 ) , ' ' ) ;
2022-11-28 16:01:08 +00:00
2022-05-19 22:28:11 +00:00
str + = padding ;
str + = suffix ;
2022-11-28 16:01:08 +00:00
2022-05-19 22:28:11 +00:00
itr = str . find ( ' \t ' , itr ) ;
}
2022-11-28 16:01:08 +00:00
2022-05-18 23:12:52 +00:00
int anyLineRemoveEsc = str . rfind ( ' \x1b ' , 0 ) = = 0 ;
2022-11-28 16:01:08 +00:00
2022-05-18 23:12:52 +00:00
int idx = AuLocale : : Encoding : : CountUTF8Length ( { str . data ( ) , AuMin < AuUInt > ( str . size ( ) , maxWidth + ( anyLineRemoveEsc * 7 ) ) } , true ) ;
auto append = str . substr ( 0 , idx ) ;
2022-12-14 01:35:18 +00:00
AuTryInsert ( this - > screenBuffer , AuMakePair ( message . color , append ) ) ;
2022-11-28 16:01:08 +00:00
2022-05-18 23:12:52 +00:00
str = str . substr ( idx ) ;
2022-06-14 15:59:37 +00:00
this - > bScreenBufferDoesntMap | = bool ( str . size ( ) ) ;
2022-05-18 23:12:52 +00:00
}
}
2022-05-28 17:47:51 +00:00
if ( this - > screenBuffer . size ( ) > maxLines )
{
UXModeFlip ( ) ;
}
} ;
2022-05-23 15:10:19 +00:00
2022-05-18 23:12:52 +00:00
if ( bShouldRegenerateStringArary )
{
// Recalculate our AuString array of lines
this - > screenBuffer . clear ( ) ;
addMessages ( this - > messages ) ;
// Redraw entire screenbuffer
return true ;
}
else
{
// Fast path - just append the damn changes
int oldSize = this - > screenBuffer . size ( ) ;
addMessages ( messagesPending ) ;
auto bannerLines = this - > GetBannerLines ( ) ;
auto indexBeforePadding = this - > GetTopBorder ( ) + this - > GetBannerFootBorder ( ) + ( bannerLines ? this - > topLogPadding + bannerLines : 0 ) ;
auto startIndex = this - > topLogPaddingExtra + indexBeforePadding ;
int drawPos = { } ;
auto delta = this - > screenBuffer . size ( ) - oldSize ;
if ( iScrollPos = = - 1 )
{
if ( this - > screenBuffer . size ( ) > maxLines )
{
2022-08-07 23:22:15 +00:00
// TODO (Reece): Removing optimization bc it was broken. This is a nightmare.
2022-05-18 23:12:52 +00:00
2022-11-28 16:01:08 +00:00
if ( ! gBuggyFastAppend )
2022-05-18 23:12:52 +00:00
{
2022-11-28 16:01:08 +00:00
static bool bSingleShot { } ;
if ( ! AuExchange ( bSingleShot , true ) )
{
EnterScrollMode ( ) ;
}
auto indexBeforePadding = ( this - > GetBannerFootBorder ( ) ? 1 + this - > topLogPadding : 0 ) + this - > topLogPaddingExtra ;
auto startIndex = this - > GetTopBorder ( ) + this - > GetBannerLines ( ) + indexBeforePadding ;
for ( int i = startIndex ; i < this - > currentHeight ; i + + )
{
this - > BlankLine ( i ) ;
}
this - > screenBuffer . clear ( ) ;
addMessages ( this - > messages ) ;
return true ;
}
else
{
// this is still buggy as shit but we NEEEEED it
// youll notice whitespace appear as soon as we start overflowing but eh
for ( int i = startIndex + maxLines ; i < this - > currentHeight ; i + + )
{
this - > BlankLine ( i ) ;
}
TTYScrollBuffer ( delta ) ;
for ( int i = indexBeforePadding ; i < startIndex ; i + + )
{
this - > BlankLine ( i ) ;
}
forceRedrawIfFalse = true ;
drawPos = startIndex + maxLines - delta ;
2022-05-18 23:12:52 +00:00
}
}
else
{
drawPos = startIndex + oldSize ;
}
}
else
{
return false ;
}
2022-05-19 22:28:11 +00:00
if ( delta > = this - > GetLogBoxLines ( ) )
{
return true ;
}
else
2022-05-18 23:12:52 +00:00
{
2022-05-19 22:28:11 +00:00
for ( int i = 0 ; i < delta ; i + + )
{
2022-12-14 01:35:18 +00:00
auto & [ color , message ] = this - > screenBuffer [ i + oldSize ] ;
WriteBufferedEx ( { GetLeftBorder ( ) + this - > leftLogPadding , i + drawPos } , color , message ) ;
2022-05-19 22:28:11 +00:00
}
2022-05-18 23:12:52 +00:00
}
return false | | resChanged ;
}
}
bool TTYConsole : : UTF8 ( )
{
# if defined(AURORA_IS_MODERNNT_DERIVED)
return true ;
# else
return AuLocale : : GetLocale ( ) . codepage = = AuLocale : : ECodePage : : eUTF8 ;
# endif
}
bool TTYConsole : : RedrawWindow ( )
{
bool bTryAgain { } ;
bool bRedrawn = { } ;
bool bRefresh { } ;
do
{
bTryAgain = false ;
bool bWarmed { } ;
# if defined(AURORA_IS_MODERNNT_DERIVED)
bWarmed = WarmBuffering ( ) ;
# endif
auto pos = TTYScreenSize ( ) ;
bool bChangedWidth = currentWidth ! = pos . first ;
bool bChangedHeight = currentHeight ! = pos . second ;
bool bChangedSize = bChangedWidth | | bChangedHeight | | bWarmed ;
bool bRedrawWindowRequired = this - > bTriggerRedraw ;
bool bHasMesasgesPending = messagesPending . size ( ) | | this - > bTriggerRedraw ;
2023-02-17 19:42:30 +00:00
auto currentHash = AuFnv1a64Runtime ( inputField . inputField . data ( ) , inputField . inputField . size ( ) ) ;
2022-05-18 23:12:52 +00:00
bool bInputChanged = NoncanonicalMode ( ) & & ( lastInputHash ! = currentHash & & lastInputHash ! = 0 ) ;
lastInputHash = currentHash ;
oldWidth = currentWidth ;
oldHeight = currentHeight ;
currentWidth = pos . first ;
currentHeight = pos . second ;
if ( currentWidth < 0 )
{
bTryAgain = true ;
continue ;
}
2022-06-06 21:34:26 +00:00
bool redrawEntireBox { } ;
2022-05-18 23:12:52 +00:00
if ( bChangedSize | | bRedrawWindowRequired | | bHasMesasgesPending )
{
bRedrawn = true ;
if ( PermitDoubleBuffering ( ) )
{
BeginBuffering ( ) ;
}
if ( NoncanonicalMode ( ) )
{
}
else
{
TTYStorePos ( ) ;
}
if ( bChangedSize | | this - > bTriggerRedraw )
{
TTYClearScreen ( ) ;
2022-06-06 21:34:26 +00:00
bRefresh = true ;
redrawEntireBox = true ;
2022-05-18 23:12:52 +00:00
}
}
if ( bChangedSize | | bHasMesasgesPending )
{
bool redrawBox { } ;
bRefresh = bChangedSize | | this - > bTriggerRedraw ;
if ( RegenerateBuffer ( bChangedSize , redrawBox ) | | this - > bTriggerRedraw )
{
bRefresh = true ;
2022-06-06 21:34:26 +00:00
redrawEntireBox = true ;
2022-05-18 23:12:52 +00:00
RedrawLogBox ( ) ;
}
2022-06-06 21:34:26 +00:00
2022-05-18 23:12:52 +00:00
bRefresh | = redrawBox ;
}
2022-06-06 21:34:26 +00:00
if ( redrawEntireBox )
{
RedrawLogBox ( ) ;
}
2022-05-18 23:12:52 +00:00
if ( bRefresh )
{
RedrawBanner ( ) ;
RedrawBorders ( ) ;
}
if ( bRedrawn | | bRefresh )
{
RedrawInput ( NoncanonicalMode ( ) ) ;
this - > NoncanonicalSetCursor ( ) ;
TTYStorePos ( ) ;
}
if ( bRedrawn | | bRefresh )
{
RedrawHintLine ( ) ;
}
#if 0
DebugLogArea ( ) ;
# endif
2023-06-24 03:47:06 +00:00
if ( bRedrawn | | bRefresh )
2022-05-18 23:12:52 +00:00
{
if ( NoncanonicalMode ( ) )
{
NoncanonicalSetCursor ( ) ;
}
else
{
TTYRestorePos ( ) ;
}
{
2022-11-28 16:01:08 +00:00
// Account for race conditions of size-change during draw
if ( PermitDoubleBuffering ( ) )
{
bTryAgain = ! EndBuffering ( ) ;
}
2022-05-18 23:12:52 +00:00
}
}
this - > bTriggerRedraw = false ;
}
2022-08-04 19:29:41 +00:00
while ( bTryAgain & & false ) ;
2022-05-18 23:12:52 +00:00
return bRedrawn ;
}
void TTYConsole : : DebugLogArea ( )
{
auto lines = this - > GetLogBoxLines ( ) ;
auto start = this - > GetTopBorder ( ) +
( this - > GetBannerLines ( ) ? this - > GetBannerLines ( ) + 1 : 0 ) +
( this - > GetBannerFootBorder ( ) ? this - > topLogPadding : 0 ) +
this - > topLogPaddingExtra ;
AuString blank ( this - > currentWidth - GetRightBorder ( ) - GetLeftBorder ( ) - this - > leftLogPadding - this - > rightLogPadding , ' ~ ' ) ;
for ( int i = 0 ; i < lines ; i + + )
{
WriteBuffered ( { GetLeftBorder ( ) + this - > leftLogPadding , i + start } , blank ) ;
}
}
void TTYConsole : : WriteLine ( int Y , const AuString & in )
{
# if defined(AURORA_IS_MODERNNT_DERIVED)
2024-04-20 01:29:49 +00:00
RecordFunction ( std : : bind ( & TTYConsole : : WriteLine , this , Y , AuString ( in ) ) ) ;
2022-05-18 23:12:52 +00:00
# endif
if ( in . empty ( ) )
{
return ;
}
int XOffset { } ;
XOffset = GetLeftBorder ( ) ;
# if defined(AURORA_IS_MODERNNT_DERIVED)
DWORD idc ;
2022-12-14 01:35:18 +00:00
auto line2 = AuLocale : : ConvertFromUTF8 ( in ) ;
2024-04-14 22:11:15 +00:00
pSetConsoleCursorPosition ( GetTTYHandle ( ) , COORD { AuStaticCast < short > ( XOffset ) , AuStaticCast < short > ( Y ) } ) ;
pWriteConsoleW ( GetTTYHandle ( ) , line2 . data ( ) , AuUInt32 ( line2 . size ( ) ) , & idc , NULL ) ;
2022-05-18 23:12:52 +00:00
# else
2022-12-16 00:41:01 +00:00
TTYSetPos ( { XOffset , Y } ) ;
2022-05-18 23:12:52 +00:00
ConsoleStd : : WriteStdOutBlocking2 ( in . data ( ) , in . size ( ) ) ;
# endif
}
void TTYConsole : : BlankBordersLine ( int Y )
{
AuString bar ;
if ( UTF8 ( ) )
{
bar = " \xe2 \x94 \x82 " ;
}
else
{
bar = " \033 (0x \033 (B " ;
}
WriteBuffered ( { 0 , Y } , bar ) ;
WriteBuffered ( { this - > currentWidth - 1 , Y } , bar ) ;
}
void TTYConsole : : BlankLine ( int Y , bool borders )
{
TTYSetPos ( { 0 , Y } ) ;
2022-08-02 04:52:17 +00:00
TTYClearLine ( EAnsiColor : : eReset ) ;
2022-05-18 23:12:52 +00:00
BlankBordersLine ( Y ) ;
}
void TTYConsole : : WriteBuffered ( AuPair < AuUInt32 , AuUInt32 > pos , const AuString & in )
{
# if defined(AURORA_IS_MODERNNT_DERIVED)
2024-04-20 01:29:49 +00:00
RecordFunction ( std : : bind ( & TTYConsole : : WriteBuffered , this , pos , AuString ( in ) ) ) ;
2022-05-18 23:12:52 +00:00
# endif
if ( in . empty ( ) )
{
return ;
}
# if defined(AURORA_IS_MODERNNT_DERIVED)
DWORD idc ;
2022-12-14 01:35:18 +00:00
auto line2 = AuLocale : : ConvertFromUTF8 ( in ) ;
2024-04-14 22:11:15 +00:00
pSetConsoleCursorPosition ( GetTTYHandle ( ) , COORD { AuStaticCast < short > ( pos . first ) , AuStaticCast < short > ( pos . second ) } ) ;
pWriteConsoleW ( GetTTYHandle ( ) , line2 . data ( ) , AuUInt32 ( line2 . size ( ) ) , & idc , NULL ) ;
2022-05-18 23:12:52 +00:00
# else
2022-12-14 05:03:37 +00:00
TTYSetPos ( pos ) ;
2022-05-18 23:12:52 +00:00
ConsoleStd : : WriteStdOutBlocking2 ( in . data ( ) , in . size ( ) ) ;
# endif
}
2022-12-14 01:35:18 +00:00
void TTYConsole : : WriteBufferedEx ( AuPair < AuUInt32 , AuUInt32 > pos , EAnsiColor color , const AuString & in )
{
# if defined(AURORA_IS_MODERNNT_DERIVED)
2024-04-20 01:29:49 +00:00
RecordFunction ( std : : bind ( & TTYConsole : : WriteBufferedEx , this , pos , color , AuString ( in ) ) ) ;
2022-12-14 01:35:18 +00:00
# endif
if ( in . empty ( ) )
{
return ;
}
# if defined(AURORA_IS_MODERNNT_DERIVED)
DWORD idc ;
{
auto hConsole = GetTTYHandle ( ) ;
DWORD attrib { } ;
if ( color ! = EAnsiColor : : eEnumCount )
{
attrib | = kAnsiColorForegroundToNT [ AuStaticCast < AuUInt > ( color ) ] ;
}
else
{
attrib = FOREGROUND_WHITE ;
}
auto line2 = AuLocale : : ConvertFromUTF8 ( in ) ;
2024-04-14 22:11:15 +00:00
pSetConsoleTextAttribute ( hConsole , attrib ) ;
pSetConsoleCursorPosition ( GetTTYHandle ( ) , COORD { AuStaticCast < short > ( pos . first ) , AuStaticCast < short > ( pos . second ) } ) ;
pWriteConsoleW ( hConsole , line2 . data ( ) , AuUInt32 ( line2 . size ( ) ) , & idc , NULL ) ;
pSetConsoleTextAttribute ( hConsole , FOREGROUND_WHITE ) ;
2022-12-14 01:35:18 +00:00
}
//WriteConsoleA(GetTTYHandle(), in.data(), AuUInt32(in.size()), &idc, NULL);
# else
2022-12-14 05:03:37 +00:00
TTYSetPos ( pos ) ;
2022-12-14 01:35:18 +00:00
AuString writeLine ;
const char * pAnsiCode =
2024-03-10 09:45:03 +00:00
static_cast < EAnsiColor > ( color ) < EAnsiColor : : eEnumCount ?
2022-12-14 01:35:18 +00:00
kAnsiColorForegroundToVirtualEscape [ static_cast < AuUInt > ( color ) ] :
" " ;
writeLine = pAnsiCode + in + kAnsiColorForegroundToVirtualEscape [ static_cast < AuUInt > ( EAnsiColor : : eReset ) ] ;
2022-12-16 00:41:01 +00:00
2022-12-14 01:35:18 +00:00
ConsoleStd : : WriteStdOutBlocking2 ( writeLine . data ( ) , writeLine . size ( ) ) ;
# endif
}
2022-05-18 23:12:52 +00:00
void TTYConsole : : RedrawBorders ( )
{
TTYSetPos ( { } ) ;
AuString start ;
AuString end ;
AuString bar ;
AuString startLine ;
AuString midLine ;
AuString endLine ;
startLine . clear ( ) ;
if ( ! UTF8 ( ) )
{
start = " \033 (0 " ;
end = " \033 (B " ;
for ( int i = 0 ; i < currentWidth ; i + + )
{
startLine + = " q " ;
}
midLine = endLine = startLine ;
if ( GetLeftBorder ( ) )
{
startLine [ 0 ] = ' l ' ;
}
if ( GetRightBorder ( ) )
{
startLine [ startLine . size ( ) - 1 ] = ' k ' ;
}
if ( GetLeftBorder ( ) )
{
midLine [ 0 ] = ' t ' ;
}
if ( GetRightBorder ( ) )
{
midLine [ midLine . size ( ) - 1 ] = ' u ' ;
}
if ( GetLeftBorder ( ) )
{
endLine [ 0 ] = ' m ' ;
}
if ( GetRightBorder ( ) )
{
endLine [ endLine . size ( ) - 1 ] = ' j ' ;
}
bar = ' x ' ;
}
else
{
AuString slash = " \xe2 \x94 \x80 " ;
for ( int i = GetLeftBorder ( ) ; i < currentWidth - int ( GetRightBorder ( ) ) ; i + + )
{
startLine + = slash ;
}
midLine = endLine = startLine ;
if ( GetLeftBorder ( ) )
{
startLine = " \xe2 \x94 \x8c " + startLine ;
}
if ( GetRightBorder ( ) )
{
startLine + = " \xe2 \x94 \x90 " ;
}
if ( GetLeftBorder ( ) )
{
midLine = " \xe2 \x94 \x9c " + midLine ;
}
if ( GetRightBorder ( ) )
{
midLine + = " \xe2 \x94 \xa4 " ;
}
if ( GetLeftBorder ( ) )
{
endLine = " \xe2 \x94 \x94 " + endLine ;
}
if ( GetRightBorder ( ) )
{
endLine + = " \xe2 \x94 \x98 " ;
}
bar = " \xe2 \x94 \x82 " ;
}
int height = currentHeight ;
int widthM = currentWidth - 1 ;
// Begin drawing
WriteBuffered ( { } , start ) ;
// Box: top
if ( GetTopBorder ( ) )
{
WriteBuffered ( { } , Stringify ( startLine , this - > headerTitle , true , true , true ) ) ;
}
// Box: sides
for ( int i = GetTopBorder ( ) ; i < height - GetBottomBorder ( ) ; i + + )
{
WriteBuffered ( { 0 , i } , bar ) ;
WriteBuffered ( { widthM , i } , bar ) ;
}
// Box: Bottom
if ( GetBottomBorder ( ) )
{
WriteBuffered ( { 0 , height - 1 } , endLine ) ;
}
// Above hint splitter line
if ( GetLogBoxHintBorder ( ) )
{
int l = this - > GetHintLines ( ) ;
// GetLogBoxHintBorder
WriteBuffered ( { 0 , this - > currentHeight - ( this - > GetBottomBorder ( ) + this - > GetTextInputLines ( ) + this - > topInputPadding + this - > GetLogBoxHintBorder ( ) + ( l ? ( this - > topHintPadding ) : 0 ) ) } , midLine ) ;
}
// Below subhead splitter line
if ( this - > GetBannerFootBorder ( ) )
{
int l = this - > GetBannerLines ( ) ;
if ( l )
{
WriteBuffered ( { 0 , this - > GetTopBorder ( ) + this - > GetBannerLines ( ) } , Stringify ( midLine , this - > logTitle , true , true , true ) ) ;
}
}
// End drawing mode
WriteBuffered ( { } , end ) ;
}
2023-02-17 19:42:30 +00:00
2022-05-18 23:12:52 +00:00
const AuString & TTYConsole : : Stringify ( const AuString & referenceLine , const AlignedString & string , bool spacing , bool brackets , bool extraPadding )
{
if ( string . str . empty ( ) )
{
return referenceLine ;
}
this - > tempMemory = referenceLine ;
int lineWidth = this - > currentWidth ;
int stride = 1 ;
if ( ! referenceLine . empty ( ) )
{
if ( UTF8 ( ) )
{
stride = 3 ;
}
}
// HACK: if non-title, remove borders
// Before i'd drop the first & last char if line == width, but ofc this doesnt work with UTF8, and it'd pretty dumb to rely on an estimated char length
int L { } , R { } ;
if ( ! extraPadding )
{
lineWidth - = GetLeftBorder ( ) * stride ;
lineWidth - = GetRightBorder ( ) * stride ;
}
else
{
// Border offsets, if accounting for them.
L = GetLeftBorder ( ) ;
R = GetRightBorder ( ) ;
}
if ( lineWidth < 0 )
{
this - > tempMemory . clear ( ) ;
return this - > tempMemory ;
}
if ( referenceLine . empty ( ) )
{
this - > tempMemory = AuString ( lineWidth , ' ' ) ;
}
int length = GuessWidth ( string . str ) + ( brackets ? 2 : 0 ) + ( spacing ? 2 : 0 ) ;
if ( length > lineWidth )
{
return referenceLine ;
}
int start { } ;
int padding2 = extraPadding ? 2 : 0 ;
// You're an idiot. you dont need a comment to work out what this does
switch ( string . align )
{
case ETTYAlign : : eLeft :
start = padding2 + L ;
break ;
case ETTYAlign : : eRight :
start = lineWidth - ( R + padding2 + length ) ;
break ;
case ETTYAlign : : eCenter :
start = lineWidth / 2 - ( length / 2 ) ;
break ;
}
if ( start + length + GetRightBorder ( ) > this - > currentWidth )
{
return referenceLine ;
}
// In UTF8 mode, we fill the buffer of characters of a constant stride of 3
start * = stride ;
if ( start > = tempMemory . size ( ) )
{
return referenceLine ;
}
// Brackets
AuString left ;
AuString right ;
if ( brackets )
{
if ( UTF8 ( ) )
{
right = " \xe2 \x94 \x9c " ;
left = " \xe2 \x94 \xa4 " ;
}
else
{
left = " u " ;
right = " t " ;
}
}
// Overhead to enter DEC drawing mode around the brackets on non-utf8 terminals
int DECOverhead = 0 ;
int DECOverheadA = 0 ;
int DECOverheadB = 0 ;
if ( ! UTF8 ( ) )
{
DECOverheadA = DECOverheadB = 3 ;
DECOverhead = DECOverheadA + DECOverheadB ;
}
// kanker
2022-06-14 15:59:37 +00:00
AuUInt toWrite = ( brackets * stride ) + DECOverheadA + spacing + string . str . size ( ) + spacing + DECOverheadB + ( brackets * stride ) ;
AuUInt toSlice = stride * ( ( spacing * 2 ) + ( brackets * 2 ) + string . str . size ( ) ) ;
2022-05-18 23:12:52 +00:00
// brrr
if ( toWrite < = toSlice )
{
// Fast path, pog. We dont need to allocate.
2022-06-14 15:59:37 +00:00
AuUInt strideTwo = brackets * stride ;
2022-05-18 23:12:52 +00:00
if ( toWrite < toSlice )
{
2022-06-14 15:59:37 +00:00
AuUInt second = start + strideTwo + DECOverheadA + spacing + string . str . size ( ) + spacing + DECOverheadB + right . size ( ) ;
AuUInt two = start + ( length * strideTwo ) ;
AuUInt count = this - > tempMemory . size ( ) - two ;
2022-05-18 23:12:52 +00:00
AuMemmove ( this - > tempMemory . data ( ) + second ,
this - > tempMemory . data ( ) + two , this - > tempMemory . size ( ) - two ) ;
this - > tempMemory . resize ( second + count ) ;
}
if ( brackets )
{
AuMemcpy ( this - > tempMemory . data ( ) + start , left . data ( ) , left . size ( ) ) ;
}
if ( spacing )
{
this - > tempMemory . data ( ) [ start + strideTwo + DECOverheadA ] = ' ' ;
}
if ( DECOverheadA )
{
AuMemcpy ( this - > tempMemory . data ( ) + strideTwo + DECOverheadA + spacing , " \033 (B " , 3 ) ;
}
AuMemcpy ( this - > tempMemory . data ( ) + start + strideTwo + DECOverheadA + spacing , string . str . data ( ) , string . str . size ( ) ) ;
if ( spacing )
{
this - > tempMemory . data ( ) [ start + strideTwo + DECOverheadA + spacing + string . str . size ( ) + DECOverheadB ] = ' ' ;
}
if ( DECOverheadB )
{
AuMemcpy ( this - > tempMemory . data ( ) + start + strideTwo + DECOverheadA + spacing + string . str . size ( ) + spacing , " \033 (0 " , 3 ) ;
}
if ( brackets )
{
AuMemcpy ( this - > tempMemory . data ( ) + start + strideTwo + DECOverheadA + spacing + string . str . size ( ) + spacing + DECOverheadB , right . data ( ) , right . size ( ) ) ;
}
}
else
{
// Slow allocation path
auto cpy = this - > tempMemory ; // alloc
AuString & ret = this - > tempMemory ;
auto begin = cpy . empty ( ) ? " " : cpy . substr ( 0 , start ) ; // alloc
auto end = cpy . empty ( ) ? " " : cpy . substr ( start + ( length * stride ) ) ; // alloc
ret = AuMove ( begin ) ;
ret . reserve ( this - > currentWidth * stride ) ;
// potential allocs:
if ( brackets )
{
ret + = left ;
}
if ( DECOverheadA )
{
ret + = " \033 (B " ;
}
if ( spacing )
{
ret + = ' ' ;
}
ret + = string . str ;
if ( spacing )
{
ret + = ' ' ;
}
if ( DECOverheadB )
{
ret + = " \033 (0 " ;
}
if ( brackets )
{
ret + = right ;
}
ret + = AuMove ( end ) ;
return ret ;
}
return this - > tempMemory ;
}
void TTYConsole : : RedrawBanner ( )
{
if ( this - > header . str . size ( ) )
{
WriteLine ( this - > GetTopBorder ( ) +
this - > topHeaderPadding ,
Stringify ( " " , this - > header , false , false , false ) ) ;
}
if ( this - > subheader . str . size ( ) )
{
WriteLine ( this - > GetTopBorder ( ) +
( this - > header . str . size ( ) ? 1 + this - > topHeaderPadding : 0 ) +
( this - > midHeaderPadding ) ,
Stringify ( " " , this - > subheader , false , false , false ) ) ;
}
}
void TTYConsole : : RedrawLogBox ( )
{
auto indexBeforePadding = ( this - > GetBannerFootBorder ( ) ? 1 + this - > topLogPadding : 0 ) + this - > topLogPaddingExtra ;
auto startIndex = this - > GetTopBorder ( ) + this - > GetBannerLines ( ) + indexBeforePadding ;
2022-12-27 15:17:34 +00:00
//auto startIndex2 = this->topLogPaddingExtra + indexBeforePadding;
int drawPos = startIndex ;
2022-05-18 23:12:52 +00:00
auto maxLines = GetLogBoxLines ( ) ;
for ( int i = startIndex + maxLines ; i < this - > currentHeight ; i + + )
{
this - > BlankLine ( i ) ;
}
auto startingLineBufferIndex = 0 ;
if ( iScrollPos = = - 1 )
{
if ( this - > screenBuffer . size ( ) > maxLines )
{
startingLineBufferIndex = this - > screenBuffer . size ( ) - maxLines ;
}
else
{
startingLineBufferIndex = 0 ;
}
}
else
{
startingLineBufferIndex = iScrollPos ;
}
for ( int i = 0 ; i < maxLines ; i + + )
{
auto strIdx = i + startingLineBufferIndex ;
if ( strIdx > = this - > screenBuffer . size ( ) )
{
break ;
}
2022-12-14 01:35:18 +00:00
auto & [ color , message ] = this - > screenBuffer [ strIdx ] ;
WriteBufferedEx ( { GetLeftBorder ( ) + this - > leftLogPadding , i + drawPos } , color , message ) ;
//WriteBuffered({GetLeftBorder() + this->leftLogPadding, i + startIndex}, this->screenBuffer[strIdx].second);
2022-05-18 23:12:52 +00:00
}
}
void TTYConsole : : BlankLogBox ( )
{
}
void TTYConsole : : RedrawInput ( bool clear )
{
int height = this - > currentHeight - ( 1 + this - > GetBottomBorder ( ) ) ;
if ( clear )
{
BlankLine ( height ) ;
}
WriteBuffered ( { this - > GetLeftBorder ( ) + this - > leftPadding , height } , " > " ) ;
if ( clear & & NoncanonicalMode ( ) )
{
2023-02-17 19:42:30 +00:00
this - > inputField . WriteBuffered ( this , { this - > GetLeftBorder ( ) + this - > leftPadding + 1 , height } ) ;
2022-05-18 23:12:52 +00:00
}
}
void TTYConsole : : RedrawHintLine ( )
{
}
int TTYConsole : : GetHintLines ( )
{
return this - > hintStrings . size ( ) ;
}
bool TTYConsole : : GetLogBoxHintBorder ( )
{
return true ;
}
bool TTYConsole : : GetBottomBorder ( )
{
return true ;
}
ETTYAlign TTYConsole : : GetTitleAlignment ( )
{
return this - > headerTitle . align ;
}
ETTYAlign TTYConsole : : SetTitleAlignment ( ETTYAlign newValue )
{
return AuExchange ( this - > headerTitle . align , newValue ) ;
2022-06-14 15:59:37 +00:00
}
2022-05-18 23:12:52 +00:00
ETTYAlign TTYConsole : : GetLogBoxTitleAlignment ( )
{
return this - > logTitle . align ;
}
ETTYAlign TTYConsole : : SetLogBoxTitleAlignment ( ETTYAlign newValue )
{
return AuExchange ( this - > logTitle . align , newValue ) ;
}
ETTYAlign TTYConsole : : GetHeaderAlignment ( )
{
return this - > header . align ;
}
ETTYAlign TTYConsole : : GetSubheaderAlignment ( )
{
return this - > subheader . align ;
}
AuString TTYConsole : : GetHeaderBorderTitle ( )
{
return this - > headerTitle . str ;
}
AuString TTYConsole : : GetLogBoxBorderTitle ( )
{
return this - > logTitle . str ;
}
AuString TTYConsole : : GetHeader ( )
{
return this - > header . str ;
}
AuString TTYConsole : : GetSubHeader ( )
{
return this - > subheader . str ;
}
ETTYAlign TTYConsole : : SetHeaderAlignment ( ETTYAlign newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > header . align , newValue ) ;
}
ETTYAlign TTYConsole : : SetSubheaderAlignment ( ETTYAlign newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > subheader . align , newValue ) ;
}
2024-04-21 05:02:47 +00:00
AuString TTYConsole : : SetHeaderBorderTitle ( const AuROString & newValue )
2022-05-18 23:12:52 +00:00
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > headerTitle . str , newValue ) ;
}
2024-04-21 05:02:47 +00:00
AuString TTYConsole : : SetLogBoxBorderTitle ( const AuROString & newValue )
2022-05-18 23:12:52 +00:00
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > logTitle . str , newValue ) ;
}
2024-04-21 05:02:47 +00:00
AuString TTYConsole : : SetHeader ( const AuROString & newValue )
2022-05-18 23:12:52 +00:00
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > header . str , newValue ) ;
}
2024-04-21 05:02:47 +00:00
AuString TTYConsole : : SetSubHeader ( const AuROString & newValue )
2022-05-18 23:12:52 +00:00
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > subheader . str , newValue ) ;
}
bool TTYConsole : : SetTopBorder ( bool newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > bTopBorder , newValue ) ;
}
bool TTYConsole : : SetLeftBorder ( bool newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > bLeftBorder , newValue ) ;
}
bool TTYConsole : : SetRightBorder ( bool newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > bRightBorder , newValue ) ;
}
int TTYConsole : : GetBannerLines ( )
{
int ret = ! this - > header . str . empty ( ) + ! this - > subheader . str . empty ( ) ;
if ( ! ret )
{
return 0 ;
}
return ret + this - > midHeaderPadding + ( this - > header . str . size ( ) ? this - > topHeaderPadding : 0 ) + ( this - > subheader . str . size ( ) ? this - > bottomSubHeaderPadding : 0 ) ;
}
int TTYConsole : : GetLogBoxLines ( )
{
int hintLines = this - > GetHintLines ( ) ;
int bannerLines = this - > GetBannerLines ( ) ;
//
return this - > currentHeight - ( this - > GetTopBorder ( ) +
//////////////////
bannerLines +
//////////////////
( bannerLines ? 1 /* splitter */ + this - > topLogPadding : 0 ) +
this - > topLogPaddingExtra +
GetLogBoxHintBorder ( ) +
//////////////////////////////
1 +
( bool ( hintLines ) ? ( hintLines + this - > topHintPadding ) : 0 ) +
this - > topInputPadding +
//////////////////////////////
this - > GetTextInputLines ( ) +
//////////////////////////////
this - > GetBottomBorder ( ) ) ;
}
int TTYConsole : : GetTextInputLines ( )
{
return 1 ;
}
bool TTYConsole : : GetBannerFootBorder ( )
{
return this - > header . str . size ( ) | | this - > subheader . str . size ( ) ;
}
bool TTYConsole : : GetTopBorder ( )
{
return this - > bTopBorder ;
}
bool TTYConsole : : GetRightBorder ( )
{
return this - > bRightBorder ;
}
bool TTYConsole : : GetLeftBorder ( )
{
return this - > bLeftBorder ;
}
bool TTYConsole : : NoncanonicalMode ( )
{
2022-08-04 19:29:41 +00:00
return ConsoleStd : : IsStdOutTTY ( ) ;
2022-05-18 23:12:52 +00:00
}
bool TTYConsole : : PermitDoubleBuffering ( )
{
// We can't double buffer and not share the input line between two framebuffers
# if defined(AURORA_IS_MODERNNT_DERIVED)
return NoncanonicalMode ( ) ;
# endif
return true ;
}
AuPair < AuUInt32 , AuUInt32 > TTYConsole : : GetLogBoxStart ( )
{
return { this - > GetLeftBorder ( ) , this - > GetTopBorder ( ) + this - > GetBannerLines ( ) + this - > GetBannerFootBorder ( ) } ;
}
AuPair < AuUInt32 , AuUInt32 > TTYConsole : : GetHintLine ( )
{
int hintLines = this - > GetHintLines ( ) ;
return { this - > GetLeftBorder ( ) , this - > currentHeight - ( 1 + hintLines + bool ( hintLines ) + this - > GetBottomBorder ( ) + this - > GetTextInputLines ( ) ) } ;
}
AuPair < AuUInt32 , AuUInt32 > TTYConsole : : GetInputCursor ( )
{
if ( ! this - > NoncanonicalMode ( ) )
{
return { this - > GetLeftBorder ( ) + this - > leftPadding + 1 + this - > leftInputPadding , this - > currentHeight - ( 1 + this - > GetBottomBorder ( ) ) } ;
}
2023-02-17 19:42:30 +00:00
return { this - > GetLeftBorder ( ) + this - > leftPadding + 1 + this - > leftInputPadding + ( this - > inputField . noncanonicalCursorPos = = - 1 ? 0 : this - > inputField . noncanonicalCursorPos ) /*:(*/ , this - > currentHeight - ( 1 + this - > GetBottomBorder ( ) ) } ; // { i do not like this, ...}
2022-05-18 23:12:52 +00:00
}
AuPair < AuUInt32 , AuUInt32 > TTYConsole : : GetInitialInputLine ( )
{
return { } ;
}
void TTYConsole : : NoncanonicalSetCursor ( )
{
TTYSetPos ( this - > GetInputCursor ( ) ) ;
}
void TTYConsole : : SetHintStrings ( const AuList < AuPair < AuString /*autocompletion*/ , AuList < AuString /* secondary hint*/ > > > & hints )
{
this - > hintStrings = AuMove ( hints ) ;
}
bool TTYConsole : : CheckRedraw ( )
{
return { } ;
}
void TTYConsole : : SetInitialCursorPos ( )
{
}
void TTYConsole : : PostRedraw ( bool first )
{
if ( first )
{
SetInitialCursorPos ( ) ;
//AuConsole::TTYSetPos()
}
else if ( NoncanonicalMode ( ) )
{
}
}
AuUInt8 TTYConsole : : SetPaddingLeftOfLog ( AuUInt8 newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > leftLogPadding , newValue ) ;
}
AuUInt8 TTYConsole : : SetPaddingRightOfLog ( AuUInt8 newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > rightLogPadding , newValue ) ;
}
AuUInt8 TTYConsole : : SetPaddingLeftOfInput ( AuUInt8 newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > leftInputPadding , newValue ) ;
}
AuUInt8 TTYConsole : : SetPaddingTopOfInput ( AuUInt8 newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > topInputPadding , newValue ) ;
}
AuUInt8 TTYConsole : : SetPaddingTopOfHint ( AuUInt8 newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > topHintPadding , newValue ) ;
}
AuUInt8 TTYConsole : : SetPaddingTopOfHeader ( AuUInt8 newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > topHeaderPadding , newValue ) ;
}
AuUInt8 TTYConsole : : SetPaddingMidOfHeader ( AuUInt8 newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > midHeaderPadding , newValue ) ;
}
AuUInt8 TTYConsole : : SetPaddingBottomOfSubheader ( AuUInt8 newValue )
{
this - > bTriggerRedraw = true ;
return AuExchange ( this - > bottomSubHeaderPadding , newValue ) ;
}
AuUInt8 TTYConsole : : GetPaddingLeftOfLog ( )
{
return this - > leftLogPadding ;
}
AuUInt8 TTYConsole : : GetPaddingRightOfLog ( )
{
return this - > rightLogPadding ;
}
AuUInt8 TTYConsole : : GetPaddingLeftOfInput ( )
{
return this - > leftInputPadding ;
}
AuUInt8 TTYConsole : : GetPaddingTopOfInput ( )
{
return this - > topInputPadding ;
}
AuUInt8 TTYConsole : : GetPaddingTopOfHint ( )
{
return this - > topHintPadding ;
}
AuUInt8 TTYConsole : : GetPaddingTopOfHeader ( )
{
return this - > topHeaderPadding ;
}
AuUInt8 TTYConsole : : GetPaddingMidOfHeader ( )
{
return this - > midHeaderPadding ;
}
AuUInt8 TTYConsole : : GetPaddingBottomOfSubheader ( )
{
return this - > bottomSubHeaderPadding ;
}
2022-06-14 17:33:34 +00:00
AuUInt8 TTYConsole : : SetPaddingHeadOfLog ( AuUInt8 newValue )
2022-06-11 23:01:27 +00:00
{
return AuExchange ( this - > topLogPadding , newValue ) ;
}
2022-06-14 17:33:34 +00:00
AuUInt8 TTYConsole : : SetPaddingTopOfLog ( AuUInt8 newValue )
2022-06-11 23:01:27 +00:00
{
return AuExchange ( this - > topLogPaddingExtra , newValue ) ;
}
AuUInt8 TTYConsole : : GetPaddingHeadOfLog ( )
{
return this - > topLogPadding ;
}
AuUInt8 TTYConsole : : GetPaddingTopOfLog ( )
{
return this - > topLogPaddingExtra ;
}
2022-05-18 23:12:52 +00:00
2022-11-28 16:01:08 +00:00
static void MainTTY ( )
{
while ( AuIsThreadRunning ( ) )
{
2023-12-18 01:42:50 +00:00
#if 0
2023-10-28 19:12:28 +00:00
if ( auto pLoopSource = AuConsole : : StdInBufferLoopSource ( ) )
{
pLoopSource - > WaitOn ( 1000 / 20 ) ;
}
else
{
AuThreading : : Sleep ( 1000 / 20 ) ;
}
2023-12-18 01:42:50 +00:00
# else
if ( auto pLoopSource = ConsoleStd : : GetLoopSourceConTTY ( ) )
{
if ( gTTYConsole . uxModeFlipped )
{
pLoopSource - > WaitOn ( 5000 ) ;
}
else
{
pLoopSource - > WaitOn ( 500 ) ;
}
}
else
{
AuThreading : : Sleep ( 1000 / 20 ) ;
}
# endif
2023-12-22 00:34:30 +00:00
try
{
gTTYConsole . Pump ( ) ;
}
catch ( . . . )
{
SysPushErrorCatch ( ) ;
}
2022-11-28 16:01:08 +00:00
}
}
2022-05-18 23:12:52 +00:00
void Init ( )
{
2023-06-28 09:33:12 +00:00
if ( ! gRuntimeConfig . console . enableConsole )
{
return ;
}
2022-05-18 23:12:52 +00:00
gTTYConsole . Init ( ) ;
2022-11-28 16:01:08 +00:00
2023-06-28 09:33:12 +00:00
if ( gMultiThreadTTY & & ! gConsoleTTYThread )
2022-11-28 16:01:08 +00:00
{
gConsoleTTYThread = AuThreads : : ThreadUnique ( AuThreads : : ThreadInfo (
AuMakeShared < AuThreads : : IThreadVectorsFunctional > ( AuThreads : : IThreadVectorsFunctional : : OnEntry_t ( std : : bind ( MainTTY ) ) ,
AuThreads : : IThreadVectorsFunctional : : OnExit_t { } ) ,
" ConsoleTTY pumper (win32 is slow as shit ok?) "
) ) ;
if ( ! gConsoleTTYThread )
{
gMultiThreadTTY = false ;
return ;
}
gConsoleTTYThread - > SetThrottle ( AuThreads : : EThreadThrottle : : eEfficient ) ;
gConsoleTTYThread - > SetPriority ( AuThreads : : EThreadPriority : : ePrioHigh ) ;
gConsoleTTYThread - > Run ( ) ;
}
2022-05-18 23:12:52 +00:00
}
void Exit ( )
{
gTTYConsole . Deinit ( ) ;
}
void WriteTTYOut ( const AuConsole : : ConsoleMessage & msg )
{
gTTYConsole . BufferMessage ( msg ) ;
}
2022-12-14 20:08:52 +00:00
void WriteTTYOut ( const AuConsole : : ConsoleMessage & msg , const AuString & input )
{
gTTYConsole . BufferMessage ( msg , input ) ;
}
2022-05-18 23:12:52 +00:00
void Pump ( )
{
2022-11-28 16:01:08 +00:00
// :(
if ( ! gMultiThreadTTY )
{
gTTYConsole . Pump ( ) ;
}
2022-05-18 23:12:52 +00:00
}
2022-11-30 11:11:18 +00:00
void PumpForce ( )
{
2023-06-28 09:33:12 +00:00
// no more force deinit for.now:
2023-02-06 05:14:01 +00:00
gConsoleTTYThread . reset ( ) ;
2022-11-30 11:11:18 +00:00
gTTYConsole . Pump ( ) ;
}
2022-05-18 23:12:52 +00:00
AUKN_SYM AuSPtr < ITTYConsole > GetTTYConsole ( )
{
return AuUnsafeRaiiToShared < ITTYConsole > ( & gTTYConsole ) ;
}
void OnEnter ( )
{
if ( gTTYConsoleEnabled )
{
gTTYConsole . OnEnter ( ) ;
}
}
# else
2022-08-09 00:55:18 +00:00
2022-05-18 23:12:52 +00:00
void Init ( )
{
}
void Pump ( )
{
}
2022-11-30 11:11:18 +00:00
void PumpForce ( )
{
}
2022-05-18 23:12:52 +00:00
void Exit ( )
{
}
2022-12-14 20:08:52 +00:00
void WriteTTYOut ( const AuConsole : : ConsoleMessage & msg , const AuString & input )
2022-05-18 23:12:52 +00:00
{
}
AUKN_SYM AuSPtr < ITTYConsole > GetTTYConsole ( )
{
return { } ;
}
void OnEnter ( )
{
}
# endif
}