Kernel/VTerm - Fix scroll in alt buffer
[tpg/acess2.git] / KernelLand / Kernel / drv / vterm_termbuf.c
index b6aff95..fed577a 100644 (file)
@@ -5,8 +5,18 @@
  * drv/vterm_termbuf.c
  * - Virtual Terminal - Terminal buffer manipulation
  */
+#define DEBUG  0
+#define DEBUG_CHECKHEAP        0
 #include "vterm.h"
 
+#if DEBUG_CHECKHEAP
+# define HEAP_VALIDATE()       Heap_Validate()
+#else
+# define HEAP_VALIDATE()       do{}while(0)
+#endif
+
+extern int     Term_HandleVT100(tVTerm *Term, int Len, const char *Buf);
+
 // === CODE ===
 
 /**
  */
 void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
 {
-       Uint32  val;
-        int    i;
-       
        // Iterate
-       for( i = 0; i < Count; i++ )
+       for( int ofs = 0; ofs < Count; )
        {
-               // Handle escape sequences
-               if( Buffer[i] == 0x1B )
-               {
-                       i ++;
-                       i += VT_int_ParseEscape(Term, (const char*)&Buffer[i]) - 1;
-                       continue;
+               int esc_len = Term_HandleVT100(Term, Count - ofs, (const void*)(Buffer + ofs));
+               if( esc_len < 0 ) {
+                       esc_len = -esc_len;
+                       //LOG("%i '%*C'", esc_len, esc_len, Buffer+ofs);
+                       LOG("%i '%.*s'", esc_len, esc_len, Buffer+ofs);
+                       VT_int_PutRawString(Term, Buffer + ofs, esc_len);
+                       //Debug("Raw string '%.*s'", esc_len, Buffer+ofs);
                }
-               
-               // Fast check for non UTF-8
-               if( Buffer[i] < 128 )   // Plain ASCII
-                       VT_int_PutChar(Term, Buffer[i]);
-               else {  // UTF-8
-                       i += ReadUTF8(&Buffer[i], &val) - 1;
-                       VT_int_PutChar(Term, val);
+               else {
+                       //Debug("Escape code '%.*s'", esc_len, Buffer+ofs);
                }
+               ASSERTCR(esc_len, >, 0, );
+               ofs += esc_len;
        }
        // Update Screen
-       VT_int_UpdateScreen( Term, 0 );
+       VT_int_UpdateScreen( Term, 1 );
+}
+
+void VT_int_PutRawString(tVTerm *Term, const Uint8 *String, size_t Bytes)
+{
+       for( int i = 0; i < Bytes; ) {
+               Uint32  val;
+               i += ReadUTF8(String+i, &val);
+               VT_int_PutChar(Term, val);
+       }
 }
 
 /**
@@ -48,37 +62,80 @@ void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
 void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
 {
         int    i;
-       tVT_Char        *buffer;
-        int    write_pos;
        
-       if(Term->Flags & VT_FLAG_ALTBUF) {
-               buffer = Term->AltBuf;
-               write_pos = Term->AltWritePos;
+       HEAP_VALIDATE();
+       
+       const size_t    maxrows = VT_int_GetBufferRows(Term);
+       const size_t    limit = maxrows * Term->TextWidth;
+       tVT_Pos *wrpos = VT_int_GetWritePosPtr(Term);
+       tVT_Char        *buffer = (Term->Flags & VT_FLAG_ALTBUF ? Term->AltBuf : Term->Text);
+
+       // If writing with the cursor on righthand edge, wrap down to next line
+       // TODO: Wrap to same line?
+       if( wrpos->Col >= Term->TextWidth )
+       {
+               ASSERTC(wrpos->Col, <=, Term->TextWidth);
+               VT_int_UpdateScreen( Term, 0 );
+               //wrpos->Row ++;
+               wrpos->Col = 0;
        }
-       else {
-               buffer = Term->Text;
-               write_pos = Term->WritePos;
+
+       // Scroll entire buffer (about to write outside limit)
+       if( wrpos->Row >= maxrows )
+       {
+               ASSERTC(wrpos->Row, <, maxrows + 1);
+               VT_int_ScrollText(Term, 1);
+               wrpos->Row --;
        }
-       
+
+       // Bring written cell into view
+       if( !(Term->Flags & VT_FLAG_ALTBUF) )
+       {
+               if( wrpos->Row >= Term->ViewTopRow + Term->TextHeight )
+               {
+                       size_t  new_pos = wrpos->Row - (Term->TextHeight - 1);
+                       size_t  count = new_pos - Term->ViewTopRow;
+                       VT_int_ScrollFramebuffer(Term, count);
+                       //Debug("VT_int_PutChar: VScroll down to %i", new_pos);
+                       Term->ViewTopRow = new_pos;
+               }
+               else if( wrpos->Row < Term->ViewTopRow )
+               {
+                       size_t  new_pos = wrpos->Row;
+                       size_t  count = Term->ViewTopRow - new_pos;
+                       VT_int_ScrollFramebuffer(Term, -count);
+                       //Debug("VT_int_PutChar: VScroll up to %i", new_pos);
+                       Term->ViewTopRow = new_pos;
+               }
+               else
+               {
+                       // no action, cell is visible
+               }
+       }
+
+       size_t  write_pos = wrpos->Row * Term->TextWidth + wrpos->Col;
+       ASSERTC(write_pos, <, limit);
+
        switch(Ch)
        {
-       case '\0':      return; // Ignore NULL byte
+       case '\0':      // Ignore NULL byte
+               return;
        case '\n':
                VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining
-               write_pos += Term->TextWidth;
+               wrpos->Row ++;
+               // TODO: Force scroll?
        case '\r':
-               write_pos -= write_pos % Term->TextWidth;
+               wrpos->Col = 0;
                break;
        
        case '\t': {
-               int line = write_pos / Term->TextWidth;
-               write_pos %= Term->TextWidth;
+               size_t  col = wrpos->Col;
                do {
                        buffer[ write_pos ].Ch = '\0';
                        buffer[ write_pos ].Colour = Term->CurColour;
                        write_pos ++;
-               } while(write_pos & 7);
-               write_pos += line * Term->TextWidth;
+                       col ++;
+               } while( (col & 7) && col < Term->TextWidth );
                break; }
        
        case '\b':
@@ -101,6 +158,7 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
                } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0');
                if(buffer[ write_pos ].Ch != '\0')
                        write_pos ++;
+               wrpos->Col = write_pos % Term->TextWidth;
                break;
        
        default:
@@ -110,47 +168,15 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
                if( (write_pos + 1) % Term->TextWidth == 0 )
                        VT_int_UpdateScreen( Term, 0 );
                write_pos ++;
+               wrpos->Col ++;
                break;
        }
        
-       if(Term->Flags & VT_FLAG_ALTBUF)
-       {
-               Term->AltWritePos = write_pos;
-               
-               if(Term->AltWritePos >= Term->TextWidth*Term->TextHeight)
-               {
-                       Term->AltWritePos -= Term->TextWidth;
-                       VT_int_ScrollText(Term, 1);
-               }
-               
-       }
-       else
-       {
-               Term->WritePos = write_pos;
-               // Move Screen
-               // - Check if we need to scroll the entire scrollback buffer
-               if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1))
-               {
-                        int    base;
-                       
-                       // Update view position
-                       base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback);
-                       if(Term->ViewPos < base)
-                               Term->ViewPos += Term->Width;
-                       if(Term->ViewPos > base)
-                               Term->ViewPos = base;
-                       
-                       VT_int_ScrollText(Term, 1);
-                       Term->WritePos -= Term->TextWidth;
-               }
-               // Ok, so we only need to scroll the screen
-               else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight)
-               {
-                       VT_int_ScrollFramebuffer( Term, 1 );
-                       
-                       Term->ViewPos += Term->TextWidth;
-               }
-       }
+       ASSERTC(write_pos, <=, limit);
+
+       HEAP_VALIDATE();
+       
+       // TODO: Schedule a delayed screen update
        
        //LEAVE('-');
 }
@@ -158,64 +184,60 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
 void VT_int_ScrollText(tVTerm *Term, int Count)
 {
        tVT_Char        *buf;
-        int    height, init_write_pos;
-        int    len, i;
         int    scroll_top, scroll_height;
+       
+       HEAP_VALIDATE();
 
        // Get buffer pointer and attributes    
+       size_t  height = VT_int_GetBufferRows(Term);
+       tVT_Pos *wrpos = VT_int_GetWritePosPtr(Term);
+       
        if( Term->Flags & VT_FLAG_ALTBUF )
        {
                buf = Term->AltBuf;
-               height = Term->TextHeight;
-               init_write_pos = Term->AltWritePos;
                scroll_top = Term->ScrollTop;
                scroll_height = Term->ScrollHeight;
        }
        else
        {
                buf = Term->Text;
-               height = Term->TextHeight*(giVT_Scrollback+1);
-               init_write_pos = Term->WritePos;
                scroll_top = 0;
                scroll_height = height;
        }
+       
+       const tVT_Pos init_wrpos = *wrpos;
 
        // Scroll text upwards (more space at bottom)
        if( Count > 0 )
        {
-                int    base;
-       
                // Set up
                if(Count > scroll_height)       Count = scroll_height;
-               base = Term->TextWidth*(scroll_top + scroll_height - Count);
-               len = Term->TextWidth*(scroll_height - Count);
+               size_t  chars = Term->TextWidth*Count;
+               size_t  base = Term->TextWidth*scroll_top;
+               size_t  len = Term->TextWidth*(scroll_height - Count);
                
                // Scroll terminal cache
-               memmove(
-                       &buf[Term->TextWidth*scroll_top],
-                       &buf[Term->TextWidth*(scroll_top+Count)],
-                       len*sizeof(tVT_Char)
-                       );
+               ASSERTC( base + chars + len, <=, Term->TextWidth*height );
+               memmove( &buf[base], &buf[base+chars], len*sizeof(tVT_Char) );
+               
                // Clear last rows
-               for( i = 0; i < Term->TextWidth*Count; i ++ )
+               for( int i = 0; i < chars; i ++ )
                {
-                       buf[ base + i ].Ch = 0;
-                       buf[ base + i ].Colour = Term->CurColour;
+                       ASSERTC(base + len + i, <, Term->TextWidth*height);
+                       buf[ base + len + i ].Ch = 0;
+                       buf[ base + len + i ].Colour = Term->CurColour;
                }
                
                // Update Screen
                VT_int_ScrollFramebuffer( Term, Count );
                if( Term->Flags & VT_FLAG_ALTBUF )
-                       Term->AltWritePos = base;
+                       wrpos->Row = scroll_top;
                else
-                       Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
-               for( i = 0; i < Count; i ++ )
+                       wrpos->Row = Term->ViewTopRow + (Term->TextHeight - Count);
+               for( int i = 0; i < Count; i ++ )
                {
                        VT_int_UpdateScreen( Term, 0 );
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                               Term->AltWritePos += Term->TextWidth;
-                       else
-                               Term->WritePos += Term->TextWidth;
+                       wrpos->Row ++;
                }
        }
        else
@@ -223,40 +245,37 @@ void VT_int_ScrollText(tVTerm *Term, int Count)
                Count = -Count;
                if(Count > scroll_height)       Count = scroll_height;
                
-               len = Term->TextWidth*(scroll_height - Count);
+               size_t  chars = Term->TextWidth*Count;
+               size_t  base = Term->TextWidth*scroll_top;
+               size_t  len = Term->TextWidth*scroll_height - chars;
                
                // Scroll terminal cache
-               memmove(
-                       &buf[Term->TextWidth*(scroll_top+Count)],
-                       &buf[Term->TextWidth*scroll_top],
-                       len*sizeof(tVT_Char)
-                       );
+               ASSERTC( base + chars + len, <=, Term->TextWidth*height );
+               memmove( &buf[base+chars], &buf[base], len*sizeof(tVT_Char) );
+
                // Clear preceding rows
-               for( i = 0; i < Term->TextWidth*Count; i ++ )
+               for( int i = 0; i < chars; i ++ )
                {
                        buf[ i ].Ch = 0;
                        buf[ i ].Colour = Term->CurColour;
                }
                
+               // Update screen (shift framebuffer, re-render revealed lines)
                VT_int_ScrollFramebuffer( Term, -Count );
                if( Term->Flags & VT_FLAG_ALTBUF )
-                       Term->AltWritePos = Term->TextWidth*scroll_top;
+                       wrpos->Row = scroll_top;
                else
-                       Term->WritePos = Term->ViewPos;
-               for( i = 0; i < Count; i ++ )
+                       wrpos->Row = Term->ViewTopRow;
+               for( int i = 0; i < Count; i ++ )
                {
                        VT_int_UpdateScreen( Term, 0 );
-                       if( Term->Flags & VT_FLAG_ALTBUF )
-                               Term->AltWritePos += Term->TextWidth;
-                       else
-                               Term->WritePos += Term->TextWidth;
+                       // Increment?
                }
        }
        
-       if( Term->Flags & VT_FLAG_ALTBUF )
-               Term->AltWritePos = init_write_pos;
-       else
-               Term->WritePos = init_write_pos;
+       *wrpos = init_wrpos;
+
+       HEAP_VALIDATE();
 }
 
 /**
@@ -264,21 +283,48 @@ void VT_int_ScrollText(tVTerm *Term, int Count)
  * \param Term Terminal to modify
  * \param Num  Line number to clear
  */
-void VT_int_ClearLine(tVTerm *Term, int Num)
+void VT_int_ClearLine(tVTerm *Term, int Row)
 {
-        int    i;
-       tVT_Char        *cell;
+       HEAP_VALIDATE();
+       
+       size_t  height = VT_int_GetBufferRows(Term);
+       tVT_Char        *buffer = (Term->Flags & VT_FLAG_ALTBUF ? Term->AltBuf : Term->Text);
+       ASSERTCR(Row, >=, 0, );
+       ASSERTCR(Row, <, height, );
        
-       if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) )        return ;
+       size_t  base = Row * Term->TextWidth;
        
-       cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
-       cell = &cell[ Num*Term->TextWidth ];
+       for( int i = 0; i < Term->TextWidth; i ++ )
+       {
+               buffer[ base + i ].Ch = 0;
+               buffer[ base + i ].Colour = Term->CurColour;
+       }
        
-       for( i = Term->TextWidth; i--; )
+       HEAP_VALIDATE();
+}
+
+void VT_int_ClearInLine(tVTerm *Term, int Row, int FirstCol, int LastCol)
+{
+       HEAP_VALIDATE();
+       
+       size_t  height = VT_int_GetBufferRows(Term);
+       tVT_Char        *buffer = (Term->Flags & VT_FLAG_ALTBUF ? Term->AltBuf : Term->Text);
+       ASSERTCR(Row, >=, 0, );
+       ASSERTCR(Row, <, height, );
+
+       ASSERTCR(FirstCol, <=, LastCol, );
+       ASSERTCR(FirstCol, <, Term->TextWidth, );
+       ASSERTCR(LastCol, <=, Term->TextWidth, );
+       
+       size_t  base = Row * Term->TextWidth;
+       for( int i = FirstCol; i < LastCol; i ++ )
        {
-               cell[ i ].Ch = 0;
-               cell[ i ].Colour = Term->CurColour;
+               ASSERTC(base + i, <, height * Term->TextWidth);
+               buffer[ base + i ].Ch = 0;
+               buffer[ base + i ].Colour = Term->CurColour;
        }
+       
+       HEAP_VALIDATE();
 }
 
 /**
@@ -288,7 +334,7 @@ void VT_int_ClearLine(tVTerm *Term, int Num)
  * \param NewWidth     New framebuffer width
  * \param NewHeight    New framebuffer height
  */
