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)); }
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); }
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); }
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)); }
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); }