Exemplo n.º 1
0
        public Task<object> CreateChangedDocumentPreviewViewAsync(Document oldDocument, Document newDocument, double zoomLevel, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Note: We don't use the original buffer that is associated with oldDocument
            // (and currently open in the editor) for oldBuffer below. This is because oldBuffer
            // will be used inside a projection buffer inside our inline diff preview below
            // and platform's implementation currently has a bug where projection buffers
            // are being leaked. This leak means that if we use the original buffer that is
            // currently visible in the editor here, the projection buffer span calculation
            // would be triggered every time user changes some code in this buffer (even though
            // the diff view would long have been dismissed by the time user edits the code)
            // resulting in crashes. Instead we create a new buffer from the same content.
            // TODO: We could use ITextBufferCloneService instead here to clone the original buffer.
            var oldBuffer = CreateNewBuffer(oldDocument, cancellationToken);
            var newBuffer = CreateNewBuffer(newDocument, cancellationToken);

            // Convert the diffs to be line based.  
            // Compute the diffs between the old text and the new.
            var diffResult = ComputeEditDifferences(oldDocument, newDocument, cancellationToken);

            // Need to show the spans in the right that are different.
            // We also need to show the spans that are in conflict.
            var originalSpans = GetOriginalSpans(diffResult, cancellationToken);
            var changedSpans = GetChangedSpans(diffResult, cancellationToken);
            var description = default(string);
            var allSpans = default(NormalizedSpanCollection);

            if (newDocument.SupportsSyntaxTree)
            {
                var newRoot = newDocument.GetSyntaxRootSynchronously(cancellationToken);
                var conflictNodes = newRoot.GetAnnotatedNodesAndTokens(ConflictAnnotation.Kind);
                var conflictSpans = conflictNodes.Select(n => n.Span.ToSpan()).ToList();
                var conflictDescriptions = conflictNodes.SelectMany(n => n.GetAnnotations(ConflictAnnotation.Kind))
                                                        .Select(a => ConflictAnnotation.GetDescription(a))
                                                        .Distinct();

                var warningNodes = newRoot.GetAnnotatedNodesAndTokens(WarningAnnotation.Kind);
                var warningSpans = warningNodes.Select(n => n.Span.ToSpan()).ToList();
                var warningDescriptions = warningNodes.SelectMany(n => n.GetAnnotations(WarningAnnotation.Kind))
                                                        .Select(a => WarningAnnotation.GetDescription(a))
                                                        .Distinct();

                var suppressDiagnosticsNodes = newRoot.GetAnnotatedNodesAndTokens(SuppressDiagnosticsAnnotation.Kind);
                var suppressDiagnosticsSpans = suppressDiagnosticsNodes.Select(n => n.Span.ToSpan()).ToList();
                AttachAnnotationsToBuffer(newBuffer, conflictSpans, warningSpans, suppressDiagnosticsSpans);

                description = conflictSpans.Count == 0 && warningSpans.Count == 0
                    ? null
                    : string.Join(Environment.NewLine, conflictDescriptions.Concat(warningDescriptions));
                allSpans = new NormalizedSpanCollection(conflictSpans.Concat(warningSpans).Concat(changedSpans));
            }
            else
            {
                allSpans = new NormalizedSpanCollection(changedSpans);
            }

            var originalLineSpans = CreateLineSpans(oldBuffer.CurrentSnapshot, originalSpans, cancellationToken);
            var changedLineSpans = CreateLineSpans(newBuffer.CurrentSnapshot, allSpans, cancellationToken);
            if (!originalLineSpans.Any())
            {
                // This means that we have no differences (likely because of conflicts).
                // In such cases, use the same spans for the left (old) buffer as the right (new) buffer.
                originalLineSpans = changedLineSpans;
            }

            // Create PreviewWorkspaces around the buffers to be displayed on the left and right
            // so that all IDE services (colorizer, squiggles etc.) light up in these buffers.
            var leftDocument = oldDocument.Project
                .RemoveDocument(oldDocument.Id)
                .AddDocument(oldDocument.Name, oldBuffer.AsTextContainer().CurrentText, oldDocument.Folders, oldDocument.FilePath);
            var leftWorkspace = new PreviewWorkspace(leftDocument.Project.Solution);
            leftWorkspace.OpenDocument(leftDocument.Id);

            var rightWorkspace = new PreviewWorkspace(
                newDocument.WithText(newBuffer.AsTextContainer().CurrentText).Project.Solution);
            rightWorkspace.OpenDocument(newDocument.Id);

            return CreateChangedDocumentViewAsync(
                oldBuffer, newBuffer, description, originalLineSpans, changedLineSpans,
                leftWorkspace, rightWorkspace, zoomLevel, cancellationToken);
        }
