Ejemplo n.º 1
0
        private static void ExecuteAnalyzers(PreviewWorkspace previewWorkspace, ImmutableArray <DiagnosticAnalyzer> analyzers)
        {
            var analyzerOptions                 = new AnalyzerOptions(additionalFiles: ImmutableArray <AdditionalText> .Empty);
            var project                         = previewWorkspace.CurrentSolution.Projects.Single();
            var workspaceAnalyzerOptions        = new WorkspaceAnalyzerOptions(analyzerOptions, project.Solution, IdeAnalyzerOptions.Default);
            var compilationWithAnalyzersOptions = new CompilationWithAnalyzersOptions(workspaceAnalyzerOptions, onAnalyzerException: null, concurrentAnalysis: false, logAnalyzerExecutionTime: false);
            var compilation                     = project.GetRequiredCompilationAsync(CancellationToken.None).Result;
            var compilationWithAnalyzers        = new CompilationWithAnalyzers(compilation, analyzers, compilationWithAnalyzersOptions);
            var result = compilationWithAnalyzers.GetAnalysisResultAsync(CancellationToken.None).Result;

            Assert.Equal(1, result.CompilationDiagnostics.Count);
        }
Ejemplo n.º 2
0
        public void TestPreviewServices()
        {
            using var previewWorkspace = new PreviewWorkspace(EditorTestCompositions.EditorFeatures.GetHostServices());
            var service = previewWorkspace.Services.GetService <ISolutionCrawlerRegistrationService>();

            Assert.IsType <PreviewSolutionCrawlerRegistrationServiceFactory.Service>(service);

            var persistentService = previewWorkspace.Services.GetRequiredService <IPersistentStorageService>();

            using var storage = persistentService.GetStorage(previewWorkspace.CurrentSolution);
            Assert.IsType <NoOpPersistentStorage>(storage);
        }
Ejemplo n.º 3
0
        public void TestPreviewServices()
        {
            using var previewWorkspace = new PreviewWorkspace(VisualStudioMefHostServices.Create(EditorServicesUtil.ExportProvider));
            var service = previewWorkspace.Services.GetService <ISolutionCrawlerRegistrationService>();

            Assert.True(service is PreviewSolutionCrawlerRegistrationServiceFactory.Service);

            var persistentService = previewWorkspace.Services.GetRequiredService <IPersistentStorageService>();

            using var storage = persistentService.GetStorage(previewWorkspace.CurrentSolution);
            Assert.True(storage is NoOpPersistentStorage);
        }