-void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
+void VT_int_Resize(tVTerm *Term, int NewWidth, int NewHeight)
 {
         int    oldW = Term->Width;
         int    oldTW = Term->TextWidth;
@@ -296,14 +342,14 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
         int    oldTH = Term->TextHeight;
        tVT_Char        *oldTBuf = Term->Text;
        Uint32  *oldFB = Term->Buffer;
-        int    w, h, i;
+        int    w, h;
+       
+       HEAP_VALIDATE();
        
        // TODO: Increase RealWidth/RealHeight when this happens
        if(NewWidth > giVT_RealWidth)   NewWidth = giVT_RealWidth;
        if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight;
        
-       Term->Mode = NewMode;
-
        // Fast exit if no resolution change
        if(NewWidth == Term->Width && NewHeight == Term->Height)
                return ;
@@ -326,7 +372,7 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
                w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW;
                h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH;
                h *= giVT_Scrollback + 1;
-               for( i = 0; i < h; i ++ )
+               for( int i = 0; i < h; i ++ )
                {
                        memcpy(
                                &Term->Text[i*Term->TextWidth],
@@ -349,7 +395,7 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
                // Copy old buffer
                w = (oldW > Term->Width) ? Term->Width : oldW;
                h = (oldH > Term->Height) ? Term->Height : oldH;
-               for( i = 0; i < h; i ++ )
+               for( int i = 0; i < h; i ++ )
                {
                        memcpy(
                                &Term->Buffer[i*Term->Width],
@@ -361,7 +407,8 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
        }
        
        // Debug
-       switch(NewMode)
+       #if 0
+       switch(Term->Mode)
        {
        case TERM_MODE_TEXT:
                Log_Log("VTerm", "Set VT %p to text mode (%ix%i)",
@@ -375,6 +422,9 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
        //case TERM_MODE_3DACCEL:
        //      return;
        }
+       #endif
+
+       HEAP_VALIDATE();
 }
 
 
@@ -387,3 +437,13 @@ void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled)
        VT_int_UpdateScreen(Term, 1);
 }
 
+tVT_Pos *VT_int_GetWritePosPtr(tVTerm *Term)
+{
+       return ((Term->Flags & VT_FLAG_ALTBUF) ? &Term->AltWritePos : &Term->WritePos);
+}
+
+size_t VT_int_GetBufferRows(tVTerm *Term)
+{
+       return ((Term->Flags & VT_FLAG_ALTBUF) ? 1 : (giVT_Scrollback+1))*Term->TextHeight;
+}
+

UCC git Repository :: git.ucc.asn.au