public void ProjectManager_Changed_ProjectRemoved_TriggersContextChanged_WithEphemeralProject() { // Arrange ProjectManager.ProjectAdded(HostProject); var project = ProjectManager.GetLoadedProject(HostProject.FilePath); ProjectManager.ProjectRemoved(HostProject); var e = new ProjectChangeEventArgs(project, null, ProjectChangeKind.ProjectRemoved); var called = false; DocumentTracker.ContextChanged += (sender, args) => { // This can be called both with tag helper and project changes. called = true; Assert.IsType <EphemeralProjectSnapshot>(DocumentTracker.ProjectSnapshot); }; // Act DocumentTracker.ProjectManager_Changed(ProjectManager, e); // Assert Assert.True(called); }
protected override void NotifyListeners(ProjectChangeEventArgs e) { if (AllowNotifyListeners) { base.NotifyListeners(e); } }
internal void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) { if (!_lspEditorFeatureDetector.IsLSPEditorAvailable(args.ProjectFilePath, hierarchy: null)) { return; } switch (args.Kind) { case ProjectChangeKind.DocumentRemoved: case ProjectChangeKind.DocumentAdded: case ProjectChangeKind.DocumentChanged: case ProjectChangeKind.ProjectChanged: // These changes can come in bursts so we don't want to overload the publishing system. Therefore, // we enqueue publishes and then publish the latest project after a delay. EnqueuePublish(args.Newer); break; case ProjectChangeKind.ProjectAdded: Publish(args.Newer); break; case ProjectChangeKind.ProjectRemoved: RemovePublishingData(args.Older); break; } }
private void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) { switch (e.Kind) { case ProjectChangeKind.ProjectAdded: case ProjectChangeKind.ProjectChanged: case ProjectChangeKind.DocumentsChanged: { var project = _projectManager.GetLoadedProject(e.ProjectFilePath); foreach (var documentFilePath in project.DocumentFilePaths) { Enqueue(project, project.GetDocument(documentFilePath)); } break; } case ProjectChangeKind.DocumentContentChanged: { throw null; } case ProjectChangeKind.ProjectRemoved: // ignore break; default: throw new InvalidOperationException($"Unknown ProjectChangeKind {e.Kind}"); } }
internal void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) { // Don't do any work if the solution is closing if (args.SolutionIsClosing) { return; } _projectSnapshotManagerDispatcher.AssertDispatcherThread(); switch (args.Kind) { case ProjectChangeKind.DocumentChanged: case ProjectChangeKind.DocumentRemoved: lock (_store) { if (_store.ContainsKey(args.DocumentFilePath) && !_projectSnapshotManager.IsDocumentOpen(args.DocumentFilePath)) { // Document closed or removed, evict entry. _store.TryRemove(args.DocumentFilePath, out var _); } } break; } }
private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) { _foregroundDispatcher.AssertForegroundThread(); switch (args.Kind) { case ProjectChangeKind.DocumentChanged: if (_documentLookup.ContainsKey(args.DocumentFilePath) && !_projectSnapshotManager.IsDocumentOpen(args.DocumentFilePath)) { // Document closed, evict entry. _documentLookup.Remove(args.DocumentFilePath); } break; } // Any event that has a project may have changed the state of the documents // and therefore requires us to mark all existing documents as latest. if (args.ProjectFilePath == null) { return; } var project = _projectSnapshotManager.GetLoadedProject(args.ProjectFilePath); if (project == null) { // Project no longer loaded, wait for document removed event. return; } CaptureProjectDocumentsAsLatest(project); }
private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) { // Don't do any work if the solution is closing if (args.SolutionIsClosing) { return; } _projectSnapshotManagerDispatcher.AssertDispatcherThread(); switch (args.Kind) { case ProjectChangeKind.DocumentChanged: if (!_projectSnapshotManager.IsDocumentOpen(args.DocumentFilePath)) { // Document closed, evict published source text. if (_publishedCSharpData.ContainsKey(args.DocumentFilePath)) { var removed = _publishedCSharpData.Remove(args.DocumentFilePath); Debug.Assert(removed, "Published data should be protected by the project snapshot manager's thread and should never fail to remove."); } if (_publishedHtmlData.ContainsKey(args.DocumentFilePath)) { var removed = _publishedHtmlData.Remove(args.DocumentFilePath); Debug.Assert(removed, "Published data should be protected by the project snapshot manager's thread and should never fail to remove."); } } break; } }
private async Task ProjectSnapshotManager_ChangedAsync(ProjectChangeEventArgs args, CancellationToken cancellationToken) { try { // Don't do any work if the solution is closing if (args.SolutionIsClosing) { return; } _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var projectSnapshot = args.Newer; if (projectSnapshot?.ProjectWorkspaceState != null && !_hasNotified) { // Un-register this method, we only need to send this once. _projectManager !.Changed -= ProjectSnapshotManager_Changed; var response = await _clientNotifierService.SendRequestAsync(LanguageServerConstants.RazorServerReadyEndpoint); await response.ReturningVoid(cancellationToken); _hasNotified = true; } } catch (Exception ex) { _projectManager?.ReportError(ex); } }
private void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) { switch (e.Kind) { case ProjectChangeKind.DocumentAdded: { var key = new DocumentKey(e.ProjectFilePath, e.DocumentFilePath); var document = _documentManager.GetOrCreateDocument(key, _onChangedOnDisk, _onChangedOnDisk, _onOpened, _onClosed); if (document.IsOpenInEditor) { Document_Opened(document, EventArgs.Empty); } break; } case ProjectChangeKind.DocumentRemoved: { // This class 'owns' the document entry so it's safe for us to dispose it. if (_documentManager.TryGetDocument(new DocumentKey(e.ProjectFilePath, e.DocumentFilePath), out var document)) { document.Dispose(); } break; } } }
public async Task ProjectManager_Changed_ProjectRemoved_AfterEnqueuedPublishAsync() { // Arrange var attemptedToSerialize = false; var projectSnapshot = CreateProjectSnapshot("/path/to/project.csproj"); var expectedPublishFilePath = "/path/to/obj/bin/Debug/project.razor.json"; var publisher = new TestDefaultRazorProjectChangePublisher( JoinableTaskContext, RazorLogger, onSerializeToFile: (snapshot, publishFilePath) => attemptedToSerialize = true, onDeleteFile: (path) => { }) { EnqueueDelay = 10 }; publisher.SetPublishFilePath(projectSnapshot.FilePath, expectedPublishFilePath); publisher.EnqueuePublish(projectSnapshot); var args = ProjectChangeEventArgs.CreateTestInstance(projectSnapshot, newer: null, documentFilePath: null, ProjectChangeKind.ProjectRemoved); // Act publisher.ProjectSnapshotManager_Changed(null, args); // Assert await Task.Delay(publisher.EnqueueDelay * 3).ConfigureAwait(false); Assert.False(attemptedToSerialize); }
public async Task ProjectManager_Changed_ProjectRemoved_AfterEnqueuedPublishAsync() { // Arrange var attemptedToSerialize = false; var projectSnapshot = CreateProjectSnapshot("/path/to/project.csproj"); var expectedConfigurationFilePath = "/path/to/obj/bin/Debug/project.razor.json"; var publisher = new TestDefaultRazorProjectChangePublisher( ProjectConfigurationFilePathStore, RazorLogger, onSerializeToFile: (snapshot, configurationFilePath) => attemptedToSerialize = true) { EnqueueDelay = 10, _active = true, }; publisher.Initialize(ProjectSnapshotManager); ProjectConfigurationFilePathStore.Set(projectSnapshot.FilePath, expectedConfigurationFilePath); publisher.EnqueuePublish(projectSnapshot); var args = ProjectChangeEventArgs.CreateTestInstance(projectSnapshot, newer: null, documentFilePath: null, ProjectChangeKind.ProjectRemoved); // Act publisher.ProjectSnapshotManager_Changed(null, args); // Assert var kvp = Assert.Single(publisher._deferredPublishTasks); await kvp.Value.ConfigureAwait(false); Assert.False(attemptedToSerialize); }
public void ProjectManager_Changed_TagHelpersChanged_TriggersContextChanged() { // Arrange Project project = null; var workspace = TestWorkspace.Create(ws => { project = ws.AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), new VersionStamp(), "Test1", "TestAssembly", LanguageNames.CSharp, filePath: "C:/Some/Path/TestProject.csproj")); }); var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, WorkspaceEditorSettings, workspace, TextBuffer, ImportDocumentManager); var projectSnapshot = new DefaultProjectSnapshot(new HostProject(project.FilePath, RazorConfiguration.Default), project); var projectChangedArgs = new ProjectChangeEventArgs(projectSnapshot, ProjectChangeKind.TagHelpersChanged); var called = false; documentTracker.ContextChanged += (sender, args) => { Assert.Equal(ContextChangeKind.TagHelpersChanged, args.Kind); called = true; }; // Act documentTracker.ProjectManager_Changed(null, projectChangedArgs); // Assert Assert.True(called); }
private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) { _foregroundDispatcher.AssertForegroundThread(); if (_disposed) { return; } if (args.Kind == ProjectChangeKind.DocumentAdded || args.Kind == ProjectChangeKind.DocumentRemoved || args.Kind == ProjectChangeKind.DocumentChanged) { // Razor LiveShare doesn't currently support document based notifications over the wire. return; } _processingChangedEventTestTask = _joinableTaskFactory.RunAsync(async() => { var projects = await GetLatestProjectsAsync(); await _joinableTaskFactory.SwitchToMainThreadAsync(); var oldProjectProxy = ConvertToProxy(args.Older); var newProjectProxy = ConvertToProxy(args.Newer); var remoteProjectChangeArgs = new ProjectChangeEventProxyArgs(oldProjectProxy, newProjectProxy, (ProjectProxyChangeKind)args.Kind); OnChanged(remoteProjectChangeArgs); }); }
internal async Task ProjectManager_Changed_EnqueuesPublishAsync(ProjectChangeKind changeKind) { // Arrange var serializationSuccessful = false; var projectSnapshot = CreateProjectSnapshot("/path/to/project.csproj"); var expectedPublishFilePath = "/path/to/obj/bin/Debug/project.razor.json"; var publisher = new TestDefaultRazorProjectChangePublisher( JoinableTaskContext, RazorLogger, onSerializeToFile: (snapshot, publishFilePath) => { Assert.Same(projectSnapshot, snapshot); Assert.Equal(expectedPublishFilePath, publishFilePath); serializationSuccessful = true; }) { EnqueueDelay = 10 }; publisher.SetPublishFilePath(projectSnapshot.FilePath, expectedPublishFilePath); var args = ProjectChangeEventArgs.CreateTestInstance(projectSnapshot, projectSnapshot, documentFilePath: null, changeKind); // Act publisher.ProjectSnapshotManager_Changed(null, args); // Assert var kvp = Assert.Single(publisher._deferredPublishTasks); await kvp.Value.ConfigureAwait(false); Assert.True(serializationSuccessful); }
private void ProjectManager_Changed(object sender, ProjectChangeEventArgs args) { if (args.SolutionIsClosing) { _entries.Clear(); return; } switch (args.Kind) { case ProjectChangeKind.ProjectRemoved: { var removedProject = args.Older; foreach (var documentFilePath in removedProject.DocumentFilePaths) { var key = new Key(removedProject.FilePath, documentFilePath); _entries.TryRemove(key, out _); } break; } case ProjectChangeKind.DocumentRemoved: { var owningProject = args.Newer; var key = new Key(owningProject.FilePath, args.DocumentFilePath); _entries.TryRemove(key, out _); break; } } }
public async Task Changed_TriggersOnSnapshotManagerChanged() { // Arrange var projectSnapshotManager = new TestProjectSnapshotManager(ProjectSnapshot1); using var proxy = new DefaultProjectSnapshotManagerProxy( new TestCollaborationSession(true), Dispatcher, projectSnapshotManager, JoinableTaskFactory); var changedArgs = new ProjectChangeEventArgs(ProjectSnapshot1, ProjectSnapshot1, ProjectChangeKind.ProjectChanged); var called = false; proxy.Changed += (sender, args) => { called = true; Assert.Equal($"vsls:/path/to/project1.csproj", args.ProjectFilePath.ToString()); Assert.Equal(ProjectProxyChangeKind.ProjectChanged, args.Kind); Assert.Equal("vsls:/path/to/project1.csproj", args.Newer.FilePath.ToString()); }; // Act projectSnapshotManager.TriggerChanged(changedArgs); await proxy._processingChangedEventTestTask.JoinAsync(); // Assert Assert.True(called); }
public void ProjectManager_Changed_IgnoresUnknownProject() { // Arrange Project project = null; var workspace = TestWorkspace.Create(ws => { project = ws.AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), new VersionStamp(), "Test1", "TestAssembly", LanguageNames.CSharp, filePath: "C:/Some/Other/Path/TestProject.csproj")); }); var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, workspace, TextBuffer, ImportDocumentManager); var projectSnapshot = new DefaultProjectSnapshot(project); var projectChangedArgs = new ProjectChangeEventArgs(projectSnapshot, ProjectChangeKind.Changed); var called = false; documentTracker.ContextChanged += (sender, args) => { called = true; }; // Act documentTracker.ProjectManager_Changed(null, projectChangedArgs); // Assert Assert.False(called); }
internal OmniSharpProjectChangeEventArgs(ProjectChangeEventArgs args) : this( OmniSharpProjectSnapshot.Convert(args.Older), OmniSharpProjectSnapshot.Convert(args.Newer), (OmniSharpProjectChangeKind)args.Kind) { InternalProjectChangeEventArgs = args; }
internal async Task ProjectManager_Changed_EnqueuesPublishAsync(ProjectChangeKind changeKind) { // Arrange var serializationSuccessful = false; var projectSnapshot = CreateProjectSnapshot("/path/to/project.csproj", new ProjectWorkspaceState(ImmutableArray <TagHelperDescriptor> .Empty, CodeAnalysis.CSharp.LanguageVersion.Default)); var expectedConfigurationFilePath = "/path/to/obj/bin/Debug/project.razor.json"; var publisher = new TestDefaultRazorProjectChangePublisher( ProjectConfigurationFilePathStore, RazorLogger, onSerializeToFile: (snapshot, configurationFilePath) => { Assert.Same(projectSnapshot, snapshot); Assert.Equal(expectedConfigurationFilePath, configurationFilePath); serializationSuccessful = true; }) { EnqueueDelay = 10, _active = true, }; publisher.Initialize(ProjectSnapshotManager); ProjectConfigurationFilePathStore.Set(projectSnapshot.FilePath, expectedConfigurationFilePath); var args = ProjectChangeEventArgs.CreateTestInstance(projectSnapshot, projectSnapshot, documentFilePath: null, changeKind); // Act publisher.ProjectSnapshotManager_Changed(null, args); // Assert var kvp = Assert.Single(publisher._deferredPublishTasks); await kvp.Value.ConfigureAwait(false); Assert.True(serializationSuccessful); }
private void SnapshotManager_Changed(object sender, ProjectChangeEventArgs e) { // The real work happens here. var project = SnapshotManager.GetLoadedProject(e.ProjectFilePath); var document = project.GetDocument(e.DocumentFilePath); Tasks.Add(document.GetGeneratedOutputAsync()); }
private void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) { if (_projectPath != null && string.Equals(_projectPath, e.Project.UnderlyingProject.FilePath, StringComparison.OrdinalIgnoreCase)) { OnContextChanged(e.Project); } }
// Does not handle C# files private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) { // Don't send for a simple Document edit. The platform should re-request any range that // is edited and if a parameter or type change is made it should be reflected as a ProjectChanged. if (args.Kind != ProjectChangeKind.DocumentChanged) { _publisher.EnqueueWorkspaceSemanticTokensRefresh(); } }
// Internal for testing. #pragma warning disable VSTHRD100 // Avoid async void methods internal async void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) #pragma warning restore VSTHRD100 // Avoid async void methods { try { switch (e.Kind) { case ProjectChangeKind.DocumentAdded: { // Don't do any work if the solution is closing if (e.SolutionIsClosing) { return; } var key = new DocumentKey(e.ProjectFilePath, e.DocumentFilePath); // GetOrCreateDocument needs to be run on the UI thread await _joinableTaskContext.Factory.SwitchToMainThreadAsync(); var document = _documentManager.GetOrCreateDocument( key, _onChangedOnDisk, _onChangedInEditor, _onOpened, _onClosed); if (document.IsOpenInEditor) { _onOpened(document, EventArgs.Empty); } break; } case ProjectChangeKind.DocumentRemoved: { // Need to run this even if the solution is closing because document dispose cleans up file watchers etc. // TryGetDocument and Dispose need to be run on the UI thread await _joinableTaskContext.Factory.SwitchToMainThreadAsync(); var documentFound = _documentManager.TryGetDocument( new DocumentKey(e.ProjectFilePath, e.DocumentFilePath), out var document); // This class 'owns' the document entry so it's safe for us to dispose it. if (documentFound) { document.Dispose(); } break; } } } catch (Exception ex) { Debug.Fail("EditorDocumentManagerListener.ProjectManager_Changed threw exception:" + Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace); } }
private void ProjectManager_Changed(object sender, ProjectChangeEventArgs args) { if (args.SolutionIsClosing) { _activeSolutionCancellationTokenSource?.Cancel(); _activeSolutionCancellationTokenSource?.Dispose(); _activeSolutionCancellationTokenSource = null; } else if (_activeSolutionCancellationTokenSource is null) { _activeSolutionCancellationTokenSource = new CancellationTokenSource(); } }
internal void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) { // Don't do any work if the solution is closing if (e.SolutionIsClosing) { return; } _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_projectPath != null && string.Equals(_projectPath, e.ProjectFilePath, StringComparison.OrdinalIgnoreCase)) { // This will be the new snapshot unless the project was removed. _projectSnapshot = _projectManager.GetLoadedProject(e.ProjectFilePath); switch (e.Kind) { case ProjectChangeKind.DocumentAdded: case ProjectChangeKind.DocumentRemoved: case ProjectChangeKind.DocumentChanged: // Nothing to do. break; case ProjectChangeKind.ProjectAdded: case ProjectChangeKind.ProjectChanged: // Just an update _ = OnContextChangedAsync(ContextChangeKind.ProjectChanged); if (e.Older is null || !Enumerable.SequenceEqual(e.Older.TagHelpers, e.Newer.TagHelpers)) { _ = OnContextChangedAsync(ContextChangeKind.TagHelpersChanged); } break; case ProjectChangeKind.ProjectRemoved: // Fall back to ephemeral project _projectSnapshot = _projectManager.GetOrCreateProject(ProjectPath); _ = OnContextChangedAsync(ContextChangeKind.ProjectChanged); break; default: throw new InvalidOperationException($"Unknown ProjectChangeKind {e.Kind}"); } } }
// Internal for testing internal void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) { if (_projectPath != null && string.Equals(_projectPath, e.Project.FilePath, StringComparison.OrdinalIgnoreCase)) { if (e.Kind == ProjectChangeKind.TagHelpersChanged) { OnContextChanged(e.Project, ContextChangeKind.TagHelpersChanged); } else { OnContextChanged(e.Project, ContextChangeKind.ProjectChanged); } } }
internal async Task ProjectManager_ChangedTagHelpers_PublishesImmediately() { // Arrange var serializationSuccessful = false; var projectSnapshot = CreateProjectSnapshot(@"C:\path\to\project.csproj", new ProjectWorkspaceState(ImmutableArray <TagHelperDescriptor> .Empty, CodeAnalysis.CSharp.LanguageVersion.Default)); var changedProjectSnapshot = CreateProjectSnapshot(@"C:\path\to\project.csproj", new ProjectWorkspaceState(ImmutableArray <TagHelperDescriptor> .Empty, CodeAnalysis.CSharp.LanguageVersion.CSharp8)); var expectedConfigurationFilePath = @"C:\path\to\obj\bin\Debug\project.razor.json"; var aboutToChange = false; var publisher = new TestProjectRazorJsonPublisher( ProjectConfigurationFilePathStore, onSerializeToFile: (snapshot, configurationFilePath) => { if (!aboutToChange) { return; } Assert.Same(changedProjectSnapshot, snapshot); Assert.Equal(expectedConfigurationFilePath, configurationFilePath); serializationSuccessful = true; }) { EnqueueDelay = 10, _active = true, }; publisher.Initialize(ProjectSnapshotManager); ProjectConfigurationFilePathStore.Set(projectSnapshot.FilePath, expectedConfigurationFilePath); var args = ProjectChangeEventArgs.CreateTestInstance(projectSnapshot, projectSnapshot, documentFilePath: null, ProjectChangeKind.ProjectChanged); publisher.ProjectSnapshotManager_Changed(null, args); // Flush publish task var kvp = Assert.Single(publisher.DeferredPublishTasks); await kvp.Value.ConfigureAwait(false); aboutToChange = true; publisher.DeferredPublishTasks.Clear(); var changedTagHelpersArgs = ProjectChangeEventArgs.CreateTestInstance(projectSnapshot, changedProjectSnapshot, documentFilePath: null, ProjectChangeKind.ProjectChanged); // Act publisher.ProjectSnapshotManager_Changed(null, changedTagHelpersArgs); // Assert Assert.Empty(publisher.DeferredPublishTasks); Assert.True(serializationSuccessful); }
public void ProjectSnapshotManager_Changed_DocumentChanged_ClosedDoc_EvictsCache() { // Arrange var documentFilePath = "/C:/path/to/file.cshtml"; var projectFilePath = "/C:/path/to/project.csproj"; var container = Store.Get(documentFilePath); var oldProject = TestProjectSnapshot.Create(projectFilePath, new[] { documentFilePath }); var newProjet = TestProjectSnapshot.Create(projectFilePath, new[] { documentFilePath }); var args = new ProjectChangeEventArgs(oldProject, newProjet, documentFilePath, ProjectChangeKind.DocumentChanged); // Act Store.ProjectSnapshotManager_Changed(null, args); var newContainer = Store.Get(documentFilePath); // Assert Assert.NotSame(container, newContainer); }
public void ProjectManager_Changed_IgnoresUnknownProject() { // Arrange ProjectManager.ProjectAdded(OtherHostProject); var e = new ProjectChangeEventArgs(null, ProjectManager.GetLoadedProject(OtherHostProject.FilePath), ProjectChangeKind.ProjectChanged); var called = false; DocumentTracker.ContextChanged += (sender, args) => called = true; // Act DocumentTracker.ProjectManager_Changed(ProjectManager, e); // Assert Assert.False(called); }
#pragma warning disable VSTHRD100 // Avoid async void methods private async void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) #pragma warning restore VSTHRD100 // Avoid async void methods { _foregroundDispatcher.AssertForegroundThread(); var projectSnapshot = args.Newer; if (projectSnapshot?.ProjectWorkspaceState != null && !_hasNotified) { // Un-register this method, we only need to send this once. _projectManager.Changed -= ProjectSnapshotManager_Changed; var response = _languageServer.SendRequest(LanguageServerConstants.RazorServerReadyEndpoint); await response.ReturningVoid(CancellationToken.None); _hasNotified = true; } }