Ejemplo n.º 4
0
        public void TestPreviewAddRemoveProject()
        {
            using var previewWorkspace = new PreviewWorkspace();
            var solution = previewWorkspace.CurrentSolution;
            var project = solution.AddProject("project", "project.dll", LanguageNames.CSharp);
            Assert.True(previewWorkspace.TryApplyChanges(project.Solution));

            var newSolution = previewWorkspace.CurrentSolution.RemoveProject(project.Id);
            Assert.True(previewWorkspace.TryApplyChanges(newSolution));

            Assert.Equal(0, previewWorkspace.CurrentSolution.ProjectIds.Count);
        }
        public void UpdatePreview(string text)
        {
            var service   = VisualStudioMefHostServices.Create(_componentModel.GetService <ExportProvider>());
            var workspace = new PreviewWorkspace(service);
            var fileName  = "project." + (Language == "C#" ? "csproj" : "vbproj");
            var project   = workspace.CurrentSolution.AddProject(fileName, "assembly.dll", Language);

            // use the mscorlib, system, and system.core that are loaded in the current process.
            string[] references =
            {
                "mscorlib",
                "System",
                "System.Core"
            };

            var metadataService = workspace.Services.GetService <IMetadataService>();

            var referenceAssemblies = Thread.GetDomain().GetAssemblies()
                                      .Where(x => references.Contains(x.GetName(true).Name, StringComparer.OrdinalIgnoreCase))
                                      .Select(a => metadataService.GetReference(a.Location, MetadataReferenceProperties.Assembly));

            project = project.WithMetadataReferences(referenceAssemblies);

            var document = project.AddDocument("document", SourceText.From(text, Encoding.UTF8));
            var fallbackFormattingOptions = _globalOptions.GetSyntaxFormattingOptions(document.Project.LanguageServices);
            var formattingOptions         = SyntaxFormattingOptions.Create(OptionStore.GetOptions(), fallbackFormattingOptions, document.Project.LanguageServices);
            var formatted = Formatter.FormatAsync(document, formattingOptions, CancellationToken.None).WaitAndGetResult(CancellationToken.None);

            var textBuffer = _textBufferFactoryService.CreateTextBuffer(formatted.GetTextSynchronously(CancellationToken.None).ToString(), _contentType);

            var container = textBuffer.AsTextContainer();

            var projection = _projectionBufferFactory.CreateProjectionBufferWithoutIndentation(_contentTypeRegistryService,
                                                                                               _editorOptions.CreateOptions(),
                                                                                               textBuffer.CurrentSnapshot,
                                                                                               separator: "",
                                                                                               exposedLineSpans: GetExposedLineSpans(textBuffer.CurrentSnapshot).ToArray());

            var textView = _textEditorFactoryService.CreateTextView(projection,
                                                                    _textEditorFactoryService.CreateTextViewRoleSet(PredefinedTextViewRoles.Interactive));

            this.TextViewHost = _textEditorFactoryService.CreateTextViewHost(textView, setFocus: false);

            workspace.TryApplyChanges(document.Project.Solution);
            workspace.OpenDocument(document.Id, container);

            this.TextViewHost.Closed += (s, a) =>
            {
                workspace.Dispose();
                workspace = null;
            };
        }
Ejemplo n.º 6
0
        public async Task TestPreviewServices()
        {
            using var previewWorkspace = new PreviewWorkspace(EditorTestCompositions.EditorFeatures.GetHostServices());
            var service = previewWorkspace.Services.GetService <ISolutionCrawlerRegistrationService>();

            Assert.IsType <PreviewSolutionCrawlerRegistrationServiceFactory.Service>(service);

            var persistentService = previewWorkspace.Services.GetPersistentStorageService(previewWorkspace.CurrentSolution.Options);

            await using var storage = await persistentService.GetStorageAsync(SolutionKey.ToSolutionKey(previewWorkspace.CurrentSolution), CancellationToken.None);

            Assert.IsType <NoOpPersistentStorage>(storage);
        }
        //private static List<LineSpan> GetExposedLineSpans (ITextSnapshot textSnapshot)
        //{
        //	const string start = "//[";
        //	const string end = "//]";

        //	var bufferText = textSnapshot.GetText ().ToString ();

        //	var lineSpans = new List<LineSpan> ();
        //	var lastEndIndex = 0;

        //	while (true) {
        //		var startIndex = bufferText.IndexOf (start, lastEndIndex, StringComparison.Ordinal);
        //		if (startIndex == -1) {
        //			break;
        //		}

        //		var endIndex = bufferText.IndexOf (end, lastEndIndex, StringComparison.Ordinal);

        //		var startLine = textSnapshot.GetLineNumberFromPosition (startIndex) + 1;
        //		var endLine = textSnapshot.GetLineNumberFromPosition (endIndex);

        //		lineSpans.Add (LineSpan.FromBounds (startLine, endLine));
        //		lastEndIndex = endIndex + end.Length;
        //	}

        //	return lineSpans;
        //}

        public void Dispose()
        {
            if (_textViewHost != null)
            {
                _textViewHost.Dispose();
                _textViewHost = null;
            }
            if (curWorkspace != null)
            {
                curWorkspace.Dispose();
                curWorkspace = null;
            }
        }
