public TextSnapshot(ITextBuffer textBuffer, ITextVersion version, StringRebuilder content) : base(version) { System.Diagnostics.Debug.Assert(version.Length == content.Length); this.textBuffer = textBuffer; this.content = content; }
public ITextBuffer CreateTextBuffer(TextReader reader, IContentType contentType, long length, string traceId, bool throwOnInvalidCharacters) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (contentType == null) { throw new ArgumentNullException(nameof(contentType)); } if (length > int.MaxValue) { throw new InvalidOperationException(Strings.FileTooLarge); } int longestLineLength; StringRebuilder content = TextImageLoader.Load( reader, length, out var newlineState, out var leadingWhitespaceState, out longestLineLength, throwOnInvalidCharacters: throwOnInvalidCharacters); ITextBuffer buffer = Make(contentType, content, false); // Make the call to GetWhitespaceManager to add the manager to the properties. We don't need the return value here. var _ = _whitespaceManagerFactory.GetOrCreateWhitespaceManager(buffer, newlineState, leadingWhitespaceState); // Leave a sign about the longest line in the buffer. This is rather nasty, but for now // we don't want to pollute the API with this factoid buffer.Properties["LongestLineLength"] = longestLineLength; return(buffer); }
internal TextContentChangedEventArgs ApplyReload(StringRebuilder newContent, EditOptions editOptions, object editTag) { // we construct a normalized change list where the inserted text is a reference string that // points "forward" to the next snapshot and whose deleted text is a reference string that points // "backward" to the prior snapshot. This pins both snapshots in memory but that's better than materializing // giant strings, and when (?) we have paging text storage, memory requirements will be minimal. ITextSnapshot oldSnapshot = this.currentSnapshot; StringRebuilder oldContent = BufferFactoryService.StringRebuilderFromSnapshotSpan(new SnapshotSpan(oldSnapshot, 0, oldSnapshot.Length)); TextChange change = TextChange.Create(oldPosition: 0, oldText: oldContent, newText: newContent, currentSnapshot: oldSnapshot); TextVersion newVersion = this.currentVersion.CreateNext(changes: null, newLength: newContent.Length, reiteratedVersionNumber: -1); TextSnapshot newSnapshot = new TextSnapshot(this, newVersion, newContent); this.currentVersion.SetChanges(NormalizedTextChangeCollection.Create(new TextChange[] { change }, editOptions.ComputeMinimalChange ? (StringDifferenceOptions?)editOptions.DifferenceOptions : null, this.textDifferencingService, oldSnapshot, newSnapshot)); this.currentVersion = newVersion; this.builder = newContent; this.currentSnapshot = newSnapshot; return(new TextContentChangedEventArgs(oldSnapshot, newSnapshot, editOptions, editTag)); }
private StringRebuilder Assemble(Span left, StringRebuilder text, Span right) { if (text.Length == 0) { return(Assemble(left, right)); } else if (left.Length == 0) { return((right.Length == 0) ? text : BinaryStringRebuilder.Create(text, this.GetSubText(right))); } else if (right.Length == 0) { return(BinaryStringRebuilder.Create(this.GetSubText(left), text)); } else if (left.Length < right.Length) { return(BinaryStringRebuilder.Create(BinaryStringRebuilder.Create(this.GetSubText(left), text), this.GetSubText(right))); } else { return(BinaryStringRebuilder.Create(this.GetSubText(left), BinaryStringRebuilder.Create(text, this.GetSubText(right)))); } }
private TextBuffer Make(IContentType contentType, StringRebuilder content, bool spurnGroup) { TextBuffer buffer = new TextBuffer(contentType, content, _textDifferencingSelectorService.DefaultTextDifferencingService, _guardedOperations, spurnGroup); RaiseTextBufferCreatedEvent(buffer); return(buffer); }
internal static StringRebuilder StringRebuilderFromSnapshotSpan(SnapshotSpan span) { TextSnapshot snapshot = span.Snapshot as TextSnapshot; if (snapshot != null) { return(snapshot.Content.Substring(span)); } IProjectionSnapshot projectionSnapshot = span.Snapshot as IProjectionSnapshot; if (projectionSnapshot != null) { StringRebuilder content = SimpleStringRebuilder.Create(string.Empty); foreach (var childSpan in projectionSnapshot.MapToSourceSnapshots(span)) { content = content.Append(StringRebuilderFromSnapshotSpan(childSpan)); } return(content); } //The we don't know what to do fallback. This should never be called unless someone provides a new snapshot //implementation. return(SimpleStringRebuilder.Create(span.GetText())); }
public ITextBuffer CreateTextBuffer(TextReader reader, IContentType contentType, long length, string traceId) { if (reader == null) { throw new ArgumentNullException("reader"); } if (contentType == null) { throw new ArgumentNullException("contentType"); } if (length > int.MaxValue) { throw new InvalidOperationException(Strings.FileTooLarge); } bool hasConsistentLineEndings; int longestLineLength; StringRebuilder content = TextImageLoader.Load(reader, length, traceId, out hasConsistentLineEndings, out longestLineLength); ITextBuffer buffer = Make(contentType, content, false); if (!hasConsistentLineEndings) { // leave a sign that line endings are inconsistent. This is rather nasty but for now // we don't want to pollute the API with this factoid buffer.Properties.AddProperty("InconsistentLineEndings", true); } // leave a similar sign about the longest line in the buffer. return(buffer); }
internal TextContentChangedEventArgs ApplyReload(StringRebuilder newContent, EditOptions editOptions, object editTag) { // we construct a normalized change list where the inserted text is a reference string that // points "forward" to the next snapshot and whose deleted text is a reference string that points // "backward" to the prior snapshot. This pins both snapshots in memory but that's better than materializing // giant strings, and when (?) we have paging text storage, memory requirements will be minimal. TextVersion newVersion = new TextVersion(this, this.currentVersion.VersionNumber + 1, this.currentVersion.VersionNumber + 1, newContent.Length); ITextSnapshot oldSnapshot = this.currentSnapshot; TextSnapshot newSnapshot = new TextSnapshot(this, newVersion, newContent); ReferenceChangeString oldText = new ReferenceChangeString(new SnapshotSpan(oldSnapshot, 0, oldSnapshot.Length)); ReferenceChangeString newText = new ReferenceChangeString(new SnapshotSpan(newSnapshot, 0, newSnapshot.Length)); TextChange change = new TextChange(oldPosition: 0, oldText: oldText, newText: newText, currentSnapshot: oldSnapshot); this.currentVersion.AddNextVersion(NormalizedTextChangeCollection.Create(new FrugalList <TextChange>() { change }, editOptions.ComputeMinimalChange ? (StringDifferenceOptions?)editOptions.DifferenceOptions : null, this.textDifferencingService, oldSnapshot, newSnapshot), newVersion); this.builder = newContent; this.currentVersion = newVersion; this.currentSnapshot = newSnapshot; return(new TextContentChangedEventArgs(oldSnapshot, newSnapshot, editOptions, editTag)); }
/// <summary> /// Replace the contents of the buffer with the contents of a different string rebuilder. /// </summary> /// <param name="newContent">The new contents of the buffer (presumably read from a file).</param> /// <param name="editOptions">Options to apply to the edit. Differencing is highly likely to be selected.</param> /// <param name="editTag">Arbitrary tag associated with the reload that will appear in event arguments.</param> /// <returns></returns> public ITextSnapshot ReloadContent(StringRebuilder newContent, EditOptions editOptions, object editTag) { using (ReloadEdit edit = new ReloadEdit(this, this.currentSnapshot, editOptions, editTag)) { return(edit.ReloadContent(newContent)); } }
protected BaseSnapshot(ITextVersion2 version, StringRebuilder content) { this.version = version; this.Content = content; this.cachingContent = CachingTextImage.Create(this.Content, version.ImageVersion); // we must extract the content type here, because the content type of the text buffer may change later. this.contentType = version.TextBuffer.ContentType; }
/// <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 TextBuffer(IContentType contentType, StringRebuilder content, ITextDifferencingService textDifferencingService, GuardedOperations guardedOperations, bool spurnGroup) : base(contentType, content.Length, textDifferencingService, guardedOperations) { // Parameters are validated outside this.group = new BufferGroup(this); this.builder = content; this.spurnGroup = spurnGroup; this.currentSnapshot = this.TakeSnapshot(); }
private BinaryStringRebuilder(StringRebuilder left, StringRebuilder right) : base(left.Length + right.Length, left.LineBreakCount + right.LineBreakCount, 1 + Math.Max(left.Depth, right.Depth)) { Debug.Assert(left.Length > 0); Debug.Assert(right.Length > 0); Debug.Assert(Math.Abs(left.Depth - right.Depth) <= 1); _left = left; _right = right; }
private CachingTextImage(StringRebuilder builder, ITextImageVersion version) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } this.Builder = builder; this.Version = version; }
public ITextBuffer CreateTextBuffer(SnapshotSpan span, IContentType contentType) { if (contentType == null) { throw new ArgumentNullException(nameof(contentType)); } StringRebuilder content = StringRebuilderFromSnapshotSpan(span); return(Make(contentType, content, false)); }
public ITextBuffer CreateTextBuffer(string text, IContentType contentType, bool spurnGroup) { if (text == null) { throw new ArgumentNullException(nameof(text)); } if (contentType == null) { throw new ArgumentNullException(nameof(contentType)); } return(Make(contentType, StringRebuilder.Create(text), spurnGroup)); }
internal static StringRebuilder StringRebuilderFromSnapshotSpans(IList <SnapshotSpan> sourceSpans, Span selectedSourceSpans) { StringRebuilder content = StringRebuilder.Empty; for (int i = 0; (i < selectedSourceSpans.Length); ++i) { var span = sourceSpans[selectedSourceSpans.Start + i]; content = AppendStringRebuildersFromSnapshotAndSpan(content, span.Snapshot, span.Span); } return(content); }
/// <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))); }
/// <summary> /// Constructs a Text Change object. /// </summary> /// <param name="oldPosition"> /// The character position in the TextBuffer at which the text change happened. /// </param> /// <param name="oldText"> /// The text in the buffer that was replaced. /// </param> /// <param name="newText"> /// The text that replaces the old text. /// </param> /// <param name="boundaryConditions"> /// Information about neighboring line break characters. /// </param> public TextChange(int oldPosition, StringRebuilder oldText, StringRebuilder newText, LineBreakBoundaryConditions boundaryConditions) { if (oldPosition < 0) { throw new ArgumentOutOfRangeException(nameof(oldPosition)); } _oldPosition = oldPosition; _newPosition = oldPosition; _oldText = oldText; _newText = newText; _lineBreakBoundaryConditions = boundaryConditions; }
private static StringRebuilder ConsolidateOrBalanceTreeNode(StringRebuilder left, StringRebuilder right) { if ((left.Length + right.Length < TextModelOptions.StringRebuilderMaxCharactersToConsolidate) && (left.LineBreakCount + right.LineBreakCount <= TextModelOptions.StringRebuilderMaxLinesToConsolidate)) { //Consolidate the two rebuilders into a single simple string rebuilder return(SimpleStringRebuilder.Create(left, right)); } else { return(BinaryStringRebuilder.BalanceTreeNode(left, right)); } }
/// <summary> /// Create a new StringRebuilder equivalent to replacing a contiguous span of characters /// with different text. /// </summary> /// <param name="span"> /// Span of text in this <see cref="StringRebuilder"/> to replace. /// </param> /// <param name="text"> /// The new text to replace the old. /// </param> /// <returns> /// A new string rebuilder containing the replacement. /// </returns> /// <remarks> /// <para>this <see cref="StringRebuilder"/> is not modified.</para> /// <para>This operation can be performed simultaneously on multiple threads.</para> /// </remarks> /// <exception cref="ArgumentOutOfRangeException"><paramref name="span"/>.End is greater than <see cref="Length"/>.</exception> /// <exception cref="ArgumentNullException"><paramref name="text"/> is null.</exception> public StringRebuilder Replace(Span span, StringRebuilder text) { if (span.End > this.Length) { throw new ArgumentOutOfRangeException("span"); } if (text == null) { throw new ArgumentNullException("text"); } return(this.Assemble(Span.FromBounds(0, span.Start), text, Span.FromBounds(span.End, this.Length))); }
/// <summary> /// Create a new StringRebuilder equivalent to inserting text into this <see cref="StringRebuilder"/>. /// </summary> /// <param name="position">Position at which to insert.</param> /// <param name="text">Text to insert.</param> /// <returns>A new StringRebuilder containing the insertion.</returns> /// <remarks> /// <para>this <see cref="StringRebuilder"/> is not modified.</para> /// <para>This operation can be performed simultaneously on multiple threads.</para> /// </remarks> /// <exception cref="ArgumentOutOfRangeException"><paramref name="position"/> is less than zero or greater than <see cref="Length"/>.</exception> /// <exception cref="ArgumentNullException"><paramref name="text"/> is null.</exception> public StringRebuilder Insert(int position, StringRebuilder text) { if ((position < 0) || (position > this.Length)) { throw new ArgumentOutOfRangeException("position"); } if (text == null) { throw new ArgumentNullException("text"); } return(this.Assemble(Span.FromBounds(0, position), text, Span.FromBounds(position, this.Length))); }
public ITextBuffer CreateTextBuffer(ITextImage image, IContentType contentType) { if (image == null) { throw new ArgumentNullException(nameof(image)); } if (contentType == null) { throw new ArgumentNullException(nameof(contentType)); } StringRebuilder content = StringRebuilder.Create(image); return(Make(contentType, content, false)); }
private static StringRebuilder BalanceTreeNode(StringRebuilder left, StringRebuilder right) { if (left.Depth > right.Depth + 1) { return(BinaryStringRebuilder.Pivot(left, right, false)); } else if (right.Depth > left.Depth + 1) { return(BinaryStringRebuilder.Pivot(right, left, true)); } else { return(new BinaryStringRebuilder(left, right)); } }
public static StringRebuilder Create(ITextStorageLoader loader) { if (loader == null) { throw new ArgumentNullException("loader"); } StringRebuilder content = _empty; foreach (ITextStorage storage in loader.Load()) { content = content.Insert(content.Length, storage); } return(content); }
internal static ChangeString CreateChangeString(StringRebuilder content) { if (content.Length == 0) { return(ChangeString.EmptyChangeString); } else if (content.Length <= ChangeString.LiteralStringThreshold) { return(new LiteralChangeString(content.GetText(new Span(0, content.Length)))); } else { return(new ReferenceChangeString(content)); } }
// internal for unit tests, a \r\n can't be spanned by left and right internal BinaryStringRebuilder(StringRebuilder left, StringRebuilder right) : base(left.Length + right.Length, left.LineBreakCount + right.LineBreakCount, left.FirstCharacter, right.LastCharacter) { Debug.Assert(left.Length > 0); Debug.Assert(right.Length > 0); Debug.Assert(Math.Abs(left.Depth - right.Depth) <= 1); Debug.Assert(left.LastCharacter != '\r' || right.FirstCharacter != '\n'); #if DEBUG Interlocked.Increment(ref _totalCreated); #endif _left = left; _right = right; this.Depth = 1 + Math.Max(left.Depth, right.Depth); }
private void ReloadBufferFromStream(Stream stream, long fileSize, EditOptions options, Encoding encoding) { using (var streamReader = new EncodedStreamReader.NonStreamClosingStreamReader(stream, encoding, detectEncodingFromByteOrderMarks: false)) { TextBuffer concreteBuffer = _textBuffer as TextBuffer; if (concreteBuffer != null) { StringRebuilder newContent = TextImageLoader.Load( streamReader, fileSize, out var newlineState, out var leadingWhitespaceState, out var longestLineLength); if (!newlineState.HasConsistentLineEndings) { // leave a sign that line endings are inconsistent. This is rather nasty but for now // we don't want to pollute the API with this factoid. concreteBuffer.Properties["InconsistentLineEndings"] = true; } else { // this covers a really obscure case where on initial load the file had inconsistent line // endings, but the UI settings were such that it was ignored, and since then the file has // acquired consistent line endings and the UI settings have also changed. concreteBuffer.Properties.RemoveProperty("InconsistentLineEndings"); } // leave a similar sign about the longest line in the buffer. concreteBuffer.Properties["LongestLineLength"] = longestLineLength; concreteBuffer.ReloadContent(newContent, options, editTag: this); } else { // we may hit this path if somebody mocks the text buffer in a test. using (var edit = _textBuffer.CreateEdit(options, null, editTag: this)) { if (edit.Replace(new Span(0, edit.Snapshot.Length), streamReader.ReadToEnd())) { edit.Apply(); } else { edit.Cancel(); } } } } }
public static StringRebuilder Create(ITextImage image) { if (image == null) { throw new ArgumentNullException(nameof(image)); } var cti = image as CachingTextImage; if (cti != null) { return(cti.Builder); } // This shouldn't happen but as a fallback, create a new string rebuilder from the text of the provided image. return(StringRebuilder.Create(image.GetText(0, image.Length))); }
internal static StringRebuilder AppendStringRebuildersFromSnapshotAndSpan(StringRebuilder content, ITextSnapshot snapshot, Span span) { var baseSnapshot = snapshot as BaseSnapshot; if (baseSnapshot != null) { content = content.Append(baseSnapshot.Content.GetSubText(span)); } else { // The we don't know what to do fallback. This should never be called unless someone provides a new snapshot // implementation. content = content.Append(snapshot.GetText(span)); } return(content); }