Ejemplo n.º 1
0
        public IProjectionBuffer CreateProjectionBuffer(IProjectionEditResolver projectionEditResolver,
                                                        IList <object> trackingSpans,
                                                        ProjectionBufferOptions options)
        {
            // projectionEditResolver is allowed to be null.
            if (trackingSpans == null)
            {
                throw new ArgumentNullException(nameof(trackingSpans));
            }

            IProjectionBuffer buffer =
                new ProjectionBuffer(this, projectionEditResolver, ProjectionContentType, trackingSpans, _differenceService, _textDifferencingSelectorService.DefaultTextDifferencingService, options, _guardedOperations);

            RaiseProjectionBufferCreatedEvent(buffer);
            return(buffer);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Creates a TestHostDocument backed by a projection buffer. The surface buffer is
        /// described by a markup string with {|name:|} style pointers to annotated spans that can
        /// be found in one of a set of provided documents. Unnamed spans in the documents (which
        /// must have both endpoints inside an annotated spans) and in the surface buffer markup are
        /// mapped and included in the resulting document.
        ///
        /// If the markup string has the caret indicator "$$", then the caret will be placed at the
        /// corresponding position. If it does not, then the first span mapped into the projection
        /// buffer that contains the caret from its document is used.
        ///
        /// The result is a new TestHostDocument backed by a projection buffer including tracking
        /// spans from any number of documents and inert text from the markup itself.
        ///
        /// As an example, consider surface buffer markup
        ///  ABC [|DEF|] [|GHI[|JKL|]|]{|S1:|} [|MNO{|S2:|}PQR S$$TU|] {|S4:|}{|S5:|}{|S3:|}
        ///
        /// This contains 4 unnamed spans and references to 5 spans that should be found and
        /// included. Consider an included base document created from the following markup:
        ///
        ///  public class C
        ///  {
        ///      public void M1()
        ///      {
        ///          {|S1:int [|abc[|d$$ef|]|] = goo;|}
        ///          int y = goo;
        ///          {|S2:int [|def|] = goo;|}
        ///          int z = {|S3:123|} + {|S4:456|} + {|S5:789|};
        ///      }
        ///  }
        ///
        /// The resulting projection buffer (with unnamed span markup preserved) would look like:
        ///  ABC [|DEF|] [|GHI[|JKL|]|]int [|abc[|d$$ef|]|] = goo; [|MNOint [|def|] = goo;PQR S$$TU|] 456789123
        ///
        /// The union of unnamed spans from the surface buffer markup and each of the projected
        /// spans is sorted as it would have been sorted by MarkupTestFile had it parsed the entire
        /// projection buffer as one file, which it would do in a stack-based manner. In our example,
        /// the order of the unnamed spans would be as follows:
        ///
        ///  ABC [|DEF|] [|GHI[|JKL|]|]int [|abc[|d$$ef|]|] = goo; [|MNOint [|def|] = goo;PQR S$$TU|] 456789123
        ///       -----1       -----2            -------4                    -----6
        ///               ------------3     --------------5         --------------------------------7
        /// </summary>
        /// <param name="markup">Describes the surface buffer, and contains a mix of inert text,
        /// named spans and unnamed spans. Any named spans must contain only the name portion
        /// (e.g. {|Span1:|} which must match the name of a span in one of the baseDocuments.
        /// Annotated spans cannot be nested but they can be adjacent, in which case order will be
        /// preserved. The markup may also contain the caret indicator.</param>
        /// <param name="baseDocuments">The set of documents from which the projection buffer
        /// document will be composed.</param>
        /// <returns></returns>
        public TestHostDocument CreateProjectionBufferDocument(
            string markup,
            IList <TestHostDocument> baseDocuments,
            string path = "projectionbufferdocumentpath",
            ProjectionBufferOptions options      = ProjectionBufferOptions.None,
            IProjectionEditResolver?editResolver = null)
        {
            GetSpansAndCaretFromSurfaceBufferMarkup(markup, baseDocuments,
                                                    out var projectionBufferSpans, out var mappedSpans, out var mappedCaretLocation);

            var projectionBufferFactory = this.GetService <IProjectionBufferFactoryService>();
            var projectionBuffer        = projectionBufferFactory.CreateProjectionBuffer(editResolver, projectionBufferSpans, options);

            // Add in mapped spans from each of the base documents
            foreach (var document in baseDocuments)
            {
                mappedSpans[string.Empty] = mappedSpans.ContainsKey(string.Empty)
                    ? mappedSpans[string.Empty]
                    : ImmutableArray <TextSpan> .Empty;
                foreach (var span in document.SelectedSpans)
                {
                    var snapshotSpan = span.ToSnapshotSpan(document.GetTextBuffer().CurrentSnapshot);
                    var mappedSpan   = projectionBuffer.CurrentSnapshot.MapFromSourceSnapshot(snapshotSpan).Single();
                    mappedSpans[string.Empty] = mappedSpans[string.Empty].Add(mappedSpan.ToTextSpan());
                }

                // Order unnamed spans as they would be ordered by the normal span finding
                // algorithm in MarkupTestFile
                mappedSpans[string.Empty] = mappedSpans[string.Empty].OrderBy(s => s.End).ThenBy(s => - s.Start).ToImmutableArray();

                foreach (var(key, spans) in document.AnnotatedSpans)
                {
                    mappedSpans[key] = mappedSpans.ContainsKey(key)
                        ? mappedSpans[key]
                        : ImmutableArray <TextSpan> .Empty;

                    foreach (var span in spans)
                    {
                        var snapshotSpan = span.ToSnapshotSpan(document.GetTextBuffer().CurrentSnapshot);
                        var mappedSpan   = projectionBuffer.CurrentSnapshot.MapFromSourceSnapshot(snapshotSpan).Cast <Span?>().SingleOrDefault();
                        if (mappedSpan == null)
                        {
                            // not all span on subject buffer needs to exist on surface buffer
                            continue;
                        }

                        // but if they do, it must be only 1
                        mappedSpans[key] = mappedSpans[key].Add(mappedSpan.Value.ToTextSpan());
                    }
                }
            }

            var projectionDocument = new TestHostDocument(
                ExportProvider,
                languageServiceProvider: null,
                projectionBuffer.CurrentSnapshot.GetText(),
                path,
                mappedCaretLocation,
                mappedSpans,
                textBuffer: projectionBuffer);

            this.ProjectionDocuments.Add(projectionDocument);
            return(projectionDocument);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Creates a TestHostDocument backed by a projection buffer. The surface buffer is
        /// described by a markup string with {|name:|} style pointers to annotated spans that can
        /// be found in one of a set of provided documents. Unnamed spans in the documents (which
        /// must have both endpoints inside an annotated spans) and in the surface buffer markup are
        /// mapped and included in the resulting document.
        ///
        /// If the markup string has the caret indicator "$$", then the caret will be placed at the
        /// corresponding position. If it does not, then the first span mapped into the projection
        /// buffer that contains the caret from its document is used.
        ///
        /// The result is a new TestHostDocument backed by a projection buffer including tracking
        /// spans from any number of documents and inert text from the markup itself.
        ///
        /// As an example, consider surface buffer markup
        ///  ABC [|DEF|] [|GHI[|JKL|]|]{|S1:|} [|MNO{|S2:|}PQR S$$TU|] {|S4:|}{|S5:|}{|S3:|}
        ///
        /// This contains 4 unnamed spans and references to 5 spans that should be found and
        /// included. Consider an included base document created from the following markup:
        ///
        ///  public class C
        ///  {
        ///      public void M1()
        ///      {
        ///          {|S1:int [|abc[|d$$ef|]|] = foo;|}
        ///          int y = foo;
        ///          {|S2:int [|def|] = foo;|}
        ///          int z = {|S3:123|} + {|S4:456|} + {|S5:789|};
        ///      }
        ///  }
        ///
        /// The resulting projection buffer (with unnamed span markup preserved) would look like:
        ///  ABC [|DEF|] [|GHI[|JKL|]|]int [|abc[|d$$ef|]|] = foo; [|MNOint [|def|] = foo;PQR S$$TU|] 456789123
        ///
        /// The union of unnamed spans from the surface buffer markup and each of the projected
        /// spans is sorted as it would have been sorted by MarkupTestFile had it parsed the entire
        /// projection buffer as one file, which it would do in a stack-based manner. In our example,
        /// the order of the unnamed spans would be as follows:
        ///
        ///  ABC [|DEF|] [|GHI[|JKL|]|]int [|abc[|d$$ef|]|] = foo; [|MNOint [|def|] = foo;PQR S$$TU|] 456789123
        ///       -----1       -----2            -------4                    -----6
        ///               ------------3     --------------5         --------------------------------7
        /// </summary>
        /// <param name="markup">Describes the surface buffer, and contains a mix of inert text,
        /// named spans and unnamed spans. Any named spans must contain only the name portion
        /// (e.g. {|Span1:|} which must match the name of a span in one of the baseDocuments.
        /// Annotated spans cannot be nested but they can be adjacent, in which case order will be
        /// preserved. The markup may also contain the caret indicator.</param>
        /// <param name="baseDocuments">The set of documents from which the projection buffer
        /// document will be composed.</param>
        /// <returns></returns>
        public TestHostDocument CreateProjectionBufferDocument(string markup, IList <TestHostDocument> baseDocuments, string languageName, string path = "projectionbufferdocumentpath", ProjectionBufferOptions options = ProjectionBufferOptions.None, IProjectionEditResolver editResolver = null)
        {
            IList <object> projectionBufferSpans;
            Dictionary <string, IList <TextSpan> > mappedSpans;
            int?mappedCaretLocation;

            GetSpansAndCaretFromSurfaceBufferMarkup(markup, baseDocuments, out projectionBufferSpans, out mappedSpans, out mappedCaretLocation);

            var projectionBufferFactory = this.GetService <IProjectionBufferFactoryService>();
            var projectionBuffer        = projectionBufferFactory.CreateProjectionBuffer(editResolver, projectionBufferSpans, options);

            // Add in mapped spans from each of the base documents
            foreach (var document in baseDocuments)
            {
                mappedSpans[string.Empty] = mappedSpans.ContainsKey(string.Empty) ? mappedSpans[string.Empty] : new List <TextSpan>();
                foreach (var span in document.SelectedSpans)
                {
                    var snapshotSpan = span.ToSnapshotSpan(document.TextBuffer.CurrentSnapshot);
                    var mappedSpan   = projectionBuffer.CurrentSnapshot.MapFromSourceSnapshot(snapshotSpan).Single();
                    mappedSpans[string.Empty].Add(mappedSpan.ToTextSpan());
                }

                // Order unnamed spans as they would be ordered by the normal span finding
                // algorithm in MarkupTestFile
                mappedSpans[string.Empty] = mappedSpans[string.Empty].OrderBy(s => s.End).ThenBy(s => - s.Start).ToList();

                foreach (var kvp in document.AnnotatedSpans)
                {
                    mappedSpans[kvp.Key] = mappedSpans.ContainsKey(kvp.Key) ? mappedSpans[kvp.Key] : new List <TextSpan>();

                    foreach (var span in kvp.Value)
                    {
                        var snapshotSpan = span.ToSnapshotSpan(document.TextBuffer.CurrentSnapshot);
                        var mappedSpan   = projectionBuffer.CurrentSnapshot.MapFromSourceSnapshot(snapshotSpan).Single();
                        mappedSpans[kvp.Key].Add(mappedSpan.ToTextSpan());
                    }
                }
            }

            var languageServices = this.Services.GetLanguageServices(languageName);

            var projectionDocument = new TestHostDocument(
                TestExportProvider.ExportProviderWithCSharpAndVisualBasic,
                languageServices,
                projectionBuffer,
                path,
                mappedCaretLocation,
                mappedSpans);

            this.ProjectionDocuments.Add(projectionDocument);
            return(projectionDocument);
        }