Ejemplo n.º 8
0
        public IWpfDifferenceViewer CreateAddedAdditionalDocumentPreviewView(TextDocument document, double zoomLevel, CancellationToken cancellationToken)
        {
            var newBuffer = CreateNewPlainTextBuffer(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.Project.Solution.WithAdditionalDocumentText(document.Id, newBuffer.AsTextContainer().CurrentText));

            rightWorkspace.OpenAdditionalDocument(document.Id);

            return(CreateAddedDocumentPreviewViewCore(newBuffer, rightWorkspace, document, zoomLevel, cancellationToken));
        }
        public async void UpdatePreview(string text)
        {
            var workspace = new PreviewWorkspace(Ide.Composition.CompositionManager.Instance.HostServices);
            var fileName  = string.Format("project.{0}", Language == "C#" ? "csproj" : "vbproj");

            project = workspace.CurrentSolution.AddProject(fileName, "assembly.dll", Language);

            // use the mscorlib, system, and system.core that are loaded in the current process.
            string [] references =
            {
                "mscorlib",
                "System",
                "System.Core"
            };

            var metadataService = workspace.Services.GetService <IMetadataService> ();

            var referenceAssemblies = Thread.GetDomain().GetAssemblies()
                                      .Where(x => references.Contains(x.GetName(true).Name, StringComparer.OrdinalIgnoreCase))
                                      .Select(a => metadataService.GetReference(a.Location, MetadataReferenceProperties.Assembly));

            project = project.WithMetadataReferences(referenceAssemblies);

            var document  = project.AddDocument("document.cs", SourceText.From(text, Encoding.UTF8));
            var formatted = Formatter.FormatAsync(document, this.Options).WaitAndGetResult(CancellationToken.None);

            workspace.TryApplyChanges(project.Solution);

            TextViewHost.MimeType        = "text/x-csharp";
            TextViewHost.Text            = (await document.GetTextAsync()).ToString();
            TextViewHost.DocumentContext = new MyDocumentContext(workspace, document);

            TextViewHost.IsReadOnly = false;
            for (int i = 1; i <= TextViewHost.LineCount; i++)
            {
                var txt = TextViewHost.GetLineText(i);
                if (txt == "//[" || txt == "//]")
                {
                    var line = TextViewHost.GetLine(i);
                    TextViewHost.RemoveText(line.Offset, line.LengthIncludingDelimiter);
                    i--;
                }
            }
            TextViewHost.IsReadOnly = true;
            if (curWorkspace != null)
            {
                curWorkspace.Dispose();
            }

            this.curWorkspace = workspace;
        }
Ejemplo n.º 10
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));
        }