Exemplo n.º 2
0
        public Task<object> CreateAddedDocumentPreviewViewAsync(Document document, double zoomLevel, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var newBuffer = CreateNewBuffer(document, cancellationToken);

            // Create PreviewWorkspace around the buffer to be displayed in the diff preview
            // so that all IDE services (colorizer, squiggles etc.) light up in this buffer.
            var rightWorkspace = new PreviewWorkspace(
                document.WithText(newBuffer.AsTextContainer().CurrentText).Project.Solution);
            rightWorkspace.OpenDocument(document.Id);

            return CreateAddedDocumentPreviewViewCoreAsync(newBuffer, rightWorkspace, document, zoomLevel, cancellationToken);
        }
Exemplo n.º 3
0
        public Task<object> CreateRemovedDocumentPreviewViewAsync(Document document, double zoomLevel, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Note: We don't use the original buffer that is associated with oldDocument
            // (and possibly open in the editor) for oldBuffer below. This is because oldBuffer
            // will be used inside a projection buffer inside our inline diff preview below
            // and platform's implementation currently has a bug where projection buffers
            // are being leaked. This leak means that if we use the original buffer that is
            // currently visible in the editor here, the projection buffer span calculation
            // would be triggered every time user changes some code in this buffer (even though
            // the diff view would long have been dismissed by the time user edits the code)
            // resulting in crashes. Instead we create a new buffer from the same content.
            // TODO: We could use ITextBufferCloneService instead here to clone the original buffer.
            var oldBuffer = CreateNewBuffer(document, cancellationToken);

            // Create PreviewWorkspace around the buffer to be displayed in the diff preview
            // so that all IDE services (colorizer, squiggles etc.) light up in this buffer.
            var leftDocument = document.Project
                .RemoveDocument(document.Id)
                .AddDocument(document.Name, oldBuffer.AsTextContainer().CurrentText);
            var leftWorkspace = new PreviewWorkspace(leftDocument.Project.Solution);
            leftWorkspace.OpenDocument(leftDocument.Id);

            return CreateRemovedDocumentPreviewViewCoreAsync(oldBuffer, leftWorkspace, leftDocument, zoomLevel, cancellationToken);
        }
Exemplo n.º 4
0
        public void TestPreviewDiagnosticTagger()
        {
            using (var workspace = CSharpWorkspaceFactory.CreateWorkspaceFromLines("class { }"))
            using (var previewWorkspace = new PreviewWorkspace(workspace.CurrentSolution))
            {
                // set up to listen diagnostic changes so that we can wait until it happens
                var diagnosticService = workspace.ExportProvider.GetExportedValue<IDiagnosticService>() as DiagnosticService;
                var taskSource = new TaskCompletionSource<DiagnosticsUpdatedArgs>();
                diagnosticService.DiagnosticsUpdated += (s, a) => taskSource.TrySetResult(a);

                // preview workspace and owner of the solution now share solution and its underlying text buffer
                var hostDocument = workspace.Projects.First().Documents.First();
                var buffer = hostDocument.GetTextBuffer();

                // enable preview diagnostics
                previewWorkspace.OpenDocument(hostDocument.Id);
                previewWorkspace.EnableDiagnostic();

                var foregroundService = new TestForegroundNotificationService();
                var optionsService = workspace.Services.GetService<IOptionService>();
                var squiggleWaiter = new ErrorSquiggleWaiter();

                // create a tagger for preview workspace
                var taggerSource = new DiagnosticsSquiggleTaggerProvider.TagSource(buffer, foregroundService, diagnosticService, optionsService, squiggleWaiter);

                // wait up to 20 seconds for diagnostic service
                taskSource.Task.Wait(20000);
                if (!taskSource.Task.IsCompleted)
                {
                    // something is wrong
                    FatalError.Report(new System.Exception("not finished after 20 seconds"));
                }

                // wait for tagger
                squiggleWaiter.CreateWaitTask().PumpingWait();

                var snapshot = buffer.CurrentSnapshot;
                var intervalTree = taggerSource.GetTagIntervalTreeForBuffer(buffer);
                var spans = intervalTree.GetIntersectingSpans(new SnapshotSpan(snapshot, 0, snapshot.Length));

                taggerSource.TestOnly_Dispose();

                Assert.Equal(1, spans.Count);
            }
        }
