Ejemplo n.º 1
0
        protected override TextLineCollection GetLinesCore()
        {
            var oldLineInfo = _oldText.Lines;
            var lineStarts  = ArrayBuilder <int> .GetInstance();

            lineStarts.Add(0);

            // position in the original document
            var position = 0;
            // delta generated by already processed changes (position in the new document = position + delta)
            var delta = 0;
            // true if last segment ends with CR and we need to check for CR+LF code below assumes that both CR and LF are also line breaks alone
            var endsWithCR = false;

            foreach (var change in _changes)
            {
                // change.Span.Start < position already ruled out by SourceText.WithChanges
                // if we've skipped a range, add
                if (change.Span.Start > position)
                {
                    if (endsWithCR && _newText[position + delta] == '\n')
                    {
                        lineStarts.RemoveLast();
                    }
                    var lps = oldLineInfo.GetLinePositionSpan(TextSpan.FromBounds(position, change.Span.Start));
                    for (int i = lps.Start.Line + 1; i <= lps.End.Line; i++)
                    {
                        lineStarts.Add(oldLineInfo[i].Start + delta);
                    }
                    endsWithCR = _oldText[change.Span.Start - 1] == '\r';
                    // in case change is inserted between CR+LF we treat CR as line break alone, but this line break might be retracted and replaced with new one in case LF is inserted
                    if (endsWithCR && change.Span.Start < _oldText.Length && _oldText[change.Span.Start] == '\n')
                    {
                        lineStarts.Add(change.Span.Start + delta);
                    }
                }

                if (change.NewLength > 0)
                {
                    var text = GetSubText(new TextSpan(change.Span.Start + delta, change.NewLength));

                    // optimizations copied from SourceText.LineInfo.ParseLineStarts
                    var index = 0;
                    while (index < text.Length)
                    {
                        char c = text[index++];

                        // Common case - ASCII & not a line break
                        // if (c > '\r' && c <= 127)
                        // if (c >= ('\r'+1) && c <= 127)
                        const uint bias = '\r' + 1;
                        if (unchecked (c - bias) <= (127 - bias))
                        {
                            continue;
                        }

                        if (endsWithCR && c == '\n')
                        {
                            lineStarts.RemoveLast();
                        }
                        else if (c == '\r' && index < text.Length && text[index] == '\n')
                        {
                            index++;
                        }
                        else if (!TextUtilities.IsAnyLineBreakCharacter(c))
                        {
                            continue;
                        }

                        lineStarts.Add(change.Span.Start + delta + index);
                    }
                    endsWithCR = text[change.NewLength - 1] == '\r';
                }

                position = change.Span.End;
                delta   += (change.NewLength - change.Span.Length);
            }

            if (position < _oldText.Length)
            {
                if (endsWithCR && _newText[position + delta] == '\n')
                {
                    lineStarts.RemoveLast();
                }
                var lps = oldLineInfo.GetLinePositionSpan(TextSpan.FromBounds(position, _oldText.Length));
                for (int i = lps.Start.Line + 1; i <= lps.End.Line; i++)
                {
                    lineStarts.Add(oldLineInfo[i].Start + delta);
                }
            }

            return(new LineInfo(this, lineStarts.ToArrayAndFree()));
        }
Ejemplo n.º 2
0
        private int[] ParseLineStarts()
        {
            // Corner case check
            if (0 == this.Length)
            {
                return(new[] { 0 });
            }

            var lineStarts = ArrayBuilder <int> .GetInstance();

            lineStarts.Add(0); // there is always the first line

            var lastWasCR = false;

            // The following loop goes through every character in the text. It is highly
            // performance critical, and thus inlines knowledge about common line breaks
            // and non-line breaks.
            EnumerateChars(
                (int position, char[] buffer, int length) =>
            {
                var index = 0;
                if (lastWasCR)
                {
                    if (length > 0 && buffer[0] == '\n')
                    {
                        index++;
                    }

                    lineStarts.Add(position + index);
                    lastWasCR = false;
                }

                while (index < length)
                {
                    char c = buffer[index];
                    index++;

                    // Common case - ASCII & not a line break
                    // if (c > '\r' && c <= 127)
                    // if (c >= ('\r'+1) && c <= 127)
                    const uint bias = '\r' + 1;
                    if (unchecked (c - bias) <= (127 - bias))
                    {
                        continue;
                    }

                    // Assumes that the only 2-char line break sequence is CR+LF
                    if (c == '\r')
                    {
                        if (index < length && buffer[index] == '\n')
                        {
                            index++;
                        }
                        else if (index >= length)
                        {
                            lastWasCR = true;
                            continue;
                        }
                    }
                    else if (!TextUtilities.IsAnyLineBreakCharacter(c))
                    {
                        continue;
                    }

                    // next line starts at index
                    lineStarts.Add(position + index);
                }
            }
                );

            return(lineStarts.ToArrayAndFree());
        }
Ejemplo n.º 3
0
        private int[] ParseLineStarts()
        {
            int length = this.Length;

            // Corner case check
            if (0 == this.Length)
            {
                return(new int[] { 0 });
            }

            var position     = 0;
            var index        = 0;
            var arrayBuilder = ArrayBuilder <int> .GetInstance();

            var lineNumber = 0;

            // The following loop goes through every character in the text. It is highly
            // performance critical, and thus inlines knowledge about common line breaks
            // and non-line breaks.
            while (index < length)
            {
                char c = this[index];
                int  lineBreakLength;

                // common case - ASCII & not a line break
                if (c > '\r' & c <= 127)
                {
                    index++;
                    continue;
                }
                else if (c == '\r' && index + 1 < length && this[index + 1] == '\n')
                {
                    lineBreakLength = 2;
                }
                else if (c == '\n')
                {
                    lineBreakLength = 1;
                }
                else
                {
                    lineBreakLength = TextUtilities.GetLengthOfLineBreak(this, index);
                }

                if (0 == lineBreakLength)
                {
                    index++;
                }
                else
                {
                    arrayBuilder.Add(position);
                    index   += lineBreakLength;
                    position = index;
                    lineNumber++;
                }
            }

            // Create a start for the final line.
            arrayBuilder.Add(position);

            return(arrayBuilder.ToArrayAndFree());
        }