Ejemplo n.º 11
0
        public Task <object> CreateChangedAdditionalDocumentPreviewViewAsync(TextDocument oldDocument, TextDocument 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 = CreateNewPlainTextBuffer(oldDocument, cancellationToken);
            var newBuffer = CreateNewPlainTextBuffer(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.
            var originalSpans = GetOriginalSpans(diffResult, cancellationToken);
            var changedSpans  = GetChangedSpans(diffResult, cancellationToken);

            string description       = null;
            var    originalLineSpans = CreateLineSpans(oldBuffer.CurrentSnapshot, originalSpans, cancellationToken);
            var    changedLineSpans  = CreateLineSpans(newBuffer.CurrentSnapshot, changedSpans, cancellationToken);

            // TODO: Why aren't we attaching conflict / warning annotations here like we do for regular documents above?

            // 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 leftDocumentId = DocumentId.CreateNewId(oldDocument.Project.Id);
            var leftSolution   = oldDocument.Project.Solution
                                 .RemoveAdditionalDocument(oldDocument.Id)
                                 .AddAdditionalDocument(leftDocumentId, oldDocument.Name, oldBuffer.AsTextContainer().CurrentText);
            var leftWorkspace = new PreviewWorkspace(leftSolution);

            leftWorkspace.OpenAdditionalDocument(leftDocumentId);

            var rightWorkSpace = new PreviewWorkspace(
                oldDocument.Project.Solution.WithAdditionalDocumentText(oldDocument.Id, newBuffer.AsTextContainer().CurrentText));

            rightWorkSpace.OpenAdditionalDocument(newDocument.Id);

            return(CreateChangedDocumentViewAsync(
                       oldBuffer, newBuffer, description, originalLineSpans, changedLineSpans,
                       leftWorkspace, rightWorkSpace, zoomLevel, cancellationToken));
        }
Ejemplo n.º 12
0
        public void TestPreviewServices()
        {
            using (var previewWorkspace = new PreviewWorkspace(MefV1HostServices.Create(EditorServicesUtil.ExportProvider.AsExportProvider())))
            {
                var service = previewWorkspace.Services.GetService <ISolutionCrawlerRegistrationService>();
                Assert.True(service is PreviewSolutionCrawlerRegistrationServiceFactory.Service);

                var persistentService = previewWorkspace.Services.GetService <IPersistentStorageService>();
                Assert.NotNull(persistentService);

                var storage = persistentService.GetStorage(previewWorkspace.CurrentSolution);
                Assert.True(storage is NoOpPersistentStorage);
            }
        }
Ejemplo n.º 13
0
        public void TestPreviewServices()
        {
            using (var previewWorkspace = new PreviewWorkspace(MefV1HostServices.Create(TestExportProvider.ExportProviderWithCSharpAndVisualBasic.AsExportProvider())))
            {
                var workcoordinatorService = previewWorkspace.Services.GetService <IWorkCoordinatorRegistrationService>();
                Assert.True(workcoordinatorService is PreviewWorkCoordinatorRegistrationService);

                var persistentService = previewWorkspace.Services.GetService <IPersistentStorageService>();
                Assert.NotNull(persistentService);

                var storage = persistentService.GetStorage(previewWorkspace.CurrentSolution);
                Assert.True(storage is NoOpPersistentStorage);
            }
        }
Ejemplo n.º 14
0
        public async Task TestPreviewDiagnostic()
        {
            var hostServices = EditorTestCompositions.EditorFeatures.GetHostServices();

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

            RoslynDebug.AssertNotNull(diagnosticService);

            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(
                    previewWorkspace,
                    InternalDiagnosticsOptions.NormalDiagnosticMode
                    ).Length > 0
                );
        }
Ejemplo n.º 15
0
        public void TestPreviewDiagnosticTagger()
        {
            using (var workspace = CSharpWorkspaceFactory.CreateWorkspaceFromLines("class { }"))
                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();

                    //// enable preview diagnostics
                    previewWorkspace.EnableDiagnostic();

                    var spans = SquiggleUtilities.GetErrorSpans(workspace);
                    Assert.Equal(1, spans.Count);
                }
        }
Ejemplo n.º 16
0
        public void TestPreviewWorkspaceDoesNotLeakSolution()
        {
            // Verify that analyzer execution doesn't leak solution instances from the preview workspace.

            var previewWorkspace = new PreviewWorkspace();
            Assert.NotNull(previewWorkspace.CurrentSolution);
            var project = previewWorkspace.CurrentSolution.AddProject("project", "project.dll", LanguageNames.CSharp);
            Assert.True(previewWorkspace.TryApplyChanges(project.Solution));
            var solutionObjectReference = ObjectReference.Create(previewWorkspace.CurrentSolution);

            var analyzers = ImmutableArray.Create<DiagnosticAnalyzer>(new CommonDiagnosticAnalyzers.NotConfigurableDiagnosticAnalyzer());
            ExecuteAnalyzers(previewWorkspace, analyzers);

            previewWorkspace.Dispose();
            solutionObjectReference.AssertReleased();
        }
Ejemplo n.º 17
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));
        }
Ejemplo n.º 18
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);
                }
        }
Ejemplo n.º 19
0
        private Task <object> CreateAddedTextDocumentPreviewViewAsync(
            TextDocument document,
            double zoomLevel,
            Func <TextDocument, CancellationToken, ITextBuffer> createBuffer,
            Action <Workspace, DocumentId> openTextDocument,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var newBuffer = createBuffer(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.Project.Solution.WithTextDocumentText(document.Id, newBuffer.AsTextContainer().CurrentText));

            openTextDocument(rightWorkspace, document.Id);

            return(CreateAddedDocumentPreviewViewCoreAsync(newBuffer, rightWorkspace, document, zoomLevel, cancellationToken));
        }
