From a02c5397f53333681a0233b87ae51fcbd5166c23 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 8 Sep 2013 22:30:12 +0800 Subject: [PATCH] Usermode/GUI Terminal - Added scrolling and cursor/save restore - IRC client now starts (... glitches out a heap tho) --- .../Applications/gui_terminal_src/display.c | 224 +++++++++++++++--- .../gui_terminal_src/include/display.h | 4 + .../Applications/gui_terminal_src/vt100.c | 25 +- 3 files changed, 215 insertions(+), 38 deletions(-) diff --git a/Usermode/Applications/gui_terminal_src/display.c b/Usermode/Applications/gui_terminal_src/display.c index f067129d..6d23898a 100644 --- a/Usermode/Applications/gui_terminal_src/display.c +++ b/Usermode/Applications/gui_terminal_src/display.c @@ -18,6 +18,9 @@ #define UNIMPLIMENTED() do{_SysDebug("UNIMPLIMENTED %s", __func__); exit(-1);}while(0) +static inline int MIN(int a, int b) { return (a < b ? a : b); } +static inline int MAX(int a, int b) { return (a > b ? a : b); } + // === EXTERN == extern tHWND gMainWindow; @@ -35,12 +38,19 @@ struct sTerminal { int ViewCols; int ViewRows; + int ScrollTop; + int ScrollRows; + int CursorRow; int CursorCol; + int SavedRow; + int SavedCol; + size_t CursorByte; bool bUsingAltBuf; + bool bHaveSwappedBuffers; size_t ViewOffset; size_t TotalLines; @@ -97,6 +107,7 @@ size_t _GetCharLength(size_t AvailLength, const char *Text, uint32_t *BaseCodepo tLine *Display_int_GetCurLine(tTerminal *Term) { int lineidx = Term->CursorRow + (Term->bUsingAltBuf ? 0 : Term->ViewOffset); + //_SysDebug("lineidx = %i", lineidx); return (Term->bUsingAltBuf ? Term->AltBuf : Term->PriBuf) + lineidx; } @@ -110,6 +121,8 @@ size_t Display_int_PushCharacter(tTerminal *Term, size_t AvailLength, const char // Figure out how much we need to shift the stream int shift; if( bOverwrite ) { + //_SysDebug("GetCharLen(%i-%i, %p+%i, NULL)", lineptr->Len, Term->CursorByte, + // lineptr->Data, Term->CursorByte); size_t nextlen = _GetCharLength( lineptr->Len-Term->CursorByte, lineptr->Data+Term->CursorByte, @@ -124,10 +137,13 @@ size_t Display_int_PushCharacter(tTerminal *Term, size_t AvailLength, const char if( !lineptr->Data || shift > 0 ) { const size_t size_step = 64; assert(shift > 0); - lineptr->Size = (lineptr->Len+shift+1 + size_step-1) & ~(size_step-1); - void *tmp = realloc(lineptr->Data, lineptr->Size); - if( !tmp ) perror("Display_int_PushCharacter - realloc"); - lineptr->Data = tmp; + size_t newsize = (lineptr->Len+shift+1 + size_step-1) & ~(size_step-1); + if( newsize > lineptr->Size ) { + lineptr->Size = newsize; + void *tmp = realloc(lineptr->Data, lineptr->Size); + if( !tmp ) perror("Display_int_PushCharacter - realloc"); + lineptr->Data = tmp; + } } // Insert into stream @@ -160,7 +176,7 @@ size_t Display_int_PushCharacter(tTerminal *Term, size_t AvailLength, const char void Display_AddText(tTerminal *Term, size_t Length, const char *UTF8Text) { - //_SysDebug("%i '%.*s'", Length, Length, UTF8Text); + _SysDebug("%i '%.*s'", Length, Length, UTF8Text); while( Length > 0 ) { size_t used = Display_int_PushCharacter(Term, Length, UTF8Text); @@ -177,40 +193,159 @@ void Display_AddText(tTerminal *Term, size_t Length, const char *UTF8Text) void Display_Newline(tTerminal *Term, bool bCarriageReturn) { -// Display_Flush(); - // Going down! - Term->CursorRow ++; - if( Term->CursorRow == Term->TotalLines ) { - // TODO: Scrolling + if( Term->bUsingAltBuf ) + { + if( Term->CursorRow == Term->ScrollTop + Term->ScrollRows-1 ) { + Display_ScrollDown(Term, 1); + } + else if( Term->CursorRow == Term->ViewRows-1 ) { + if( Term->ScrollRows == 0 ) { + // Scroll entire buffer + Display_ScrollDown(Term, 1); + } + else { + // Don't go down a line + Term->CursorRow --; + } + } + else { + // No scroll needed + } + } + else + { + if( Term->CursorRow == Term->TotalLines-1 ) { + Display_ScrollDown(Term, 1); + } } + Term->CursorRow ++; - if( bCarriageReturn ) { + if( bCarriageReturn ) + { Term->CursorByte = 0; Term->CursorCol = 0; - return ; } + else + { + tLine *line = Display_int_GetCurLine(Term); + + Term->CursorByte = 0; + int old_col = Term->CursorCol; + Term->CursorCol = 0; - tLine *line = Display_int_GetCurLine(Term); + size_t ofs = 0; + while( Term->CursorCol < old_col && ofs < line->Len ) { + ofs += _GetCharLength(line->Len-ofs, line->Data+ofs, NULL); + Term->CursorCol ++; + } + Term->CursorByte = ofs; + + while( Term->CursorCol < old_col ) + Display_AddText(Term, 1, " "); + } +} + +void Display_SetScrollArea(tTerminal *Term, int Start, int Count) +{ + assert(Start >= 0); + assert(Count >= 0); + Term->ScrollTop = Start; + Term->ScrollRows = MIN(Count, Term->ViewRows - Start); +} + +void Display_ScrollDown(tTerminal *Term, int Count) +{ + int top, max; + tLine *buffer; + + if( Term->bUsingAltBuf ) + { + top = (Term->ScrollRows == 0 ? 0 : Term->ScrollTop); + max = (Term->ScrollRows == 0 ? Term->ViewRows : Term->ScrollRows); + buffer = Term->AltBuf; + } + else + { + top = 0; + max = Term->TotalLines; + buffer = Term->PriBuf; + } - Term->CursorByte = 0; - int old_col = Term->CursorCol; - Term->CursorCol = 0; + assert(Count < max); + assert(Count > -max); - size_t ofs = 0; - while( Term->CursorCol < old_col && ofs < line->Len ) { - ofs += _GetCharLength(line->Len-ofs, line->Data+ofs, NULL); - Term->CursorCol ++; + _SysDebug("Scroll %p %i-%i down by %i", buffer, top, max, Count); + + buffer += top; + + if( Term->CursorRow >= top && Term->CursorRow < top+max ) { + Term->CursorRow -= Count; + Term->CursorRow = MAX(Term->CursorRow, top); + Term->CursorRow = MIN(Term->CursorRow, top+max); } - Term->CursorByte = ofs; - while( Term->CursorCol < old_col ) - Display_AddText(Term, 1, " "); + int clear_top, clear_max; + if( Count < 0 ) + { + // -ve: Scroll up, move buffer contents down + Count = -Count; + memmove(buffer+Count, buffer, (max-Count)*sizeof(*buffer)); + + clear_top = 0; + clear_max = Count; + } + else + { + memmove(buffer, buffer+Count, (max-Count)*sizeof(*buffer)); + clear_top = max-Count; + clear_max = max; + } + // Clear exposed lines + for( int i = clear_top; i < clear_max; i ++ ) + { + free(buffer[i].Data); + buffer[i].Data = NULL; + buffer[i].Len = 0; + buffer[i].Size = 0; + buffer[i].IsDirty = true; + if( Term->CursorRow == i ) { + Term->CursorCol = 0; + Term->CursorByte = 0; + } + } } void Display_SetCursor(tTerminal *Term, int Row, int Col) { - UNIMPLIMENTED(); + assert(Row >= 0); + assert(Col >= 0); + + _SysDebug("Set cursor R%i,C%i", Row, Col); + + if( !Term->bUsingAltBuf ) { + _SysDebug("NOTE: Using \\e[%i;%iH outside of alternat buffer is undefined", Row, Col); + } + + // NOTE: This may be interesting outside of AltBuffer + Term->CursorRow = Row; + + tLine *line = Display_int_GetCurLine(Term); + size_t ofs = 0; + for( int i = 0; i < Col; i ++ ) + { + + size_t clen = _GetCharLength(line->Len-ofs, line->Data+ofs, NULL); + if( clen == 0 ) { + // TODO: Should moving the cursor up to an unoccupied cell cause a jump? + Col = i; + break; + } + ofs += clen; + } + + Term->CursorCol = Col; + Term->CursorByte = ofs; } void Display_MoveCursor(tTerminal *Term, int RelRow, int RelCol) @@ -243,6 +378,16 @@ void Display_MoveCursor(tTerminal *Term, int RelRow, int RelCol) } } +void Display_SaveCursor(tTerminal *Term) +{ + Term->SavedRow = Term->CursorRow; + Term->SavedCol = Term->CursorCol; +} +void Display_RestoreCursor(tTerminal *Term) +{ + Display_SetCursor(Term, Term->SavedRow, Term->SavedCol); +} + void Display_ClearLine(tTerminal *Term, int Dir) // 0: All, 1: Forward, -1: Reverse { if( Dir == 0 ) @@ -305,21 +450,40 @@ void Display_SetBackground(tTerminal *Term, uint32_t RGB) void Display_Flush(tTerminal *Term) { + int viewOfs = (Term->bUsingAltBuf ? 0 : Term->ViewOffset); + tLine *buffer = (Term->bUsingAltBuf ? Term->AltBuf : Term->PriBuf ); for( int i = 0; i < Term->ViewRows; i ++ ) { - int line = (Term->ViewOffset + i) % Term->TotalLines; - tLine *lineptr = &Term->PriBuf[line]; - if( !lineptr->IsDirty ) + int line = (viewOfs + i) % Term->TotalLines; + tLine *lineptr = &buffer[line]; + // Swapping buffers should cause a full resend + if( !Term->bHaveSwappedBuffers && !lineptr->IsDirty ) continue; - _SysDebug("Line %i+%i '%.*s'", Term->ViewOffset, i, lineptr->Len, lineptr->Data); - AxWin3_RichText_SendLine(gMainWindow, Term->ViewOffset + i, lineptr->Data ); + _SysDebug("Line %i+%i '%.*s'", viewOfs, i, lineptr->Len, lineptr->Data); + AxWin3_RichText_SendLine(gMainWindow, viewOfs + i, + lineptr->Data ? lineptr->Data : "" ); lineptr->IsDirty = 0; } AxWin3_RichText_SetCursorPos(gMainWindow, Term->CursorRow, Term->CursorCol); + Term->bHaveSwappedBuffers = false; } void Display_ShowAltBuffer(tTerminal *Term, bool AltBufEnabled) { - UNIMPLIMENTED(); + if( Term->bUsingAltBuf == AltBufEnabled ) + { + // Nothing to do, so do nothing + return ; + } + + Term->bUsingAltBuf = AltBufEnabled; + Term->bHaveSwappedBuffers = true; + if( AltBufEnabled ) + { + if( !Term->AltBuf ) + { + Term->AltBuf = calloc( sizeof(Term->AltBuf[0]), Term->ViewRows ); + } + } } diff --git a/Usermode/Applications/gui_terminal_src/include/display.h b/Usermode/Applications/gui_terminal_src/include/display.h index 26601fe1..cab762cb 100644 --- a/Usermode/Applications/gui_terminal_src/include/display.h +++ b/Usermode/Applications/gui_terminal_src/include/display.h @@ -18,8 +18,12 @@ extern tTerminal *Display_Init(int Cols, int Lines, int ExtraScrollbackLines); extern void Display_AddText(tTerminal *Term, size_t Length, const char *UTF8Text); extern void Display_Newline(tTerminal *Term, bool bCarriageReturn); +extern void Display_SetScrollArea(tTerminal *Term, int Start, int Count); // Only valid in AltBuffer +extern void Display_ScrollDown(tTerminal *Term, int Count); extern void Display_SetCursor(tTerminal *Term, int Row, int Col); extern void Display_MoveCursor(tTerminal *Term, int RelRow, int RelCol); +extern void Display_SaveCursor(tTerminal *Term); +extern void Display_RestoreCursor(tTerminal *Term); extern void Display_ClearLine(tTerminal *Term, int Dir); // 0: All, 1: Forward, -1: Reverse extern void Display_ClearLines(tTerminal *Term, int Dir); // 0: All, 1: Forward, -1: Reverse extern void Display_SetForeground(tTerminal *Term, uint32_t RGB); diff --git a/Usermode/Applications/gui_terminal_src/vt100.c b/Usermode/Applications/gui_terminal_src/vt100.c index cad41194..2f473a9a 100644 --- a/Usermode/Applications/gui_terminal_src/vt100.c +++ b/Usermode/Applications/gui_terminal_src/vt100.c @@ -11,6 +11,7 @@ #include "include/display.h" #include // isalpha #include // _SysDebug +#include const uint32_t caVT100Colours[] = { // Black, Red, Green, Yellow, Blue, Purple, Cyan, Gray @@ -59,6 +60,7 @@ int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf) if( ret != 0 ) { inc_len = 0; + assert(ret > old_inc_len); ret -= old_inc_len; // counter cached bytes } return ret; @@ -67,9 +69,9 @@ int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf) switch( *Buf ) { case '\b': - Display_MoveCursor(Term, -1, 0); + Display_MoveCursor(Term, 0, -1); Display_AddText(Term, 1, " "); - Display_MoveCursor(Term, -1, 0); + Display_MoveCursor(Term, 0, -1); // TODO: Need to handle \t and ^A-Z return 1; case '\t': @@ -79,7 +81,7 @@ int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf) Display_Newline(Term, 1); return 1; case '\r': - Display_MoveCursor(Term, INT_MIN, 0); + Display_MoveCursor(Term, 0, INT_MIN); return 1; } @@ -140,8 +142,9 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) // Get Command if( !isalpha(c) ) { // Bother. - _SysDebug("Unexpected char 0x%x in VT100 escape code", c); - return 1; + _SysDebug("Unexpected char 0x%x in VT100 escape code '\\e[%.*s'", c, + Len, Buffer); + return j; } if( bQuestionMark ) @@ -192,7 +195,7 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) _SysDebug("TODO: VT100 %i J", args[0]); break; case 'T': // Scroll down n=1 - _SysDebug("TODO: \\x1B[nT - Scroll down"); + Display_ScrollDown(Term, 1); break; case 'm': if( argc == 0 ) @@ -223,8 +226,14 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) break; // Set scrolling region case 'r': - _SysDebug("TODO: \\x1B[%i;%ir - Set Scroll Region", - args[0], args[1]); + Display_SetScrollArea(Term, args[0], args[1]); + break; + + case 's': + Display_SaveCursor(Term); + break; + case 'u': + Display_RestoreCursor(Term); break; default: _SysDebug("Unknown VT100 long escape char 0x%x '%c'", c, c); -- 2.20.1