private async ValueTask <DifferenceViewerPreview> CreateNewDifferenceViewerAsync(
            PreviewWorkspace?leftWorkspace, PreviewWorkspace?rightWorkspace,
            IProjectionBuffer originalBuffer, IProjectionBuffer changedBuffer,
            double zoomLevel, CancellationToken cancellationToken)
        {
            // IWpfDifferenceViewerFactoryService is a Visual Studio API which is not documented as free-threaded
            await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

            // leftWorkspace can be null if the change is adding a document.
            // rightWorkspace can be null if the change is removing a document.
            // However both leftWorkspace and rightWorkspace can't be null at the same time.
            Contract.ThrowIfTrue((leftWorkspace == null) && (rightWorkspace == null));

            var diffBuffer = _differenceBufferService.CreateDifferenceBuffer(
                originalBuffer, changedBuffer,
                new StringDifferenceOptions(), disableEditing: true);

            var mode = leftWorkspace == null ? DifferenceViewMode.RightViewOnly :
                       rightWorkspace == null ? DifferenceViewMode.LeftViewOnly :
                       DifferenceViewMode.Inline;

            var diffViewer = await CreateDifferenceViewAsync(diffBuffer, _previewRoleSet, mode, zoomLevel, cancellationToken).ConfigureAwait(true);

            diffViewer.Closed += (s, e) =>
            {
                // Workaround Editor bug.  The editor has an issue where they sometimes crash when
                // trying to apply changes to projection buffer.  So, when the user actually invokes
                // a SuggestedAction we may then edit a text buffer, which the editor will then
                // try to propagate through the projections we have here over that buffer.  To ensure
                // that that doesn't happen, we clear out the projections first so that this crash
                // won't happen.
                originalBuffer.DeleteSpans(0, originalBuffer.CurrentSnapshot.SpanCount);
                changedBuffer.DeleteSpans(0, changedBuffer.CurrentSnapshot.SpanCount);

                leftWorkspace?.Dispose();
                leftWorkspace = null;

                rightWorkspace?.Dispose();
                rightWorkspace = null;
            };

            leftWorkspace?.EnableDiagnostic();
            rightWorkspace?.EnableDiagnostic();

            return(new DifferenceViewerPreview(diffViewer));
        }
예제 #2
0
        public async Task TestPreviewDiagnosticTagger()
        {
            using var workspace = TestWorkspace.CreateCSharp(
                      "class { }",
                      composition: EditorTestCompositions.EditorFeatures
                      );
            using var previewWorkspace = new PreviewWorkspace(workspace.CurrentSolution);

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

            previewWorkspace.TryApplyChanges(
                previewWorkspace.CurrentSolution.WithAnalyzerReferences(
                    new[]
            {
                DiagnosticExtensions.GetCompilerDiagnosticAnalyzerReference(
                    LanguageNames.CSharp
                    )
            }
                    )
                );

            // enable preview diagnostics
            previewWorkspace.EnableDiagnostic();

            var diagnosticsAndErrorsSpans =
                await SquiggleUtilities.GetDiagnosticsAndErrorSpansAsync <DiagnosticsSquiggleTaggerProvider>(
                    workspace
                    );

            const string AnalyzerCount = "Analyzer Count: ";

            Assert.Equal(AnalyzerCount + 1, AnalyzerCount + diagnosticsAndErrorsSpans.Item1.Length);

            const string SquigglesCount = "Squiggles Count: ";

            Assert.Equal(
                SquigglesCount + 1,
                SquigglesCount + diagnosticsAndErrorsSpans.Item2.Length
                );
        }
        public async Task TestPreviewDiagnostic()
        {
            var hostServices   = EditorTestCompositions.EditorFeatures.GetHostServices();
            var exportProvider = (IMefHostExportProvider)hostServices;

            var diagnosticService = (IDiagnosticUpdateSource)exportProvider.GetExportedValue <IDiagnosticAnalyzerService>();

            RoslynDebug.AssertNotNull(diagnosticService);
            var globalOptions = exportProvider.GetExportedValue <IGlobalOptionService>();

            var taskSource = new TaskCompletionSource <DiagnosticsUpdatedArgs>();

            diagnosticService.DiagnosticsUpdated += (s, a) => taskSource.TrySetResult(a);

            using var previewWorkspace = new PreviewWorkspace(hostServices);

            var solution = previewWorkspace.CurrentSolution
                           .WithAnalyzerReferences(new[] { DiagnosticExtensions.GetCompilerDiagnosticAnalyzerReference(LanguageNames.CSharp) })
                           .AddProject("project", "project.dll", LanguageNames.CSharp)
                           .AddDocument("document", "class { }")
                           .Project
                           .Solution;

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

            var document = previewWorkspace.CurrentSolution.Projects.First().Documents.Single();

            previewWorkspace.OpenDocument(document.Id, (await document.GetTextAsync()).Container);
            previewWorkspace.EnableDiagnostic();

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

            var args = taskSource.Task.Result;

            Assert.True(args.GetPushDiagnostics(globalOptions, InternalDiagnosticsOptions.NormalDiagnosticMode).Length > 0);
        }