Ejemplo n.º 20
0
        public async Task TestPreviewDiagnosticTagger()
        {
            using (var workspace = TestWorkspace.CreateCSharp("class { }", exportProvider: EditorServicesUtil.ExportProvider))
                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();

                    //// enable preview diagnostics
                    previewWorkspace.EnableDiagnostic();

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

                    const string AnalzyerCount = "Analyzer Count: ";
                    Assert.Equal(AnalzyerCount + 1, AnalzyerCount + diagnosticsAndErrorsSpans.Item1.Length);

                    const string SquigglesCount = "Squiggles Count: ";
                    Assert.Equal(SquigglesCount + 1, SquigglesCount + diagnosticsAndErrorsSpans.Item2.Length);
                }
        }
Ejemplo n.º 21
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);
        }
Ejemplo n.º 22
0
        public DisposableToolTip CreateDisposableToolTip(Document document, ITextBuffer textBuffer, Span contentSpan, object backgroundResourceKey)
        {
            var control = CreateViewHostingControl(textBuffer, contentSpan);

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

            // Create a preview workspace for this text buffer and open it's corresponding
            // document.
            //
            // our underlying preview tagger and mechanism to attach tagger to associated buffer of
            // opened document will light up automatically
            var workspace = new PreviewWorkspace(document.Project.Solution);

            workspace.OpenDocument(document.Id, textBuffer.AsTextContainer());

            return(new DisposableToolTip(toolTip, workspace));
        }
        public void UpdatePreview(string text)
        {
            const string start = "//[";
            const string end   = "//]";

            var service   = MefV1HostServices.Create(_componentModel.DefaultExportProvider);
            var workspace = new PreviewWorkspace(service);

            var document  = workspace.OpenDocument(DocumentId.CreateNewId("document"), SourceText.From(text), Language);
            var formatted = Formatter.FormatAsync(document, this.Options).WaitAndGetResult(CancellationToken.None);

            var textBuffer = _textBufferFactoryService.CreateTextBuffer(formatted.SourceText.ToString(), _contentType);

            var container = textBuffer.AsTextContainer();
            var documentBackedByTextBuffer = document.WithText(container.CurrentText);

            var bufferText = textBuffer.CurrentSnapshot.GetText().ToString();
            var startIndex = bufferText.IndexOf(start, StringComparison.Ordinal);
            var endIndex   = bufferText.IndexOf(end, StringComparison.Ordinal);
            var startLine  = textBuffer.CurrentSnapshot.GetLineNumberFromPosition(startIndex) + 1;
            var endLine    = textBuffer.CurrentSnapshot.GetLineNumberFromPosition(endIndex);

            var projection = _projectionBufferFactory.CreateProjectionBufferWithoutIndentation(_contentTypeRegistryService,
                                                                                               _editorOptions.CreateOptions(),
                                                                                               textBuffer.CurrentSnapshot,
                                                                                               "",
                                                                                               LineSpan.FromBounds(startLine, endLine));

            var textView = _textEditorFactoryService.CreateTextView(projection,
                                                                    _textEditorFactoryService.CreateTextViewRoleSet());

            this.TextViewHost = _textEditorFactoryService.CreateTextViewHost(textView, setFocus: false);

            workspace.CloseDocument(document.Id);
            workspace.OpenDocument(document.Id, documentBackedByTextBuffer.SourceText, Language);
            //workspace.UpdateDocument(documentBackedByTextBuffer.Id, documentBackedByTextBuffer.SourceText);
        }
Ejemplo n.º 24
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);
        }
