private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) { switch (args.Kind) { case WorkspaceChangeKind.SolutionCleared: case WorkspaceChangeKind.SolutionRemoved: case WorkspaceChangeKind.SolutionAdded: this.CancelAllParses(); break; case WorkspaceChangeKind.DocumentRemoved: this.CancelParse(args.DocumentId); break; case WorkspaceChangeKind.DocumentChanged: this.ParseIfOpen(args.NewSolution.GetDocument(args.DocumentId)); break; case WorkspaceChangeKind.ProjectChanged: foreach (var doc in args.NewSolution.GetProject(args.ProjectId).Documents) { this.ParseIfOpen(doc); } break; } }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { if (e.Kind == WorkspaceChangeKind.ProjectChanged) { var oldProject = e.OldSolution.GetProject(e.ProjectId); var newProject = e.NewSolution.GetProject(e.ProjectId); if (!object.Equals(oldProject.ParseOptions, newProject.ParseOptions)) { var workspace = e.NewSolution.Workspace; var documentIds = workspace.GetRelatedDocumentIds(SubjectBuffer.AsTextContainer()); if (documentIds.Any(d => d.ProjectId == e.ProjectId)) { this.RaiseChanged(); } } } }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) { switch (args.Kind) { case WorkspaceChangeKind.SolutionCleared: case WorkspaceChangeKind.SolutionAdded: case WorkspaceChangeKind.SolutionRemoved: this.CancelBuild(releasePreviousCompilations: true); break; case WorkspaceChangeKind.SolutionChanged: case WorkspaceChangeKind.ProjectRemoved: this.Rebuild(args.NewSolution); break; default: this.Rebuild(args.NewSolution, args.ProjectId); break; } }
private void OnWorkspaceChangedLookForAnalyzer(object sender, WorkspaceChangeEventArgs e) { if (e.Kind == WorkspaceChangeKind.SolutionCleared || e.Kind == WorkspaceChangeKind.SolutionReloaded || e.Kind == WorkspaceChangeKind.SolutionRemoved) { _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; } else if (e.Kind == WorkspaceChangeKind.SolutionAdded) { _analyzerReference = TryGetAnalyzerReference(e.NewSolution); if (_analyzerReference != null) { _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasItems))); } } else if (e.ProjectId == _projectId) { if (e.Kind == WorkspaceChangeKind.ProjectRemoved) { _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; } else if (e.Kind == WorkspaceChangeKind.ProjectAdded || e.Kind == WorkspaceChangeKind.ProjectChanged) { _analyzerReference = TryGetAnalyzerReference(e.NewSolution); if (_analyzerReference != null) { _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasItems))); } } } }
private void ProcessEvents(WorkspaceChangeEventArgs args, IAsyncToken asyncToken) { SolutionCrawlerLogger.LogWorkspaceEvent(_logAggregator, (int)args.Kind); // TODO: add telemetry that record how much it takes to process an event (max, min, average and etc) switch (args.Kind) { case WorkspaceChangeKind.SolutionAdded: case WorkspaceChangeKind.SolutionChanged: case WorkspaceChangeKind.SolutionReloaded: case WorkspaceChangeKind.SolutionRemoved: case WorkspaceChangeKind.SolutionCleared: ProcessSolutionEvent(args, asyncToken); break; case WorkspaceChangeKind.ProjectAdded: case WorkspaceChangeKind.ProjectChanged: case WorkspaceChangeKind.ProjectReloaded: case WorkspaceChangeKind.ProjectRemoved: ProcessProjectEvent(args, asyncToken); break; case WorkspaceChangeKind.DocumentAdded: case WorkspaceChangeKind.DocumentReloaded: case WorkspaceChangeKind.DocumentChanged: case WorkspaceChangeKind.DocumentRemoved: case WorkspaceChangeKind.AdditionalDocumentAdded: case WorkspaceChangeKind.AdditionalDocumentRemoved: case WorkspaceChangeKind.AdditionalDocumentChanged: case WorkspaceChangeKind.AdditionalDocumentReloaded: ProcessDocumentEvent(args, asyncToken); break; default: throw ExceptionUtilities.Unreachable; } }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { switch (e.Kind) { case WorkspaceChangeKind.SolutionAdded: case WorkspaceChangeKind.SolutionChanged: case WorkspaceChangeKind.SolutionRemoved: case WorkspaceChangeKind.SolutionCleared: case WorkspaceChangeKind.SolutionReloaded: ClearVersionMap(e.NewSolution.Workspace, e.NewSolution.ProjectIds); break; case WorkspaceChangeKind.ProjectAdded: case WorkspaceChangeKind.ProjectRemoved: case WorkspaceChangeKind.ProjectChanged: case WorkspaceChangeKind.ProjectReloaded: ClearVersionMap(e.NewSolution.Workspace, e.ProjectId); break; case WorkspaceChangeKind.DocumentRemoved: ClearVersionMap(e.NewSolution.Workspace, e.DocumentId); break; case WorkspaceChangeKind.DocumentAdded: case WorkspaceChangeKind.DocumentReloaded: case WorkspaceChangeKind.DocumentChanged: case WorkspaceChangeKind.AdditionalDocumentAdded: case WorkspaceChangeKind.AdditionalDocumentRemoved: case WorkspaceChangeKind.AdditionalDocumentChanged: case WorkspaceChangeKind.AdditionalDocumentReloaded: break; default: Contract.Fail("Unknown event"); break; } }
public async void OnWorkspaceChangedAsync(object sender, WorkspaceChangeEventArgs args) { Document oldDocument = (from d in _project.Documents where StringComparers.Paths.Equals(d.FilePath, _oldFilePath) select d).FirstOrDefault(); if (oldDocument == null) { return; } if (args.Kind == WorkspaceChangeKind.DocumentAdded && args.ProjectId == _project.Id) { Project project = (from p in args.NewSolution.Projects where p.Id.Equals(_project.Id) select p).FirstOrDefault(); Document addedDocument = (from d in project?.Documents where d.Id.Equals(args.DocumentId) select d).FirstOrDefault(); if (addedDocument != null && StringComparers.Paths.Equals(addedDocument.FilePath, _newFilePath)) { _docAdded = true; } } if (args.Kind == WorkspaceChangeKind.DocumentRemoved && args.ProjectId == _project.Id && args.DocumentId == oldDocument.Id) { _docRemoved = true; } if (args.Kind == WorkspaceChangeKind.DocumentChanged && args.ProjectId == _project.Id) { _docChanged = true; } if (_docAdded && _docRemoved && _docChanged) { _workspace.WorkspaceChanged -= OnWorkspaceChangedAsync; Project myNewProject = _workspace.CurrentSolution.Projects.Where(p => StringComparers.Paths.Equals(p.FilePath, _project.FilePath)).FirstOrDefault(); await RenameAsync(myNewProject); } }
private void ProcessDocumentEvent(WorkspaceChangeEventArgs e, string eventName) { switch (e.Kind) { case WorkspaceChangeKind.DocumentAdded: Contract.ThrowIfNull(e.DocumentId); EnqueueEvent(e.NewSolution, e.DocumentId, InvocationReasons.DocumentAdded, eventName); break; case WorkspaceChangeKind.DocumentRemoved: Contract.ThrowIfNull(e.DocumentId); EnqueueEvent(e.OldSolution, e.DocumentId, InvocationReasons.DocumentRemoved, eventName); break; case WorkspaceChangeKind.DocumentReloaded: case WorkspaceChangeKind.DocumentChanged: Contract.ThrowIfNull(e.DocumentId); EnqueueEvent(e.OldSolution, e.NewSolution, e.DocumentId, eventName); break; case WorkspaceChangeKind.AdditionalDocumentAdded: case WorkspaceChangeKind.AdditionalDocumentRemoved: case WorkspaceChangeKind.AdditionalDocumentChanged: case WorkspaceChangeKind.AdditionalDocumentReloaded: case WorkspaceChangeKind.AnalyzerConfigDocumentAdded: case WorkspaceChangeKind.AnalyzerConfigDocumentRemoved: case WorkspaceChangeKind.AnalyzerConfigDocumentChanged: case WorkspaceChangeKind.AnalyzerConfigDocumentReloaded: // If an additional file or .editorconfig has changed we need to reanalyze the entire project. Contract.ThrowIfNull(e.ProjectId); EnqueueEvent(e.NewSolution, e.ProjectId, InvocationReasons.AdditionalDocumentChanged, eventName); break; default: throw ExceptionUtilities.UnexpectedValue(e.Kind); } }
public virtual void Update( Optional <Drawing> drawing = default(Optional <Drawing>), Optional <Plane> drawingPlane = default(Optional <Plane>), Optional <ViewPort> activeViewPort = default(Optional <ViewPort>), Optional <IViewControl> viewControl = default(Optional <IViewControl>), bool isDirty = true) { var e = new WorkspaceChangeEventArgs( drawing.HasValue, drawingPlane.HasValue, activeViewPort.HasValue, viewControl.HasValue, this.IsDirty != isDirty); OnWorkspaceChanging(e); if (drawing.HasValue) { this.Drawing = drawing.Value; } if (drawingPlane.HasValue) { this.DrawingPlane = drawingPlane.Value; } if (activeViewPort.HasValue) { this.ActiveViewPort = activeViewPort.Value; } if (viewControl.HasValue) { this.ViewControl = viewControl.Value; } this.IsDirty = isDirty; OnWorkspaceChanged(e); var selectedEntityIds = SelectedEntities.Select(ent => ent.Id).ToList(); }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) { // We're getting an event for a workspace we already disconnected from if (args.NewSolution.Workspace != _workspace) { return; } // If the displayed project is being renamed, retrigger the update if (args.Kind == WorkspaceChangeKind.ProjectChanged && args.ProjectId != null) { var oldProject = args.OldSolution.GetProject(args.ProjectId); var newProject = args.NewSolution.GetProject(args.ProjectId); if (oldProject.Name != newProject.Name) { var currentContextDocumentId = _workspace.GetDocumentIdInCurrentContext(_subjectBuffer.AsTextContainer()); if (currentContextDocumentId != null && currentContextDocumentId.ProjectId == args.ProjectId) { StartModelUpdateAndSelectedItemUpdateTasks(modelUpdateDelay: 0, selectedItemUpdateDelay: 0, updateUIWhenDone: true); } } } if (args.Kind == WorkspaceChangeKind.DocumentChanged && args.OldSolution == args.NewSolution) { var currentContextDocumentId = _workspace.GetDocumentIdInCurrentContext(_subjectBuffer.AsTextContainer()); if (currentContextDocumentId != null && currentContextDocumentId == args.DocumentId) { // The context has changed, so update everything. StartModelUpdateAndSelectedItemUpdateTasks(modelUpdateDelay: 0, selectedItemUpdateDelay: 0, updateUIWhenDone: true); } } }
private void ProcessProjectEvent(WorkspaceChangeEventArgs e, string eventName) { switch (e.Kind) { case WorkspaceChangeKind.ProjectAdded: Contract.ThrowIfNull(e.ProjectId); EnqueueEvent(e.NewSolution, e.ProjectId, InvocationReasons.DocumentAdded, eventName); break; case WorkspaceChangeKind.ProjectRemoved: Contract.ThrowIfNull(e.ProjectId); EnqueueEvent(e.OldSolution, e.ProjectId, InvocationReasons.DocumentRemoved, eventName); break; case WorkspaceChangeKind.ProjectChanged: case WorkspaceChangeKind.ProjectReloaded: Contract.ThrowIfNull(e.ProjectId); EnqueueEvent(e.OldSolution, e.NewSolution, e.ProjectId, eventName); break; default: throw ExceptionUtilities.UnexpectedValue(e.Kind); } }
public async Task WorkspaceChanged_DocumentChanged_Razor_UpdatesProjectState_AfterDelay() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator) { EnqueueDelay = 1, BlockDelayedUpdateWorkEnqueue = new ManualResetEventSlim(initialState: false), }; Workspace.TryApplyChanges(SolutionWithTwoProjects); var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); projectManager.ProjectAdded(HostProjectOne); workspaceStateGenerator.ClearQueue(); var solution = SolutionWithTwoProjects.WithDocumentText(RazorDocumentId, SourceText.From("Hello World")); var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: SolutionWithTwoProjects, newSolution: solution, projectId: ProjectNumberOne.Id, RazorDocumentId); // Act detector.Workspace_WorkspaceChanged(Workspace, e); // Assert // // The change hasn't come through yet. Assert.Empty(workspaceStateGenerator.UpdateQueue); detector.BlockDelayedUpdateWorkEnqueue.Set(); await detector._deferredUpdates.Single().Value; var update = Assert.Single(workspaceStateGenerator.UpdateQueue); Assert.Equal(update.workspaceProject.Id, ProjectNumberOne.Id); Assert.Equal(update.projectSnapshot.FilePath, HostProjectOne.FilePath); }
public async Task WorkspaceChanged_ProjectAddedEvent_AddsProject() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue) { NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false), }; var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectThree), CancellationToken.None).ConfigureAwait(false); var solution = SolutionWithOneProject; var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.ProjectAdded, oldSolution: EmptySolution, newSolution: solution, projectId: ProjectNumberThree.Id); // Act detector.Workspace_WorkspaceChanged(Workspace, e); detector.NotifyWorkspaceChangedEventComplete.Wait(); WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait(); // Assert Assert.Collection( workspaceStateGenerator.UpdateQueue, p => Assert.Equal(ProjectNumberThree.Id, p.WorkspaceProject.Id)); }
private void OnWorkspaceChanged(object?sender, WorkspaceChangeEventArgs e) { if (e.Kind == WorkspaceChangeKind.ProjectChanged) { RoslynDebug.AssertNotNull(e.ProjectId); var oldProject = e.OldSolution.GetRequiredProject(e.ProjectId); var newProject = e.NewSolution.GetRequiredProject(e.ProjectId); if (!object.Equals(oldProject.ParseOptions, newProject.ParseOptions)) { var workspace = e.NewSolution.Workspace; var documentId = workspace.GetDocumentIdInCurrentContext(SubjectBuffer.AsTextContainer()); if (documentId != null) { var relatedDocumentIds = e.NewSolution.GetRelatedDocumentIds(documentId); if (relatedDocumentIds.Any(d => d.ProjectId == e.ProjectId)) { RaiseChanged(); } } } } }
// We override Workspace_WorkspaceChanged in order to enforce calls to this to be on the foreground thread. // OmniSharp currently has an issue where they update the Solution on multiple different threads resulting // in change events dispatching through the Workspace on multiple different threads. This normalizes // that abnormality. #pragma warning disable VSTHRD100 // Avoid async void methods internal override async void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs args) #pragma warning restore VSTHRD100 // Avoid async void methods { if (_foregroundDispatcher.IsForegroundThread) { base.Workspace_WorkspaceChanged(sender, args); return; } await Task.Factory.StartNew( () => { try { base.Workspace_WorkspaceChanged(sender, args); } catch (Exception ex) { Debug.Fail("Unexpected error when handling a workspace changed event: " + ex); } }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); }
public async System.Threading.Tasks.Task WorkspaceChangedAsync(object sender, WorkspaceChangeEventArgs e) { var profiler = MiniProfiler.StartNew(nameof(WorkspaceChangedAsync)); profiler.Storage = new NLogStorage(LogManager.GetLogger("profiler")); var workspace = sender as VisualStudioWorkspace; switch (e.Kind) { case WorkspaceChangeKind.SolutionAdded: try { using (profiler.Step(WorkspaceChangeKind.SolutionAdded.ToString())) { await _indexingQueue.EnqueueMultipleAsync(workspace.CurrentSolution.Projects); } } catch (Exception ex) { LogManager.GetLogger("error").Error(ex, "WorkspaceChangeKind.SolutionAdded"); await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); OutputWindowLogger.WriteLn($"Exception occured during adding solution: {ex.Message}"); } break; case WorkspaceChangeKind.SolutionChanged: break; case WorkspaceChangeKind.SolutionRemoved: break; case WorkspaceChangeKind.SolutionCleared: break; case WorkspaceChangeKind.SolutionReloaded: break; case WorkspaceChangeKind.ProjectAdded: try { using (profiler.Step(WorkspaceChangeKind.SolutionAdded.ToString())) { await _indexingQueue.EnqueueMultipleAsync(workspace.CurrentSolution.Projects); } } catch (Exception ex) { LogManager.GetLogger("error").Error(ex, "WorkspaceChangeKind.ProjectAdded"); OutputWindowLogger.WriteLn($"Exception occured during adding projects: {ex.Message}"); } break; case WorkspaceChangeKind.ProjectRemoved: break; case WorkspaceChangeKind.ProjectChanged: break; case WorkspaceChangeKind.ProjectReloaded: break; case WorkspaceChangeKind.DocumentAdded: var documentAddedChanges = e.NewSolution.GetChanges(e.OldSolution); var addedDocuments = documentAddedChanges.GetProjectChanges() .SelectMany(x => x.GetAddedDocuments()) .Select(x => workspace.CurrentSolution.GetDocument(x)); await DocumentsAddedActionAsync(addedDocuments); break; case WorkspaceChangeKind.DocumentRemoved: var documentRemovedChanges = e.NewSolution.GetChanges(e.OldSolution); var removedDocuments = documentRemovedChanges.GetProjectChanges() .SelectMany(x => x.GetRemovedDocuments()); await DocumentRemovedActionAsync(removedDocuments); break; case WorkspaceChangeKind.DocumentReloaded: break; case WorkspaceChangeKind.DocumentChanged: break; case WorkspaceChangeKind.AdditionalDocumentAdded: break; case WorkspaceChangeKind.AdditionalDocumentRemoved: break; case WorkspaceChangeKind.AdditionalDocumentReloaded: break; case WorkspaceChangeKind.AdditionalDocumentChanged: break; default: break; } await profiler.StopAsync(); }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) { if (args.Kind != WorkspaceChangeKind.DocumentChanged) { if (!_dismissed) { this.Cancel(); } } }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs eventArgs) => _workQueue.AddWork(true);
private void OnWorkspaceChanged(object?sender, WorkspaceChangeEventArgs eventArgs) => _asyncDelay.RequeueWork();
// Internal for testing, virtual for temporary VSCode workaround internal virtual void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { Project project; switch (e.Kind) { case WorkspaceChangeKind.ProjectAdded: { project = e.NewSolution.GetProject(e.ProjectId); Debug.Assert(project != null); if (TryGetProjectSnapshot(project.FilePath, out var projectSnapshot)) { _workspaceStateGenerator.Update(project, projectSnapshot, CancellationToken.None); } break; } case WorkspaceChangeKind.ProjectChanged: case WorkspaceChangeKind.ProjectReloaded: { project = e.NewSolution.GetProject(e.ProjectId); if (TryGetProjectSnapshot(project?.FilePath, out var _)) { EnqueueUpdate(e.ProjectId); } break; } case WorkspaceChangeKind.ProjectRemoved: { project = e.OldSolution.GetProject(e.ProjectId); Debug.Assert(project != null); if (TryGetProjectSnapshot(project?.FilePath, out var projectSnapshot)) { _workspaceStateGenerator.Update(workspaceProject: null, projectSnapshot, CancellationToken.None); } break; } case WorkspaceChangeKind.DocumentChanged: case WorkspaceChangeKind.DocumentReloaded: { // This is the case when a component declaration file changes on disk. We have an MSBuild // generator configured by the SDK that will poke these files on disk when a component // is saved, or loses focus in the editor. project = e.OldSolution.GetProject(e.ProjectId); var document = project.GetDocument(e.DocumentId); if (document.FilePath == null) { return; } // Using EndsWith because Path.GetExtension will ignore everything before .cs // Using Ordinal because the SDK generates these filenames. // Stll have .cshtml.g.cs and .razor.g.cs for Razor.VSCode scenarios. if (document.FilePath.EndsWith(".cshtml.g.cs", StringComparison.Ordinal) || document.FilePath.EndsWith(".razor.g.cs", StringComparison.Ordinal) || document.FilePath.EndsWith(".razor", StringComparison.Ordinal) || // VSCode's background C# document document.FilePath.EndsWith("__bg__virtual.cs", StringComparison.Ordinal)) { EnqueueUpdate(e.ProjectId); return; } // We now know we're not operating directly on a Razor file. However, it's possible the user is operating on a partial class that is associated with a Razor file. if (IsPartialComponentClass(document)) { EnqueueUpdate(e.ProjectId); } break; } case WorkspaceChangeKind.SolutionAdded: case WorkspaceChangeKind.SolutionChanged: case WorkspaceChangeKind.SolutionCleared: case WorkspaceChangeKind.SolutionReloaded: case WorkspaceChangeKind.SolutionRemoved: if (e.OldSolution != null) { foreach (var p in e.OldSolution.Projects) { if (TryGetProjectSnapshot(p?.FilePath, out var projectSnapshot)) { _workspaceStateGenerator.Update(workspaceProject: null, projectSnapshot, CancellationToken.None); } } } InitializeSolution(e.NewSolution); break; } }
private void WorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { OnPropertyChangedDirect(string.Empty); }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { switch (e.Kind) { case WorkspaceChangeKind.SolutionAdded: _infoBarShownForCurrentSolution = false; return; // Check if a new analyzer config document was added case WorkspaceChangeKind.AnalyzerConfigDocumentAdded: break; default: return; } // Bail out if we have a null DTE instance or we have already shown the info bar for current solution. if (_dte == null || _infoBarShownForCurrentSolution) { return; } // Check if added analyzer config document is at the root of the current solution. var analyzerConfigDocumentFilePath = e.NewSolution.GetAnalyzerConfigDocument(e.DocumentId)?.FilePath; var analyzerConfigDirectory = PathUtilities.GetDirectoryName(analyzerConfigDocumentFilePath); var solutionDirectory = PathUtilities.GetDirectoryName(e.NewSolution.FilePath); if (analyzerConfigDocumentFilePath == null || analyzerConfigDirectory == null || analyzerConfigDirectory != solutionDirectory) { return; } // Check if user has explicitly disabled the suggestion to add newly added analyzer config document as solution item. if (_workspace.Options.GetOption(NeverShowAgain)) { return; } // Kick off a task to show info bar to make it a solution item. Task.Run(async() => { await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); var solution = (Solution2)_dte.Solution; if (VisualStudioAddSolutionItemService.TryGetExistingSolutionItemsFolder(solution, analyzerConfigDocumentFilePath, out _, out var hasExistingSolutionItem) && hasExistingSolutionItem) { return; } if (!_infoBarShownForCurrentSolution) { _infoBarShownForCurrentSolution = true; var infoBarService = _workspace.Services.GetRequiredService <IInfoBarService>(); infoBarService.ShowInfoBarInGlobalView( ServicesVSResources.A_new_editorconfig_file_was_detected_at_the_root_of_your_solution_Would_you_like_to_make_it_a_solution_item, GetInfoBarUIItems().ToArray()); } }); return; // Local functions IEnumerable <InfoBarUI> GetInfoBarUIItems() { // Yes - add editorconfig solution item. yield return(new InfoBarUI( title: ServicesVSResources.Yes, kind: InfoBarUI.UIKind.Button, action: AddEditorconfigSolutionItem, closeAfterAction: true)); // No - do not add editorconfig solution item. yield return(new InfoBarUI( title: ServicesVSResources.No, kind: InfoBarUI.UIKind.Button, action: () => { }, closeAfterAction: true)); // Don't show the InfoBar again link yield return(new InfoBarUI(title: ServicesVSResources.Never_show_this_again, kind: InfoBarUI.UIKind.Button, action: () => _workspace.Options = _workspace.Options.WithChangedOption(NeverShowAgain, true), closeAfterAction: true)); } void AddEditorconfigSolutionItem() { var addSolutionItemService = _workspace.Services.GetRequiredService <IAddSolutionItemService>(); addSolutionItemService.AddSolutionItemAsync(analyzerConfigDocumentFilePath, CancellationToken.None).Wait(); } }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) { // guard us from cancellation try { ProcessEvents(args, _listener.BeginAsyncOperation("OnWorkspaceChanged")); } catch (OperationCanceledException oce) { if (NotOurShutdownToken(oce)) { throw; } // it is our cancellation, ignore } catch (AggregateException ae) { ae = ae.Flatten(); // If we had a mix of exceptions, don't eat it if (ae.InnerExceptions.Any(e => !(e is OperationCanceledException)) || ae.InnerExceptions.Cast<OperationCanceledException>().Any(NotOurShutdownToken)) { // We had a cancellation with a different token, so don't eat it throw; } // it is our cancellation, ignore } }
private void OnWorkspaceChangedLookForOptionsChanges(object sender, WorkspaceChangeEventArgs e) { if (e.Kind == WorkspaceChangeKind.SolutionCleared || e.Kind == WorkspaceChangeKind.SolutionReloaded || e.Kind == WorkspaceChangeKind.SolutionRemoved) { Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForOptionsChanges; } else if (e.ProjectId == ProjectId) { if (e.Kind == WorkspaceChangeKind.ProjectRemoved) { Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForOptionsChanges; } else if (e.Kind == WorkspaceChangeKind.ProjectChanged) { OnProjectConfigurationChanged(); } else if (e.DocumentId != null) { switch (e.Kind) { case WorkspaceChangeKind.AnalyzerConfigDocumentAdded: case WorkspaceChangeKind.AnalyzerConfigDocumentChanged: case WorkspaceChangeKind.AnalyzerConfigDocumentReloaded: case WorkspaceChangeKind.AnalyzerConfigDocumentRemoved: OnProjectConfigurationChanged(); break; } } } return; // Local functions. void OnProjectConfigurationChanged() { var project = e.NewSolution.GetRequiredProject(ProjectId); var newGeneralDiagnosticOption = project.CompilationOptions !.GeneralDiagnosticOption; var newSpecificDiagnosticOptions = project.CompilationOptions !.SpecificDiagnosticOptions; var newAnalyzerConfigOptions = project.GetAnalyzerConfigOptions(); if (newGeneralDiagnosticOption != _generalDiagnosticOption || !object.ReferenceEquals(newSpecificDiagnosticOptions, _specificDiagnosticOptions) || !object.ReferenceEquals(newAnalyzerConfigOptions?.TreeOptions, _analyzerConfigOptions?.TreeOptions) || !object.ReferenceEquals(newAnalyzerConfigOptions?.AnalyzerOptions, _analyzerConfigOptions?.AnalyzerOptions)) { _generalDiagnosticOption = newGeneralDiagnosticOption; _specificDiagnosticOptions = newSpecificDiagnosticOptions; _analyzerConfigOptions = newAnalyzerConfigOptions; Contract.ThrowIfNull(_items, "We only subscribe to events after we create the items, so this should not be null."); foreach (var item in _items.OfType <DiagnosticItem>()) { var effectiveSeverity = item.Descriptor.GetEffectiveSeverity(project.CompilationOptions, newAnalyzerConfigOptions); item.UpdateEffectiveSeverity(effectiveSeverity); } } } }
public static bool IsActiveDocumentCleared(this WorkspaceChangeEventArgs changeEventArgs, Document?oldDocument) => changeEventArgs.CheckIfNull(nameof(changeEventArgs)).Kind switch {
async void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { await CheckForSemanticChange(); }
async void Ws_WorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { var ws = (Microsoft.CodeAnalysis.Workspace)sender; var currentSolution = ws.CurrentSolution; if (currentSolution == null) { return; } try { switch (e.Kind) { case WorkspaceChangeKind.ProjectAdded: var project1 = currentSolution.GetProject(e.ProjectId); if (project1 != null) { SearchAsync(documentInfos, project1, default(CancellationToken)); } break; case WorkspaceChangeKind.ProjectRemoved: var project = currentSolution.GetProject(e.ProjectId); if (project != null) { foreach (var docId in project.DocumentIds) { RemoveDocument(documentInfos, docId); } } break; case WorkspaceChangeKind.DocumentAdded: var document = currentSolution.GetDocument(e.DocumentId); if (document != null) { await UpdateDocument(documentInfos, document, default(CancellationToken)); } break; case WorkspaceChangeKind.DocumentRemoved: RemoveDocument(documentInfos, e.DocumentId); break; case WorkspaceChangeKind.DocumentChanged: var doc = currentSolution.GetDocument(e.DocumentId); if (doc != null) { CancellationTokenSource tcs; lock (documentChangedCts) { CancellationTokenSource oldTcs; if (documentChangedCts.TryGetValue(e.DocumentId, out oldTcs)) { oldTcs.Cancel(); } tcs = new CancellationTokenSource(); documentChangedCts [e.DocumentId] = tcs; } try { //Delaying parsing of new content for 1 second shouldn't be noticable by user //since he would have to edit file and instantlly go to search for newly written member... await Task.Delay(1000, tcs.Token).ConfigureAwait(false); await Task.Run(delegate { return(UpdateDocument(documentInfos, doc, tcs.Token)); }, tcs.Token).ConfigureAwait(false); } finally { lock (documentChangedCts) { //cts might be replaced by newer call cts CancellationTokenSource existingCts; if (documentChangedCts.TryGetValue(e.DocumentId, out existingCts) && tcs == existingCts) { documentChangedCts.Remove(e.DocumentId); } } } } break; } } catch (AggregateException ae) { ae.Flatten().Handle(ex => ex is OperationCanceledException); } catch (OperationCanceledException) { } catch (Exception ex) { LoggingService.LogError("Error while updating navigation symbol cache.", ex); } }
private void WorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { ignoreLayerChange = true; Layers = workspace.Drawing.GetLayers().OrderBy(l => l.Name).Select(l => new ReadOnlyLayerViewModel(l)); ignoreLayerChange = false; }
// We override Workspace_WorkspaceChanged in order to enforce calls to this to be on the project snapshot manager's // thread. OmniSharp currently has an issue where they update the Solution on multiple different threads resulting // in change events dispatching through the Workspace on multiple different threads. This normalizes // that abnormality. internal override void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs args) { _ = Workspace_WorkspaceChangedAsync(sender, args, CancellationToken.None); }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { Debug.Assert(View == null); StartRefresh(); }
// Here we're specifically listening for cases when a user opens a Razor document and an active C# content gets created. internal void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs args) { lock (_workspaceChangedLock) { switch (args.Kind) { case WorkspaceChangeKind.DocumentAdded: { // We could technically listen for DocumentAdded here but just because a document gets added doesn't mean it has content included. // Therefore we need to wait for content to populated for Razor files so we don't preemptively remove the corresponding background // C# before the active C# content has been populated. var project = args.NewSolution.GetProject(args.ProjectId); var document = project.GetDocument(args.DocumentId); if (document.FilePath == null) { break; } if (document.FilePath.EndsWith(ActiveVirtualDocumentSuffix, StringComparison.Ordinal) && !document.FilePath.EndsWith(BackgroundVirtualDocumentSuffix, StringComparison.Ordinal)) { // Document from editor got opened, clear out any background documents of the same type var razorDocumentFilePath = GetRazorDocumentFilePath(document); var backgroundDocumentFilePath = GetBackgroundVirtualDocumentFilePath(razorDocumentFilePath); var backgroundDocument = GetRoslynDocument(project, backgroundDocumentFilePath); if (backgroundDocument != null) { _workspace.RemoveDocument(backgroundDocument.Id); } } break; } case WorkspaceChangeKind.DocumentRemoved: { var project = args.OldSolution.GetProject(args.ProjectId); var document = project.GetDocument(args.DocumentId); if (document.FilePath == null) { break; } if (document.FilePath.EndsWith(ActiveVirtualDocumentSuffix, StringComparison.Ordinal) && !document.FilePath.EndsWith(BackgroundVirtualDocumentSuffix, StringComparison.Ordinal)) { var razorDocumentFilePath = GetRazorDocumentFilePath(document); if (File.Exists(razorDocumentFilePath)) { // Razor document closed because the backing C# virtual document went away var backgroundDocumentFilePath = GetBackgroundVirtualDocumentFilePath(razorDocumentFilePath); var newName = Path.GetFileName(backgroundDocumentFilePath); var delegatedTextLoader = new DelegatedTextLoader(document); var movedDocumentInfo = DocumentInfo.Create(args.DocumentId, newName, loader: delegatedTextLoader, filePath: backgroundDocumentFilePath); _workspace.AddDocument(movedDocumentInfo); } } } break; } } }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) { // We're getting an event for a workspace we already disconnected from if (args.NewSolution.Workspace != _workspace) { // we are async so we are getting events from previous workspace we were associated with // just ignore them return; } switch (args.Kind) { case WorkspaceChangeKind.ProjectChanged: { var documentId = _workspace.GetDocumentIdInCurrentContext(_subjectBuffer.AsTextContainer()); if (documentId == null || documentId.ProjectId != args.ProjectId) { break; } var oldProject = args.OldSolution.GetProject(args.ProjectId); var newProject = args.NewSolution.GetProject(args.ProjectId); // make sure in case of parse config change, we re-colorize whole document. not just edited section. var configChanged = !object.Equals(oldProject.ParseOptions, newProject.ParseOptions); EnqueueParseSnapshotTask(newProject.GetDocument(documentId)); break; } case WorkspaceChangeKind.DocumentChanged: { ParseIfThisDocument(args.OldSolution, args.NewSolution, args.DocumentId); break; } } // put a request to update last parsed document. // this will make us to enqueue a request per workspace change event per a opened file. // if this show up as perf cost, we might need to revisit this design. currently we do this so that our Roslyn Language Service API // maintain its consistency. var newSolution = args.NewSolution; _workQueue.EnqueueBackgroundTask(c => UpdateLastParsedDocumentAsync(newSolution, c), "UpdateLastParsedDocument", CancellationToken.None); }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { EnqueueUpdate(); }
private void ProcessEvent(WorkspaceChangeEventArgs args, string eventName) { SolutionCrawlerLogger.LogWorkspaceEvent(_logAggregator, (int)args.Kind); // TODO: add telemetry that record how much it takes to process an event (max, min, average and etc) switch (args.Kind) { case WorkspaceChangeKind.SolutionAdded: EnqueueFullSolutionEvent(args.NewSolution, InvocationReasons.DocumentAdded, eventName); break; case WorkspaceChangeKind.SolutionChanged: case WorkspaceChangeKind.SolutionReloaded: EnqueueSolutionChangedEvent(args.OldSolution, args.NewSolution, eventName); break; case WorkspaceChangeKind.SolutionRemoved: EnqueueFullSolutionEvent(args.OldSolution, InvocationReasons.SolutionRemoved, eventName); break; case WorkspaceChangeKind.SolutionCleared: EnqueueFullSolutionEvent(args.OldSolution, InvocationReasons.DocumentRemoved, eventName); break; case WorkspaceChangeKind.ProjectAdded: Contract.ThrowIfNull(args.ProjectId); EnqueueFullProjectEvent(args.NewSolution, args.ProjectId, InvocationReasons.DocumentAdded, eventName); break; case WorkspaceChangeKind.ProjectChanged: case WorkspaceChangeKind.ProjectReloaded: Contract.ThrowIfNull(args.ProjectId); EnqueueProjectChangedEvent(args.OldSolution, args.NewSolution, args.ProjectId, eventName); break; case WorkspaceChangeKind.ProjectRemoved: Contract.ThrowIfNull(args.ProjectId); EnqueueFullProjectEvent(args.OldSolution, args.ProjectId, InvocationReasons.DocumentRemoved, eventName); break; case WorkspaceChangeKind.DocumentAdded: Contract.ThrowIfNull(args.DocumentId); EnqueueFullDocumentEvent(args.NewSolution, args.DocumentId, InvocationReasons.DocumentAdded, eventName); break; case WorkspaceChangeKind.DocumentReloaded: case WorkspaceChangeKind.DocumentChanged: Contract.ThrowIfNull(args.DocumentId); EnqueueDocumentChangedEvent(args.OldSolution, args.NewSolution, args.DocumentId, eventName); break; case WorkspaceChangeKind.DocumentRemoved: Contract.ThrowIfNull(args.DocumentId); EnqueueFullDocumentEvent(args.OldSolution, args.DocumentId, InvocationReasons.DocumentRemoved, eventName); break; case WorkspaceChangeKind.AdditionalDocumentAdded: case WorkspaceChangeKind.AdditionalDocumentRemoved: case WorkspaceChangeKind.AdditionalDocumentChanged: case WorkspaceChangeKind.AdditionalDocumentReloaded: case WorkspaceChangeKind.AnalyzerConfigDocumentAdded: case WorkspaceChangeKind.AnalyzerConfigDocumentRemoved: case WorkspaceChangeKind.AnalyzerConfigDocumentChanged: case WorkspaceChangeKind.AnalyzerConfigDocumentReloaded: // If an additional file or .editorconfig has changed we need to reanalyze the entire project. Contract.ThrowIfNull(args.ProjectId); EnqueueFullProjectEvent(args.NewSolution, args.ProjectId, InvocationReasons.AdditionalDocumentChanged, eventName); break; default: throw ExceptionUtilities.UnexpectedValue(args.Kind); } }
// Internal for testing, virtual for temporary VSCode workaround internal virtual void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { Project project; switch (e.Kind) { case WorkspaceChangeKind.ProjectAdded: { project = e.NewSolution.GetProject(e.ProjectId); Debug.Assert(project != null); if (TryGetProjectSnapshot(project.FilePath, out var projectSnapshot)) { _workspaceStateGenerator.Update(project, projectSnapshot); } break; } case WorkspaceChangeKind.ProjectChanged: case WorkspaceChangeKind.ProjectReloaded: { project = e.NewSolution.GetProject(e.ProjectId); if (TryGetProjectSnapshot(project?.FilePath, out var _)) { EnqueueUpdate(e.ProjectId); } break; } case WorkspaceChangeKind.ProjectRemoved: { project = e.OldSolution.GetProject(e.ProjectId); Debug.Assert(project != null); if (TryGetProjectSnapshot(project?.FilePath, out var projectSnapshot)) { _workspaceStateGenerator.Update(workspaceProject: null, projectSnapshot); } break; } case WorkspaceChangeKind.DocumentChanged: case WorkspaceChangeKind.DocumentReloaded: { // This is the case when a component declaration file changes on disk. We have an MSBuild // generator configured by the SDK that will poke these files on disk when a component // is saved, or loses focus in the editor. project = e.OldSolution.GetProject(e.ProjectId); var document = project.GetDocument(e.DocumentId); if (document.FilePath == null) { break; } // Using EndsWith because Path.GetExtension will ignore everything before .cs // Using Ordinal because the SDK generates these filenames. if (document.FilePath.EndsWith(".cshtml.g.cs", StringComparison.Ordinal) || document.FilePath.EndsWith(".razor.g.cs", StringComparison.Ordinal)) { EnqueueUpdate(e.ProjectId); } break; } case WorkspaceChangeKind.SolutionAdded: case WorkspaceChangeKind.SolutionChanged: case WorkspaceChangeKind.SolutionCleared: case WorkspaceChangeKind.SolutionReloaded: case WorkspaceChangeKind.SolutionRemoved: if (e.OldSolution != null) { foreach (var p in e.OldSolution.Projects) { if (TryGetProjectSnapshot(p?.FilePath, out var projectSnapshot)) { _workspaceStateGenerator.Update(workspaceProject: null, projectSnapshot); } } } InitializeSolution(e.NewSolution); break; } }
private void ProcessDocumentEvent(WorkspaceChangeEventArgs e, IAsyncToken asyncToken) { switch (e.Kind) { case WorkspaceChangeKind.DocumentAdded: EnqueueEvent(e.NewSolution, e.DocumentId, InvocationReasons.DocumentAdded, asyncToken); break; case WorkspaceChangeKind.DocumentRemoved: EnqueueEvent(e.OldSolution, e.DocumentId, InvocationReasons.DocumentRemoved, asyncToken); break; case WorkspaceChangeKind.DocumentReloaded: case WorkspaceChangeKind.DocumentChanged: EnqueueEvent(e.OldSolution, e.NewSolution, e.DocumentId, asyncToken); break; case WorkspaceChangeKind.AdditionalDocumentAdded: case WorkspaceChangeKind.AdditionalDocumentRemoved: case WorkspaceChangeKind.AdditionalDocumentChanged: case WorkspaceChangeKind.AdditionalDocumentReloaded: // If an additional file has changed we need to reanalyze the entire project. EnqueueEvent(e.NewSolution, e.ProjectId, InvocationReasons.AdditionalDocumentChanged, asyncToken); break; default: throw ExceptionUtilities.Unreachable; } }
protected virtual void SolutionOrProjectChanged(WorkspaceChangeEventArgs e) { // do nothing in base implementation }
private void ProcessSolutionEvent(WorkspaceChangeEventArgs e, IAsyncToken asyncToken) { switch (e.Kind) { case WorkspaceChangeKind.SolutionAdded: OnSolutionAdded(e.NewSolution); EnqueueEvent(e.NewSolution, InvocationReasons.DocumentAdded, asyncToken); break; case WorkspaceChangeKind.SolutionRemoved: EnqueueEvent(e.OldSolution, InvocationReasons.SolutionRemoved, asyncToken); break; case WorkspaceChangeKind.SolutionCleared: EnqueueEvent(e.OldSolution, InvocationReasons.DocumentRemoved, asyncToken); break; case WorkspaceChangeKind.SolutionChanged: case WorkspaceChangeKind.SolutionReloaded: EnqueueEvent(e.OldSolution, e.NewSolution, asyncToken); break; default: throw ExceptionUtilities.Unreachable; } }