예제 #4
0
        private async Task <object> CreateNewDifferenceViewerAsync(PreviewWorkspace leftWorkspace, PreviewWorkspace rightWorkspace,
                                                                   IProjectionBuffer originalBuffer, IProjectionBuffer changedBuffer, double zoomLevel, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // leftWorkspace can be null if the change is adding a document.
            // rightWorkspace can be null if the change is removing a document.
            // However both leftWorkspace and rightWorkspace can't be null at the same time.
            Contract.ThrowIfTrue((leftWorkspace == null) && (rightWorkspace == null));

            var diffBuffer = _differenceBufferService.CreateDifferenceBuffer(
                originalBuffer, changedBuffer,
                new StringDifferenceOptions(), disableEditing: true);

            var diffViewer = _differenceViewerService.CreateDifferenceView(diffBuffer, _previewRoleSet);

            diffViewer.Closed += (s, e) =>
            {
                if (leftWorkspace != null)
                {
                    leftWorkspace.Dispose();
                    leftWorkspace = null;
                }

                if (rightWorkspace != null)
                {
                    rightWorkspace.Dispose();
                    rightWorkspace = null;
                }
            };

            const string DiffOverviewMarginName = "deltadifferenceViewerOverview";

            if (leftWorkspace == null)
            {
                diffViewer.ViewMode             = DifferenceViewMode.RightViewOnly;
                diffViewer.RightView.ZoomLevel *= zoomLevel;
                diffViewer.RightHost.GetTextViewMargin(DiffOverviewMarginName).VisualElement.Visibility = Visibility.Collapsed;
            }
            else if (rightWorkspace == null)
            {
                diffViewer.ViewMode            = DifferenceViewMode.LeftViewOnly;
                diffViewer.LeftView.ZoomLevel *= zoomLevel;
                diffViewer.LeftHost.GetTextViewMargin(DiffOverviewMarginName).VisualElement.Visibility = Visibility.Collapsed;
            }
            else
            {
                diffViewer.ViewMode              = DifferenceViewMode.Inline;
                diffViewer.InlineView.ZoomLevel *= zoomLevel;
                diffViewer.InlineHost.GetTextViewMargin(DiffOverviewMarginName).VisualElement.Visibility = Visibility.Collapsed;
            }

            // Disable focus / tab stop for the diff viewer.
            diffViewer.RightView.VisualElement.Focusable  = false;
            diffViewer.LeftView.VisualElement.Focusable   = false;
            diffViewer.InlineView.VisualElement.Focusable = false;

            // This code path must be invoked on UI thread.
            AssertIsForeground();

            // We use ConfigureAwait(true) to stay on the UI thread.
            await diffViewer.SizeToFitAsync().ConfigureAwait(true);

            if (leftWorkspace != null)
            {
                leftWorkspace.EnableDiagnostic();
            }

            if (rightWorkspace != null)
            {
                rightWorkspace.EnableDiagnostic();
            }

            return(diffViewer);
        }