Ejemplo n.º 25
0
        private Task <object> CreateChangedDocumentViewAsync(ITextBuffer oldBuffer, ITextBuffer newBuffer, string description,
                                                             List <LineSpan> originalSpans, List <LineSpan> changedSpans, PreviewWorkspace leftWorkspace, PreviewWorkspace rightWorkspace,
                                                             double zoomLevel, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            if (!(originalSpans.Any() && changedSpans.Any()))
            {
                // Both line spans must be non-empty. Otherwise, below projection buffer factory API call will throw.
                // So if either is empty (signalling that there are no changes to preview in the document), then we bail out.
                // This can happen in cases where the user has already applied the fix and light bulb has already been dismissed,
                // but platform hasn't cancelled the preview operation yet. Since the light bulb has already been dismissed at
                // this point, the preview that we return will never be displayed to the user. So returning null here is harmless.
                return(SpecializedTasks.Default <object>());
            }

            var originalBuffer = _projectionBufferFactoryService.CreateProjectionBufferWithoutIndentation(
                _contentTypeRegistryService,
                _editorOptionsFactoryService.GlobalOptions,
                oldBuffer.CurrentSnapshot,
                "...",
                description,
                originalSpans.ToArray());

            var changedBuffer = _projectionBufferFactoryService.CreateProjectionBufferWithoutIndentation(
                _contentTypeRegistryService,
                _editorOptionsFactoryService.GlobalOptions,
                newBuffer.CurrentSnapshot,
                "...",
                description,
                changedSpans.ToArray());

            return(CreateNewDifferenceViewerAsync(leftWorkspace, rightWorkspace, originalBuffer, changedBuffer, zoomLevel, cancellationToken));
        }
