Пример #1
0
        protected static int GetWrappedLineTrimmedLength(BufferLine line, BufferLine nextLine, int cols)
        {
            // If this is the last row in the wrapped line, get the actual trimmed length
            if (nextLine == null)
            {
                return(line.GetTrimmedLength());
            }

            // Detect whether the following line starts with a wide character and the end of the current line
            // is null, if so then we can be pretty sure the null character should be excluded from the line
            // length]
            bool endsInNull = !(line.HasContent(cols - 1)) && line.GetWidth(cols - 1) == 1;
            bool followingLineStartsWithWide = nextLine.GetWidth(0) == 2;

            if (endsInNull && followingLineStartsWithWide)
            {
                return(cols - 1);
            }

            return(cols);
        }
Пример #2
0
        public override void Reflow(int newCols, int newRows, int oldCols, int oldRows)
        {
            // Gather all BufferLines that need to be inserted into the Buffer here so that they can be
            // batched up and only committed once
            List <InsertionSet> toInsert = new List <InsertionSet> ();
            int countToInsert            = 0;

            // Go backwards as many lines may be trimmed and this will avoid considering them
            for (int y = Buffer.Lines.Length - 1; y >= 0; y--)
            {
                // Check whether this line is a problem or not, if not skip it
                BufferLine nextLine   = Buffer.Lines [y];
                int        lineLength = nextLine.GetTrimmedLength();
                if (!nextLine.IsWrapped && lineLength <= newCols)
                {
                    continue;
                }

                // Gather wrapped lines and adjust y to be the starting line
                List <BufferLine> wrappedLines = new List <BufferLine> ();
                wrappedLines.Add(nextLine);
                while (nextLine.IsWrapped && y > 0)
                {
                    nextLine = Buffer.Lines [--y];
                    wrappedLines.Insert(0, nextLine);
                }

                // If these lines contain the cursor don't touch them, the program will handle fixing up
                // wrapped lines with the cursor
                int absoluteY = Buffer.YBase + Buffer.Y;

                if (absoluteY >= y && absoluteY < y + wrappedLines.Count)
                {
                    continue;
                }

                int    lastLineLength  = wrappedLines [wrappedLines.Count - 1].GetTrimmedLength();
                int [] destLineLengths = GetNewLineLengths(wrappedLines, oldCols, newCols);
                int    linesToAdd      = destLineLengths.Length - wrappedLines.Count;

                int trimmedLines;
                if (Buffer.YBase == 0 && Buffer.Y != Buffer.Lines.Length - 1)
                {
                    // If the top section of the buffer is not yet filled
                    trimmedLines = Math.Max(0, Buffer.Y - Buffer.Lines.MaxLength + linesToAdd);
                }
                else
                {
                    trimmedLines = Math.Max(0, Buffer.Lines.Length - Buffer.Lines.MaxLength + linesToAdd);
                }

                // Add the new lines
                List <BufferLine> newLines = new List <BufferLine> ();
                for (int i = 0; i < linesToAdd; i++)
                {
                    BufferLine newLine = Buffer.GetBlankLine(CharData.DefaultAttr, true);
                    newLines.Add(newLine);
                }

                if (newLines.Count > 0)
                {
                    toInsert.Add(new InsertionSet {
                        Start = y + wrappedLines.Count + countToInsert,
                        Lines = newLines.ToArray()
                    });

                    countToInsert += newLines.Count;
                }

                newLines.ForEach(l => wrappedLines.Add(l));

                // Copy buffer data to new locations, this needs to happen backwards to do in-place
                int destLineIndex = destLineLengths.Length - 1;                // Math.floor(cellsNeeded / newCols);
                int destCol       = destLineLengths [destLineIndex];           // cellsNeeded % newCols;
                if (destCol == 0)
                {
                    destLineIndex--;
                    destCol = destLineLengths [destLineIndex];
                }

                int srcLineIndex = wrappedLines.Count - linesToAdd - 1;
                int srcCol       = lastLineLength;
                while (srcLineIndex >= 0)
                {
                    int cellsToCopy = Math.Min(srcCol, destCol);
                    wrappedLines [destLineIndex].CopyCellsFrom(wrappedLines [srcLineIndex], srcCol - cellsToCopy, destCol - cellsToCopy, cellsToCopy);
                    destCol -= cellsToCopy;
                    if (destCol == 0)
                    {
                        destLineIndex--;
                        if (destLineIndex >= 0)
                        {
                            destCol = destLineLengths [destLineIndex];
                        }
                    }

                    srcCol -= cellsToCopy;
                    if (srcCol == 0)
                    {
                        srcLineIndex--;
                        int wrappedLinesIndex = Math.Max(srcLineIndex, 0);
                        srcCol = GetWrappedLineTrimmedLength(wrappedLines, wrappedLinesIndex, oldCols);
                    }
                }

                // Null out the end of the line ends if a wide character wrapped to the following line
                for (int i = 0; i < wrappedLines.Count; i++)
                {
                    if (destLineLengths [i] < newCols)
                    {
                        wrappedLines [i] [destLineLengths [i]] = CharData.Null;
                    }
                }

                // Adjust viewport as needed
                int viewportAdjustments = linesToAdd - trimmedLines;
                while (viewportAdjustments-- > 0)
                {
                    if (Buffer.YBase == 0)
                    {
                        if (Buffer.Y < newRows - 1)
                        {
                            Buffer.Y++;
                            Buffer.Lines.Pop();
                        }
                        else
                        {
                            Buffer.YBase++;
                            Buffer.YDisp++;
                        }
                    }
                    else
                    {
                        // Ensure ybase does not exceed its maximum value
                        if (Buffer.YBase < Math.Min(Buffer.Lines.MaxLength, Buffer.Lines.Length + countToInsert) - newRows)
                        {
                            if (Buffer.YBase == Buffer.YDisp)
                            {
                                Buffer.YDisp++;
                            }

                            Buffer.YBase++;
                        }
                    }
                }

                Buffer.SavedY = Math.Min(Buffer.SavedY + linesToAdd, Buffer.YBase + newRows - 1);
            }

            Rearrange(toInsert, countToInsert);
        }