예제 #5
0
        private async Task <object> CreateNewDifferenceViewerAsync(
            PreviewWorkspace leftWorkspace, PreviewWorkspace rightWorkspace,
            IProjectionBuffer originalBuffer, IProjectionBuffer changedBuffer,
            double zoomLevel, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // leftWorkspace can be null if the change is adding a document.
            // rightWorkspace can be null if the change is removing a document.
            // However both leftWorkspace and rightWorkspace can't be null at the same time.
            Contract.ThrowIfTrue((leftWorkspace == null) && (rightWorkspace == null));

            var diffBuffer = _differenceBufferService.CreateDifferenceBuffer(
                originalBuffer, changedBuffer,
                new StringDifferenceOptions(), disableEditing: true);

            var diffViewer = _differenceViewerService.CreateDifferenceView(diffBuffer, _previewRoleSet);

            diffViewer.Closed += (s, e) =>
            {
                // Workaround Editor bug.  The editor has an issue where they sometimes crash when
                // trying to apply changes to projection buffer.  So, when the user actually invokes
                // a SuggestedAction we may then edit a text buffer, which the editor will then
                // try to propagate through the projections we have here over that buffer.  To ensure
                // that that doesn't happen, we clear out the projections first so that this crash
                // won't happen.
                originalBuffer.DeleteSpans(0, originalBuffer.CurrentSnapshot.SpanCount);
                changedBuffer.DeleteSpans(0, changedBuffer.CurrentSnapshot.SpanCount);

                leftWorkspace?.Dispose();
                leftWorkspace = null;

                rightWorkspace?.Dispose();
                rightWorkspace = null;
            };

            const string DiffOverviewMarginName = "deltadifferenceViewerOverview";

            if (leftWorkspace == null)
            {
                diffViewer.ViewMode             = DifferenceViewMode.RightViewOnly;
                diffViewer.RightView.ZoomLevel *= zoomLevel;
                diffViewer.RightHost.GetTextViewMargin(DiffOverviewMarginName).VisualElement.Visibility = Visibility.Collapsed;
            }
            else if (rightWorkspace == null)
            {
                diffViewer.ViewMode            = DifferenceViewMode.LeftViewOnly;
                diffViewer.LeftView.ZoomLevel *= zoomLevel;
                diffViewer.LeftHost.GetTextViewMargin(DiffOverviewMarginName).VisualElement.Visibility = Visibility.Collapsed;
            }
            else
            {
                diffViewer.ViewMode              = DifferenceViewMode.Inline;
                diffViewer.InlineView.ZoomLevel *= zoomLevel;
                diffViewer.InlineHost.GetTextViewMargin(DiffOverviewMarginName).VisualElement.Visibility = Visibility.Collapsed;
            }

            // Disable focus / tab stop for the diff viewer.
            diffViewer.RightView.VisualElement.Focusable  = false;
            diffViewer.LeftView.VisualElement.Focusable   = false;
            diffViewer.InlineView.VisualElement.Focusable = false;

            // This code path must be invoked on UI thread.
            AssertIsForeground();

            // We use ConfigureAwait(true) to stay on the UI thread.
            await diffViewer.SizeToFitAsync(ThreadingContext).ConfigureAwait(true);

            leftWorkspace?.EnableDiagnostic();
            rightWorkspace?.EnableDiagnostic();

            return(new DifferenceViewerPreview(diffViewer));
        }
예제 #6
0
        private IWpfDifferenceViewer CreateNewDifferenceViewer(PreviewWorkspace leftWorkspace, PreviewWorkspace rightWorkspace,
                                                               IProjectionBuffer originalBuffer, IProjectionBuffer changedBuffer, double zoomLevel)
        {
            // leftWorkspace can be null if the change is adding a document.
            // rightWorkspace can be null if the change is removing a document.
            // However both leftWorkspace and rightWorkspace can't be null at the same time.
            Contract.ThrowIfTrue((leftWorkspace == null) && (rightWorkspace == null));

            var diffBuffer = _differenceBufferService.CreateDifferenceBuffer(
                originalBuffer, changedBuffer,
                new StringDifferenceOptions(), disableEditing: true);

            var diffViewer = _differenceViewerService.CreateDifferenceView(diffBuffer, _previewRoleSet);

            diffViewer.Closed += (s, e) =>
            {
                if (leftWorkspace != null)
                {
                    leftWorkspace.Dispose();
                    leftWorkspace = null;
                }

                if (rightWorkspace != null)
                {
                    rightWorkspace.Dispose();
                    rightWorkspace = null;
                }
            };

            const string DiffOverviewMarginName = "deltadifferenceViewerOverview";

            if (leftWorkspace == null)
            {
                diffViewer.ViewMode             = DifferenceViewMode.RightViewOnly;
                diffViewer.RightView.ZoomLevel *= zoomLevel;
                diffViewer.RightHost.GetTextViewMargin(DiffOverviewMarginName).VisualElement.Visibility = Visibility.Collapsed;
            }
            else if (rightWorkspace == null)
            {
                diffViewer.ViewMode            = DifferenceViewMode.LeftViewOnly;
                diffViewer.LeftView.ZoomLevel *= zoomLevel;
                diffViewer.LeftHost.GetTextViewMargin(DiffOverviewMarginName).VisualElement.Visibility = Visibility.Collapsed;
            }
            else
            {
                diffViewer.ViewMode              = DifferenceViewMode.Inline;
                diffViewer.InlineView.ZoomLevel *= zoomLevel;
                diffViewer.InlineHost.GetTextViewMargin(DiffOverviewMarginName).VisualElement.Visibility = Visibility.Collapsed;
            }

            // Disable focus / tab stop for the diff viewer.
            diffViewer.RightView.VisualElement.Focusable  = false;
            diffViewer.LeftView.VisualElement.Focusable   = false;
            diffViewer.InlineView.VisualElement.Focusable = false;

            diffViewer.SizeToFit();

            if (leftWorkspace != null)
            {
                leftWorkspace.EnableDiagnostic();
            }

            if (rightWorkspace != null)
            {
                rightWorkspace.EnableDiagnostic();
            }

            return(diffViewer);
        }