Ejemplo n.º 26
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 newRoot              = newDocument.GetSyntaxRootAsync(cancellationToken).WaitAndGetResult(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();

            AttachConflictAndWarningAnnotationToBuffer(newBuffer, conflictSpans, warningSpans);

            var description = conflictSpans.Count == 0 && warningSpans.Count == 0
                ? null
                : string.Join(Environment.NewLine, conflictDescriptions.Concat(warningDescriptions));

            var allSpans = new NormalizedSpanCollection(conflictSpans.Concat(warningSpans).Concat(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);
            var leftWorkspace = new PreviewWorkspace(leftDocument.Project.Solution);

            leftWorkspace.OpenDocument(leftDocument.Id);

            var rightWorkspace = new PreviewWorkspace(
                oldDocument.WithText(newBuffer.AsTextContainer().CurrentText).Project.Solution);

            rightWorkspace.OpenDocument(newDocument.Id);

            return(CreateChangedDocumentViewAsync(
                       oldBuffer, newBuffer, description, originalLineSpans, changedLineSpans,
                       leftWorkspace, rightWorkspace, zoomLevel, cancellationToken));
        }
Ejemplo n.º 27
0
        private Task <object> CreateRemovedDocumentPreviewViewCoreAsync(ITextBuffer oldBuffer, PreviewWorkspace workspace, TextDocument document, double zoomLevel, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var firstLine = string.Format(EditorFeaturesResources.RemovingFromWithContent,
                                          document.Name, document.Project.Name);

            var span = new SnapshotSpan(oldBuffer.CurrentSnapshot, Span.FromBounds(0, oldBuffer.CurrentSnapshot.Length))
                       .CreateTrackingSpan(SpanTrackingMode.EdgeExclusive);
            var originalBuffer = _projectionBufferFactoryService.CreatePreviewProjectionBuffer(
                sourceSpans: new List <object> {
                firstLine, "\r\n", span
            }, registryService: _contentTypeRegistryService);

            var changedBuffer = _projectionBufferFactoryService.CreatePreviewProjectionBuffer(
                sourceSpans: new List <object> {
                firstLine, "\r\n"
            }, registryService: _contentTypeRegistryService);

            return(CreateNewDifferenceViewerAsync(workspace, null, originalBuffer, changedBuffer, zoomLevel, cancellationToken));
        }
        private async ValueTask <DifferenceViewerPreview?> CreateChangedDocumentViewAsync(ITextBuffer oldBuffer, ITextBuffer newBuffer, string?description,
                                                                                          List <LineSpan> originalSpans, List <LineSpan> changedSpans, PreviewWorkspace leftWorkspace, PreviewWorkspace rightWorkspace,
                                                                                          double zoomLevel, CancellationToken cancellationToken)
        {
            if (!(originalSpans.Any() && changedSpans.Any()))
            {
                // Both line spans must be non-empty. Otherwise, below projection buffer factory API call will throw.
                // So if either is empty (signaling that there are no changes to preview in the document), then we bail out.
                // This can happen in cases where the user has already applied the fix and light bulb has already been dismissed,
                // but platform hasn't cancelled the preview operation yet. Since the light bulb has already been dismissed at
                // this point, the preview that we return will never be displayed to the user. So returning null here is harmless.

                // TODO: understand how this can even happen. The diff input is stable -- we shouldn't be depending on some sort of
                // state that could change underneath us. If we know the file changed, how would we discover here it didn't?
                return(null);
            }

            // IProjectionBufferFactoryService is a Visual Studio API which is not documented as free-threaded
            await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

            var originalBuffer = _projectionBufferFactoryService.CreateProjectionBufferWithoutIndentation(
                _contentTypeRegistryService,
                _editorOptionsFactoryService.GlobalOptions,
                oldBuffer.CurrentSnapshot,
                "...",
                description,
                originalSpans.ToArray());

            var changedBuffer = _projectionBufferFactoryService.CreateProjectionBufferWithoutIndentation(
                _contentTypeRegistryService,
                _editorOptionsFactoryService.GlobalOptions,
                newBuffer.CurrentSnapshot,
                "...",
                description,
                changedSpans.ToArray());

#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task (containing method uses JTF)
            return(await CreateNewDifferenceViewerAsync(leftWorkspace, rightWorkspace, originalBuffer, changedBuffer, zoomLevel, cancellationToken));

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
        }
        public async Task <DifferenceViewerPreview?> CreateChangedDocumentPreviewViewAsync(Document oldDocument, Document newDocument, double zoomLevel, CancellationToken cancellationToken)
        {
            // CreateNewBufferAsync must be called from the main thread
            await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

            // 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.
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task (containing method uses JTF)
            var oldBuffer = await CreateNewBufferAsync(oldDocument, cancellationToken);

            var newBuffer = await CreateNewBufferAsync(newDocument, cancellationToken);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

            // 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);
            string?description   = null;
            NormalizedSpanCollection allSpans;

            if (newDocument.SupportsSyntaxTree)
            {
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task (containing method uses JTF)
                var newRoot = await newDocument.GetRequiredSyntaxRootAsync(cancellationToken);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
                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 leftWorkspace = new PreviewWorkspace(oldDocument.Project.Solution);
            leftWorkspace.OpenDocument(oldDocument.Id, oldBuffer.AsTextContainer());

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

#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task (containing method uses JTF)
            return(await CreateChangedDocumentViewAsync(
                       oldBuffer, newBuffer, description, originalLineSpans, changedLineSpans,
                       leftWorkspace, rightWorkspace, zoomLevel, cancellationToken));

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
        }
        private async ValueTask <DifferenceViewerPreview> CreateRemovedDocumentPreviewViewCoreAsync(ITextBuffer oldBuffer, PreviewWorkspace workspace, TextDocument document, double zoomLevel, CancellationToken cancellationToken)
        {
            // IProjectionBufferFactoryService is a Visual Studio API which is not documented as free-threaded
            await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

            var firstLine = string.Format(EditorFeaturesResources.Removing_0_from_1_with_content_colon,
                                          document.Name, document.Project.Name);

            var span = new SnapshotSpan(oldBuffer.CurrentSnapshot, Span.FromBounds(0, oldBuffer.CurrentSnapshot.Length))
                       .CreateTrackingSpan(SpanTrackingMode.EdgeExclusive);
            var originalBuffer = _projectionBufferFactoryService.CreatePreviewProjectionBuffer(
                sourceSpans: new List <object> {
                firstLine, "\r\n", span
            }, registryService: _contentTypeRegistryService);

            var changedBuffer = _projectionBufferFactoryService.CreatePreviewProjectionBuffer(
                sourceSpans: new List <object> {
                firstLine, "\r\n"
            }, registryService: _contentTypeRegistryService);

#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task (containing method uses JTF)
            return(await CreateNewDifferenceViewerAsync(workspace, null, originalBuffer, changedBuffer, zoomLevel, cancellationToken));

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
        }