/// <summary> /// Consolidate two string rebuilders, taking advantage of the fact that they have already extracted the line breaks. /// </summary> public static StringRebuilder Consolidate(StringRebuilder left, StringRebuilder right) { Debug.Assert(left.Length > 0); Debug.Assert(right.Length > 0); int length = left.Length + right.Length; char[] result = new char[length]; left.CopyTo(0, result, 0, left.Length); right.CopyTo(0, result, left.Length, right.Length); ILineBreaks lineBreaks; if ((left.LineBreakCount == 0) && (right.LineBreakCount == 0)) { lineBreaks = LineBreakManager.Empty; //_lineBreakSpan defaults to 0, 0 which is what we want } else { ILineBreaksEditor breaks = LineBreakManager.CreateLineBreakEditor(length, left.LineBreakCount + right.LineBreakCount); int offset = 0; if ((result[left.Length] == '\n') && (result[left.Length - 1] == '\r')) { //We have a \r\n spanning the seam ... add that as a special linebreak later. offset = 1; } int leftLines = left.LineBreakCount - offset; for (int i = 0; (i < leftLines); ++i) { Span extent; int lineBreakLength; left.GetLineFromLineNumber(i, out extent, out lineBreakLength); breaks.Add(extent.End, lineBreakLength); } if (offset == 1) { breaks.Add(left.Length - 1, 2); } for (int i = offset; (i < right.LineBreakCount); ++i) { Span extent; int lineBreakLength; right.GetLineFromLineNumber(i, out extent, out lineBreakLength); breaks.Add(extent.End + left.Length, lineBreakLength); } lineBreaks = breaks; } return(StringRebuilderForChars.Create(result, length, lineBreaks)); }
public override void GetLineFromLineNumber(int lineNumber, out Span extent, out int lineBreakLength) { if ((lineNumber < 0) || (lineNumber > this.LineBreakCount)) { throw new ArgumentOutOfRangeException(nameof(lineNumber)); } if (lineNumber < _left.LineBreakCount) { _left.GetLineFromLineNumber(lineNumber, out extent, out lineBreakLength); } else if (lineNumber > _left.LineBreakCount) { _right.GetLineFromLineNumber(lineNumber - _left.LineBreakCount, out extent, out lineBreakLength); extent = new Span(extent.Start + _left.Length, extent.Length); } else { // The line crosses the seam. int start = 0; if (lineNumber != 0) { _left.GetLineFromLineNumber(lineNumber, out extent, out lineBreakLength); // ignore the returned extend.Length start = extent.Start; Debug.Assert(lineBreakLength == 0); } int end; if (lineNumber == this.LineBreakCount) { end = this.Length; lineBreakLength = 0; } else { _right.GetLineFromLineNumber(0, out extent, out lineBreakLength); end = extent.End + _left.Length; } extent = Span.FromBounds(start, end); } }
public override LineSpan GetLineFromLineNumber(int lineNumber) { if ((lineNumber < 0) || (lineNumber > this.LineBreakCount)) { throw new ArgumentOutOfRangeException("lineNumber"); } if (lineNumber < _left.LineBreakCount) { return(_left.GetLineFromLineNumber(lineNumber)); } else if (lineNumber > _left.LineBreakCount) { LineSpan rightSpan = _right.GetLineFromLineNumber(lineNumber - _left.LineBreakCount); return(new LineSpan(lineNumber, new Span(rightSpan.Start + _left.Length, rightSpan.Length), rightSpan.LineBreakLength)); } else { int start = (lineNumber == 0) ? 0 : _left.GetLineFromLineNumber(lineNumber).Start; int end; int breakLength; if (lineNumber == this.LineBreakCount) { end = this.Length; breakLength = 0; } else { LineSpan rightSpan = _right.GetLineFromLineNumber(0); end = rightSpan.End + _left.Length; breakLength = rightSpan.LineBreakLength; } return(new LineSpan(lineNumber, Span.FromBounds(start, end), breakLength)); } }
/// <summary> /// Consolidate two string rebuilders, taking advantage of the fact that they have already extracted the line breaks. /// </summary> public static SimpleStringRebuilder Create(StringRebuilder left, StringRebuilder right) { Debug.Assert(left.Length > 0); Debug.Assert(right.Length > 0); int length = left.Length + right.Length; char[] result = new char[length]; left.CopyTo(0, result, 0, left.Length); right.CopyTo(0, result, left.Length, right.Length); string text = new string(result); int[] lineBreaks; if ((left.LineBreakCount == 0) && (right.LineBreakCount == 0)) { lineBreaks = _emptyLineBreaks; //_lineBreakSpan defaults to 0, 0 which is what we want } else { int offset = 0; if ((text[left.Length] == '\n') && (text[left.Length - 1] == '\r')) { //We have a \r\n spanning the seam ... add that as a special linebreak later. offset = 1; } lineBreaks = new int[left.LineBreakCount + right.LineBreakCount - offset]; int lastLineBreak = 0; int leftLines = left.LineBreakCount - offset; for (int i = 0; (i < leftLines); ++i) { LineSpan lineSpan = left.GetLineFromLineNumber(i); lineBreaks[lastLineBreak++] = lineSpan.End; } if (offset == 1) { lineBreaks[lastLineBreak++] = left.Length - 1; } for (int i = offset; (i < right.LineBreakCount); ++i) { LineSpan lineSpan = right.GetLineFromLineNumber(i); lineBreaks[lastLineBreak++] = lineSpan.End + left.Length; } } return(new SimpleStringRebuilder(SimpleTextStorage.Create(text, lineBreaks))); }