Ejemplo n.º 1
0
        protected void ResizeBuffer()
        {
            // Grow or shrink the width of the buffer lines to match the new
            // value.  Note that this does not (yet) account for preserving lines and wrapping them.
            for (int row = 0; row < buffer.Count; ++row)
            {
                var newRow = new ScreenBufferLine(ColumnCount);
                newRow.ArrayCopyFrom(buffer[row], 0, 0, Math.Min(buffer[row].Length, ColumnCount));
                buffer[row] = newRow;
            }

            // Add more buffer lines if needed to pad out the rest of the screen:
            while (buffer.Count - topRow < RowCount)
            {
                buffer.Add(new ScreenBufferLine(ColumnCount));
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Make a copy of me for later diffing against.
        /// Almost a deep copy.
        /// </summary>
        /// <returns>The new copy</returns>
        public IScreenSnapShot DeepCopy()
        {
            ScreenSnapShot newCopy = new ScreenSnapShot
            {
                TopRow       = TopRow,
                CursorColumn = CursorColumn,
                CursorRow    = CursorRow,
                RowCount     = RowCount,
                Buffer       = new List <IScreenBufferLine>()
            };

            // This will probably reset the timestamps on the rows, but for our purposes that's actually fine - we call this
            // when we want to get a fully sync'ed copy:
            foreach (IScreenBufferLine line in Buffer)
            {
                ScreenBufferLine newLine = new ScreenBufferLine(line.Length);
                newLine.ArrayCopyFrom(line.ToArray(), 0, 0);
                newCopy.Buffer.Add(newLine);
            }
            return(newCopy);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Make a copy of me for later diffing against.
        /// Almost a deep copy.
        /// </summary>
        /// <returns>The new copy</returns>
        public IScreenSnapShot DeepCopy()
        {
            ScreenSnapShot newCopy = new ScreenSnapShot
            {
                TopRow = TopRow,
                CursorColumn = CursorColumn,
                CursorRow = CursorRow,
                RowCount = RowCount,
                Buffer = new List<IScreenBufferLine>()
            };

            // This will probably reset the timestamps on the rows, but for our purposes that's actually fine - we call this
            // when we want to get a fully sync'ed copy:
            foreach (IScreenBufferLine line in Buffer)
            {
                ScreenBufferLine newLine = new ScreenBufferLine(line.Length);
                newLine.ArrayCopyFrom(line.ToArray(), 0, 0);
                newCopy.Buffer.Add(newLine);
            }
            return newCopy;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Get a list of the operations that would make a terminal window look like this snapshot
        /// if you assume that beforehand it looked like the older snapshot you pass in.
        /// </summary>
        /// <param name="older">the older snapshot of a screen to diff from</param>
        /// <returns>the string that if output in order, will give you the desired changes</returns>
        public string DiffFrom(IScreenSnapShot older)
        {
            StringBuilder output = new StringBuilder();
            
            int verticalScroll = TopRow - older.TopRow;
            int trackCursorColumn = older.CursorColumn; // track the movements that will occur as the outputs happen.
            int trackCursorRow = older.CursorRow; // track the movements that will occur as the outputs happen.

            // First, output the command to make the terminal scroll to match:
            if (verticalScroll > 0) // scrolling text up (eyeballs panning down)
                output.Append(new String((char)UnicodeCommand.SCROLLSCREENUPONE, verticalScroll)); // A run of scrollup chars
            else if (verticalScroll < 0) // scrolling text down (eyeballs panning up)
                output.Append(new String((char)UnicodeCommand.SCROLLSCREENDOWNONE, -verticalScroll)); // A run of scrolldown chars

            // Check each row:
            for (int newRowNum = 0 ; newRowNum < RowCount ; ++newRowNum)
            {
                // Account for the diff due to the scrolling:
                int oldRowNum = newRowNum + verticalScroll;

                IScreenBufferLine newRow = Buffer[newRowNum];
                bool oldRowExists = (oldRowNum >= 0 && oldRowNum < older.Buffer.Count);
                IScreenBufferLine olderRow = oldRowExists ? older.Buffer[oldRowNum] : new ScreenBufferLine(0);
                
                // if new row is an empty dummy, then pad it out so it gets properly diffed against the old row:
                if (newRow.Length == 0)
                    newRow = new ScreenBufferLine(olderRow.Length);
                // If the old row is a dummy pad or if the new row is newer than the old row, then it needs checking for diffs:
                if (olderRow.Length == 0 || newRow.LastChangeTick > olderRow.LastChangeTick)
                {
                    List<DiffChunk> diffs = new List<DiffChunk>();
                    
                    for (int newCol = 0 ; newCol < newRow.Length ; ++newCol)
                    {
                        // Check if they differ, but in a way that treats ' ' and 0x00 as identical, and treats a shorter
                        // old row as if it has been padded with spaces:
                        bool oldRowTooShort = newCol >= olderRow.Length;
                        char newChar = (newRow[newCol] == '\0' ? ' ' : newRow[newCol]);
                        char oldChar = (oldRowTooShort ? ' ' : (olderRow[newCol] == '\0' ? ' ' : olderRow[newCol]));
                        if (newChar != oldChar)
                        {
                            // Start a new diff chunk if there isn't one yet, or the diff is a long enough distance from the existing one:
                            if (diffs.Count == 0 || diffs[diffs.Count-1].EndCol < newCol - JOIN_DIFF_DIST)
                            {
                                DiffChunk newChunk = new DiffChunk
                                {
                                    StartCol = newCol, 
                                    EndCol = newCol
                                };
                                diffs.Add(newChunk);
                            }
                            else // stretch the existing diff chunk to here.
                            {
                                diffs[diffs.Count-1].EndCol = newCol;
                            }
                        }
                    }
                    
                    string newRowText = newRow.ToString();

                    foreach (DiffChunk diff in diffs)
                    {
                        /* comment-out -----------------
                        // If we're lucky enough that the current cursor happens to be right where we need it to
                        // be, some of these are more efficient.  Else it does TELEPORTCURSOR's:
                        
                        // Just one char removed to the left of current cursor pos - do a backspace instead of the ugly work:
                        if (trackCursorRow == newRowNum && (diff.EndCol == trackCursorColumn - 1 && diff.StartCol == diff.EndCol))
                        {
                            output.Append(String.Format("{0}{1}{2}", (char)0x08, newRowText.Substring(diff.StartCol,1), (char)0x08));
                            trackCursorColumn = diff.EndCol;
                            trackCursorRow = newRowNum;
                        }
                        else
                        {
                        --------------------------- */
                            // If the change starts right where the cursor happens to be (i.e. when typing, one char
                            // at current cursor position will typically be the only diff from one update to the next),
                            // then don't bother moving the cursor first, else move it to the new pos:
                            string moveString;
                            if (trackCursorRow == newRowNum && diff.StartCol == trackCursorColumn)
                                moveString = "";
                            else
                                moveString = String.Format("{0}{1}{2}",
                                                           (char)UnicodeCommand.TELEPORTCURSOR,
                                                           (char)diff.StartCol,
                                                           (char)newRowNum);
                            
                            // content = the bit of string to print at this location, with nulls made into spaces so the 
                            // telnet terminal will print correctly.
                            string content = newRowText.Substring(diff.StartCol, diff.EndCol - diff.StartCol + 1).Replace('\0',' ');

                            output.Append(String.Format("{0}{1}", moveString, content));
 
                            trackCursorColumn = diff.EndCol+1;
                            trackCursorRow = newRowNum;
                        /* comment-out -----------------
                        }
                        --------------------------- */
                    }
                    
                }
                    
            }
                    
            // Now set the cursor back to the right spot one more time, unless it's already there:
            if (trackCursorRow != CursorRow || trackCursorColumn != CursorColumn)
            {
                output.Append(String.Format("{0}{1}{2}",
                                            (char)UnicodeCommand.TELEPORTCURSOR,
                                            (char)CursorColumn,
                                            (char)CursorRow));
            }
            return output.ToString();
        }
Ejemplo n.º 5
0
        protected void ResizeBuffer()
        {
            // Grow or shrink the width of the buffer lines to match the new
            // value.  Note that this does not (yet) account for preserving lines and wrapping them.
            for (int row = 0; row < buffer.Count; ++row)
            {
                var newRow = new ScreenBufferLine(ColumnCount);
                newRow.ArrayCopyFrom(buffer[row], 0, 0, Math.Min(buffer[row].Length, ColumnCount));
                buffer[row] = newRow;
            }

            // Add more buffer lines if needed to pad out the rest of the screen:
            while (buffer.Count - topRow < RowCount)
                buffer.Add(new ScreenBufferLine(ColumnCount));
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Get a list of the operations that would make a terminal window look like this snapshot
        /// if you assume that beforehand it looked like the older snapshot you pass in.
        /// </summary>
        /// <param name="older">the older snapshot of a screen to diff from</param>
        /// <returns>the string that if output in order, will give you the desired changes</returns>
        public string DiffFrom(IScreenSnapShot older)
        {
            StringBuilder output = new StringBuilder();

            int verticalScroll    = TopRow - older.TopRow;
            int trackCursorColumn = older.CursorColumn; // track the movements that will occur as the outputs happen.
            int trackCursorRow    = older.CursorRow;    // track the movements that will occur as the outputs happen.

            // First, output the command to make the terminal scroll to match:
            if (verticalScroll > 0)                                                                   // scrolling text up (eyeballs panning down)
            {
                output.Append(new String((char)UnicodeCommand.SCROLLSCREENUPONE, verticalScroll));    // A run of scrollup chars
            }
            else if (verticalScroll < 0)                                                              // scrolling text down (eyeballs panning up)
            {
                output.Append(new String((char)UnicodeCommand.SCROLLSCREENDOWNONE, -verticalScroll)); // A run of scrolldown chars
            }
            // Check each row:
            for (int newRowNum = 0; newRowNum < RowCount; ++newRowNum)
            {
                // Account for the diff due to the scrolling:
                int oldRowNum = newRowNum + verticalScroll;

                IScreenBufferLine newRow   = Buffer[newRowNum];
                bool oldRowExists          = (oldRowNum >= 0 && oldRowNum < older.Buffer.Count);
                IScreenBufferLine olderRow = oldRowExists ? older.Buffer[oldRowNum] : new ScreenBufferLine(0);

                // if new row is an empty dummy, then pad it out so it gets properly diffed against the old row:
                if (newRow.Length == 0)
                {
                    newRow = new ScreenBufferLine(olderRow.Length);
                }
                // If the old row is a dummy pad or if the new row is newer than the old row, then it needs checking for diffs:
                if (olderRow.Length == 0 || newRow.LastChangeTick > olderRow.LastChangeTick)
                {
                    List <DiffChunk> diffs = new List <DiffChunk>();

                    for (int newCol = 0; newCol < newRow.Length; ++newCol)
                    {
                        // Check if they differ, but in a way that treats ' ' and 0x00 as identical, and treats a shorter
                        // old row as if it has been padded with spaces:
                        bool oldRowTooShort = newCol >= olderRow.Length;
                        char newChar        = (newRow[newCol] == '\0' ? ' ' : newRow[newCol]);
                        char oldChar        = (oldRowTooShort ? ' ' : (olderRow[newCol] == '\0' ? ' ' : olderRow[newCol]));
                        if (newChar != oldChar)
                        {
                            // Start a new diff chunk if there isn't one yet, or the diff is a long enough distance from the existing one:
                            if (diffs.Count == 0 || diffs[diffs.Count - 1].EndCol < newCol - JOIN_DIFF_DIST)
                            {
                                DiffChunk newChunk = new DiffChunk
                                {
                                    StartCol = newCol,
                                    EndCol   = newCol
                                };
                                diffs.Add(newChunk);
                            }
                            else // stretch the existing diff chunk to here.
                            {
                                diffs[diffs.Count - 1].EndCol = newCol;
                            }
                        }
                    }

                    string newRowText = newRow.ToString();

                    foreach (DiffChunk diff in diffs)
                    {
                        /* comment-out -----------------
                         * // If we're lucky enough that the current cursor happens to be right where we need it to
                         * // be, some of these are more efficient.  Else it does TELEPORTCURSOR's:
                         *
                         * // Just one char removed to the left of current cursor pos - do a backspace instead of the ugly work:
                         * if (trackCursorRow == newRowNum && (diff.EndCol == trackCursorColumn - 1 && diff.StartCol == diff.EndCol))
                         * {
                         *  output.Append(String.Format("{0}{1}{2}", (char)0x08, newRowText.Substring(diff.StartCol,1), (char)0x08));
                         *  trackCursorColumn = diff.EndCol;
                         *  trackCursorRow = newRowNum;
                         * }
                         * else
                         * {
                         * --------------------------- */
                        // If the change starts right where the cursor happens to be (i.e. when typing, one char
                        // at current cursor position will typically be the only diff from one update to the next),
                        // then don't bother moving the cursor first, else move it to the new pos:
                        string moveString;
                        if (trackCursorRow == newRowNum && diff.StartCol == trackCursorColumn)
                        {
                            moveString = "";
                        }
                        else
                        {
                            moveString = String.Format("{0}{1}{2}",
                                                       (char)UnicodeCommand.TELEPORTCURSOR,
                                                       (char)diff.StartCol,
                                                       (char)newRowNum);
                        }

                        // content = the bit of string to print at this location, with nulls made into spaces so the
                        // telnet terminal will print correctly.
                        string content = newRowText.Substring(diff.StartCol, diff.EndCol - diff.StartCol + 1).Replace('\0', ' ');

                        output.Append(String.Format("{0}{1}", moveString, content));

                        trackCursorColumn = diff.EndCol + 1;
                        trackCursorRow    = newRowNum;

                        /* comment-out -----------------
                         * }
                         * --------------------------- */
                    }
                }
            }

            // Now set the cursor back to the right spot one more time, unless it's already there:
            if (trackCursorRow != CursorRow || trackCursorColumn != CursorColumn)
            {
                output.Append(String.Format("{0}{1}{2}",
                                            (char)UnicodeCommand.TELEPORTCURSOR,
                                            (char)CursorColumn,
                                            (char)CursorRow));
            }
            return(output.ToString());
        }