示例#1
0
 public TextSnapshot(ITextBuffer textBuffer, ITextVersion version, StringRebuilder content)
     : base(version)
 {
     System.Diagnostics.Debug.Assert(version.Length == content.Length);
     this.textBuffer = textBuffer;
     this.content    = content;
 }
示例#2
0
        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);
        }
示例#3
0
        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))));
     }
 }
示例#5
0
        private TextBuffer Make(IContentType contentType, StringRebuilder content, bool spurnGroup)
        {
            TextBuffer buffer = new TextBuffer(contentType, content, _textDifferencingSelectorService.DefaultTextDifferencingService, _guardedOperations, spurnGroup);

            RaiseTextBufferCreatedEvent(buffer);
            return(buffer);
        }
示例#6
0
        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);
        }
示例#8
0
        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));
        }
示例#9
0
 /// <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));
     }
 }
示例#10
0
        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;
        }
示例#11
0
        /// <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));
        }
示例#12
0
 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;
        }
示例#14
0
        private CachingTextImage(StringRebuilder builder, ITextImageVersion version)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            this.Builder = builder;
            this.Version = version;
        }
示例#15
0
        public ITextBuffer CreateTextBuffer(SnapshotSpan span, IContentType contentType)
        {
            if (contentType == null)
            {
                throw new ArgumentNullException(nameof(contentType));
            }

            StringRebuilder content = StringRebuilderFromSnapshotSpan(span);

            return(Make(contentType, content, false));
        }
示例#16
0
 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));
 }
示例#17
0
        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)));
        }
示例#19
0
        /// <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));
     }
 }
示例#21
0
        /// <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)));
        }
示例#22
0
        /// <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)));
        }
示例#23
0
        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);
        }
示例#26
0
 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));
     }
 }
示例#27
0
        // 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);
        }
示例#28
0
        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();
                        }
                    }
                }
            }
        }
示例#29
0
        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);
        }