Exemplo n.º 5
0
        public void TestPreviewDiagnostic()
        {
            var diagnosticService = TestExportProvider.ExportProviderWithCSharpAndVisualBasic.GetExportedValue<IDiagnosticAnalyzerService>() as IDiagnosticUpdateSource;

            var taskSource = new TaskCompletionSource<DiagnosticsUpdatedArgs>();
            diagnosticService.DiagnosticsUpdated += (s, a) => taskSource.TrySetResult(a);

            using (var previewWorkspace = new PreviewWorkspace(MefV1HostServices.Create(TestExportProvider.ExportProviderWithCSharpAndVisualBasic.AsExportProvider())))
            {
                var solution = previewWorkspace.CurrentSolution
                                               .AddProject("project", "project.dll", LanguageNames.CSharp)
                                               .AddDocument("document", "class { }")
                                               .Project
                                               .Solution;

                Assert.True(previewWorkspace.TryApplyChanges(solution));

                previewWorkspace.OpenDocument(previewWorkspace.CurrentSolution.Projects.First().DocumentIds[0]);
                previewWorkspace.EnableDiagnostic();

                // wait 20 seconds
                taskSource.Task.Wait(20000);
                if (!taskSource.Task.IsCompleted)
                {
                    // something is wrong
                    FatalError.Report(new System.Exception("not finished after 20 seconds"));
                }

                var args = taskSource.Task.Result;
                Assert.True(args.Diagnostics.Length > 0);
            }
        }
Exemplo n.º 6
0
        public void TestPreviewOpenCloseFile()
        {
            using (var previewWorkspace = new PreviewWorkspace())
            {
                var solution = previewWorkspace.CurrentSolution;
                var project = solution.AddProject("project", "project.dll", LanguageNames.CSharp);
                var document = project.AddDocument("document", "");

                Assert.True(previewWorkspace.TryApplyChanges(document.Project.Solution));

                previewWorkspace.OpenDocument(document.Id);
                Assert.Equal(1, previewWorkspace.GetOpenDocumentIds().Count());
                Assert.True(previewWorkspace.IsDocumentOpen(document.Id));

                previewWorkspace.CloseDocument(document.Id);
                Assert.Equal(0, previewWorkspace.GetOpenDocumentIds().Count());
                Assert.False(previewWorkspace.IsDocumentOpen(document.Id));
            }
        }
            private DisposableToolTip CreateDisposableToolTip()
            {
                Presenter.AssertIsForeground();

                // Create a new buffer that we'll show a preview for.  We can't search for an 
                // existing buffer because:
                //   1. the file may not be open.
                //   2. our results may not be in sync with what's actually in the editor.
                var textBuffer = CreateNewBuffer();

                // Create the actual tooltip around the region of that text buffer we want to show.
                var toolTip = new ToolTip
                {
                    Content = CreateToolTipContent(textBuffer),
                    Background = (Brush)Application.Current.Resources[EnvironmentColors.ToolWindowBackgroundBrushKey]
                };

                // Create a preview workspace for this text buffer and open it's corresponding 
                // document.  That way we'll get nice things like classification as well as the
                // reference highlight span.
                var newDocument = Document.WithText(textBuffer.AsTextContainer().CurrentText);
                var workspace = new PreviewWorkspace(newDocument.Project.Solution);
                workspace.OpenDocument(newDocument.Id);

                return new DisposableToolTip(toolTip, workspace);
            }
Exemplo n.º 8
0
        public void TestPreviewDiagnostic()
        {
            var diagnosticService = EditorServicesUtil.ExportProvider.GetExportedValue<IDiagnosticAnalyzerService>() as IDiagnosticUpdateSource;

            var taskSource = new TaskCompletionSource<DiagnosticsUpdatedArgs>();
            diagnosticService.DiagnosticsUpdated += (s, a) => taskSource.TrySetResult(a);

            using (var previewWorkspace = new PreviewWorkspace(MefV1HostServices.Create(EditorServicesUtil.ExportProvider.AsExportProvider())))
            {
                var solution = previewWorkspace.CurrentSolution
                                               .AddProject("project", "project.dll", LanguageNames.CSharp)
                                               .AddDocument("document", "class { }")
                                               .Project
                                               .Solution;

                Assert.True(previewWorkspace.TryApplyChanges(solution));

                previewWorkspace.OpenDocument(previewWorkspace.CurrentSolution.Projects.First().DocumentIds[0]);
                previewWorkspace.EnableDiagnostic();

                // wait 20 seconds
                taskSource.Task.Wait(20000);
                Assert.True(taskSource.Task.IsCompleted);

                var args = taskSource.Task.Result;
                Assert.True(args.Diagnostics.Length > 0);
            }
        }