Пример #3
0
 public BufferLine(BufferLine other)
 {
     data = new CharData [other.data.Length];
     other.data.CopyTo(data, 0);
     IsWrapped = other.IsWrapped;
 }
Пример #4
0
        /// <summary>
        /// Evaluates and returns indexes to be removed after a reflow larger occurs. Lines will be removed
        /// when a wrapped line unwraps.
        /// </summary>
        /// <param name="lines">The buffer lines</param>
        /// <param name="oldCols">The columns before resize</param>
        /// <param name="newCols">The columns after resize</param>
        /// <param name="bufferAbsoluteY"></param>
        /// <param name="nullCharacter"></param>
        int [] GetLinesToRemove(CircularList <BufferLine> lines, int oldCols, int newCols, int bufferAbsoluteY, CharData nullCharacter)
        {
            // Gather all BufferLines that need to be removed from the Buffer here so that they can be
            // batched up and only committed once
            List <int> toRemove = new List <int> ();

            for (int y = 0; y < lines.Length - 1; y++)
            {
                // Check if this row is wrapped
                int        i        = y;
                BufferLine nextLine = lines [++i];
                if (!nextLine.IsWrapped)
                {
                    continue;
                }

                // Check how many lines it's wrapped for
                List <BufferLine> wrappedLines = new List <BufferLine> (lines.Length - y);
                wrappedLines.Add(lines [y]);
                while (i < lines.Length && nextLine.IsWrapped)
                {
                    wrappedLines.Add(nextLine);
                    nextLine = lines [++i];
                }

                // If these lines contain the cursor don't touch them, the program will handle fixing up wrapped
                // lines with the cursor
                if (bufferAbsoluteY >= y && bufferAbsoluteY < i)
                {
                    y += wrappedLines.Count - 1;
                    continue;
                }

                // Copy buffer data to new locations
                int destLineIndex = 0;
                int destCol       = GetWrappedLineTrimmedLength(Buffer.Lines, destLineIndex, oldCols);
                int srcLineIndex  = 1;
                int srcCol        = 0;
                while (srcLineIndex < wrappedLines.Count)
                {
                    int srcTrimmedTineLength = GetWrappedLineTrimmedLength(wrappedLines, srcLineIndex, oldCols);
                    int srcRemainingCells    = srcTrimmedTineLength - srcCol;
                    int destRemainingCells   = newCols - destCol;
                    int cellsToCopy          = Math.Min(srcRemainingCells, destRemainingCells);

                    wrappedLines [destLineIndex].CopyCellsFrom(wrappedLines [srcLineIndex], srcCol, destCol, cellsToCopy);

                    destCol += cellsToCopy;
                    if (destCol == newCols)
                    {
                        destLineIndex++;
                        destCol = 0;
                    }

                    srcCol += cellsToCopy;
                    if (srcCol == srcTrimmedTineLength)
                    {
                        srcLineIndex++;
                        srcCol = 0;
                    }

                    // Make sure the last cell isn't wide, if it is copy it to the current dest
                    if (destCol == 0 && destLineIndex != 0)
                    {
                        if (wrappedLines [destLineIndex - 1].GetWidth(newCols - 1) == 2)
                        {
                            wrappedLines [destLineIndex].CopyCellsFrom(wrappedLines [destLineIndex - 1], newCols - 1, destCol++, 1);
                            // Null out the end of the last row
                            wrappedLines [destLineIndex - 1].ReplaceCells(newCols - 1, 1, nullCharacter);
                        }
                    }
                }

                // Clear out remaining cells or fragments could remain;
                wrappedLines [destLineIndex].ReplaceCells(destCol, newCols, nullCharacter);

                // Work backwards and remove any rows at the end that only contain null cells
                int countToRemove = 0;
                for (int ix = wrappedLines.Count - 1; ix > 0; ix--)
                {
                    if (ix > destLineIndex || wrappedLines [ix].GetTrimmedLength() == 0)
                    {
                        countToRemove++;
                    }
                    else
                    {
                        break;
                    }
                }

                if (countToRemove > 0)
                {
                    toRemove.Add(y + wrappedLines.Count - countToRemove);                      // index
                    toRemove.Add(countToRemove);
                }

                y += wrappedLines.Count - 1;
            }

            return(toRemove.ToArray());
        }