public async Task <IWorkspaceProjectContext> CreateProjectContextAsync( string languageName, string projectUniqueName, string projectFilePath, Guid projectGuid, object hierarchy, string binOutputPath, CancellationToken cancellationToken ) { await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var creationInfo = new VisualStudioProjectCreationInfo { FilePath = projectFilePath, Hierarchy = hierarchy as IVsHierarchy, ProjectGuid = projectGuid, }; var visualStudioProject = await _projectFactory .CreateAndAddToWorkspaceAsync( projectUniqueName, languageName, creationInfo, cancellationToken ) .ConfigureAwait(true); #pragma warning disable IDE0059 // Unnecessary assignment of a value // At this point we've mutated the workspace. So we're no longer cancellable. cancellationToken = CancellationToken.None; #pragma warning restore IDE0059 // Unnecessary assignment of a value if (languageName == LanguageNames.FSharp) { var shell = await _serviceProvider .GetServiceAsync <SVsShell, IVsShell7>() .ConfigureAwait(true); // Force the F# package to load; this is necessary because the F# package listens to WorkspaceChanged to // set up some items, and the F# project system doesn't guarantee that the F# package has been loaded itself // so we're caught in the middle doing this. var packageId = Guids.FSharpPackageId; await shell.LoadPackageAsync(ref packageId); } // CPSProject constructor has a UI thread dependencies currently, so switch back to the UI thread before proceeding. return(new CPSProject( visualStudioProject, _workspace, _projectCodeModelFactory, projectGuid, binOutputPath )); }
public async Task <IWorkspaceProjectContext> CreateProjectContextAsync( string languageName, string projectUniqueName, string?projectFilePath, Guid projectGuid, object?hierarchy, string?binOutputPath, string?assemblyName, CancellationToken cancellationToken) { var creationInfo = new VisualStudioProjectCreationInfo { AssemblyName = assemblyName, FilePath = projectFilePath, Hierarchy = hierarchy as IVsHierarchy, ProjectGuid = projectGuid, }; var visualStudioProject = await _projectFactory.CreateAndAddToWorkspaceAsync( projectUniqueName, languageName, creationInfo, cancellationToken).ConfigureAwait(false); #pragma warning disable IDE0059 // Unnecessary assignment of a value // At this point we've mutated the workspace. So we're no longer cancellable. cancellationToken = CancellationToken.None; #pragma warning restore IDE0059 // Unnecessary assignment of a value if (languageName == LanguageNames.FSharp) { await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var shell = await _serviceProvider.GetServiceAsync <SVsShell, IVsShell7>().ConfigureAwait(true); // Force the F# package to load; this is necessary because the F# package listens to WorkspaceChanged to // set up some items, and the F# project system doesn't guarantee that the F# package has been loaded itself // so we're caught in the middle doing this. var packageId = Guids.FSharpPackageId; await shell.LoadPackageAsync(ref packageId); await TaskScheduler.Default; } var project = new CPSProject(visualStudioProject, _workspace, _projectCodeModelFactory, projectGuid); // Set the output path in a batch; if we set the property directly we'll be taking a synchronous lock here and // potentially block up thread pool threads. Doing this in a batch means the global lock will be acquired asynchronously. project.StartBatch(); project.BinOutputPath = binOutputPath; await project.EndBatchAsync().ConfigureAwait(false); return(project); }
public FileChangeWatcherProvider(IThreadingContext threadingContext, [Import(typeof(SVsServiceProvider))] Shell.IAsyncServiceProvider serviceProvider) { // We do not want background work to implicitly block on the availability of the SVsFileChangeEx to avoid any deadlock risk, // since the first fetch for a file watcher might end up happening on the background. Watcher = new FileChangeWatcher(_fileChangeService.Task); System.Threading.Tasks.Task.Run(async() => { await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); var fileChangeService = (IVsAsyncFileChangeEx)await serviceProvider.GetServiceAsync(typeof(SVsFileChangeEx)).ConfigureAwait(true); _fileChangeService.SetResult(fileChangeService); }); }
private async Task InitializeAndPopulateSnippetsCacheAsync(Shell.IAsyncServiceProvider asyncServiceProvider) { await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); var textManager = (IVsTextManager2?)await asyncServiceProvider.GetServiceAsync(typeof(SVsTextManager)).ConfigureAwait(true); Assumes.Present(textManager); if (textManager.GetExpansionManager(out _expansionManager) == VSConstants.S_OK) { ComEventSink.Advise <IVsExpansionEvents>(_expansionManager, this); await PopulateSnippetCacheAsync().ConfigureAwait(false); } }
public FileChangeWatcherProvider( IThreadingContext threadingContext, IAsynchronousOperationListenerProvider listenerProvider, [Import(typeof(SVsServiceProvider))] Shell.IAsyncServiceProvider serviceProvider) { var fileChangeService = Task.Factory.StartNew( async() => { await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(threadingContext.DisposalToken); var fileChangeService = (IVsAsyncFileChangeEx?)await serviceProvider.GetServiceAsync(typeof(SVsFileChangeEx)).ConfigureAwait(true); Assumes.Present(fileChangeService); return(fileChangeService); }, threadingContext.DisposalToken, TaskCreationOptions.RunContinuationsAsynchronously, TaskScheduler.Default) .Unwrap(); // We do not want background work to implicitly block on the availability of the SVsFileChangeEx to avoid any deadlock risk, // since the first fetch for a file watcher might end up happening on the background. Watcher = new FileChangeWatcher(listenerProvider, fileChangeService); }
public async Task <VisualStudioProject> CreateAndAddToWorkspaceAsync( string projectSystemName, string language, VisualStudioProjectCreationInfo creationInfo, CancellationToken cancellationToken) { // HACK: Fetch this service to ensure it's still created on the UI thread; once this is // moved off we'll need to fix up it's constructor to be free-threaded. await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); _visualStudioWorkspaceImpl.Services.GetRequiredService <VisualStudioMetadataReferenceManager>(); _visualStudioWorkspaceImpl.SubscribeExternalErrorDiagnosticUpdateSourceToSolutionBuildEvents(); // Since we're on the UI thread here anyways, use that as an opportunity to grab the // IVsSolution object and solution file path. // // ConfigureAwait(true) as we have to come back to the UI thread to do the cast to IVsSolution2. var solution = (IVsSolution2?)await _serviceProvider.GetServiceAsync(typeof(SVsSolution)).ConfigureAwait(true); var solutionFilePath = solution != null && ErrorHandler.Succeeded(solution.GetSolutionInfo(out _, out var filePath, out _)) ? filePath : null; // Following can be off the UI thread. await TaskScheduler.Default; // From this point on, we start mutating the solution. So make us non cancellable. cancellationToken = CancellationToken.None; var id = ProjectId.CreateNewId(projectSystemName); var assemblyName = creationInfo.AssemblyName ?? projectSystemName; // We will use the project system name as the default display name of the project var project = new VisualStudioProject( _visualStudioWorkspaceImpl, _dynamicFileInfoProviders, _hostDiagnosticUpdateSource, id, displayName: projectSystemName, language, assemblyName: assemblyName, compilationOptions: creationInfo.CompilationOptions, filePath: creationInfo.FilePath, parseOptions: creationInfo.ParseOptions); var versionStamp = creationInfo.FilePath != null?VersionStamp.Create(File.GetLastWriteTimeUtc(creationInfo.FilePath)) : VersionStamp.Create(); await _visualStudioWorkspaceImpl.ApplyChangeToWorkspaceAsync(w => { _visualStudioWorkspaceImpl.AddProjectToInternalMaps_NoLock(project, creationInfo.Hierarchy, creationInfo.ProjectGuid, projectSystemName); var projectInfo = ProjectInfo.Create( id, versionStamp, name: projectSystemName, assemblyName: assemblyName, language: language, filePath: creationInfo.FilePath, compilationOptions: creationInfo.CompilationOptions, parseOptions: creationInfo.ParseOptions) .WithTelemetryId(creationInfo.ProjectGuid); // If we don't have any projects and this is our first project being added, then we'll create a new SolutionId // and count this as the solution being added so that event is raised. if (w.CurrentSolution.ProjectIds.Count == 0) { var solutionSessionId = GetSolutionSessionId(); w.OnSolutionAdded( SolutionInfo.Create( SolutionId.CreateNewId(solutionFilePath), VersionStamp.Create(), solutionFilePath, projects: new[] { projectInfo }, analyzerReferences: w.CurrentSolution.AnalyzerReferences) .WithTelemetryId(solutionSessionId)); } else { w.OnProjectAdded(projectInfo); } }).ConfigureAwait(false); // Ensure that other VS contexts get accurate information that the UIContext for this language is now active. // This is not cancellable as we have already mutated the solution. await _visualStudioWorkspaceImpl.RefreshProjectExistsUIContextForLanguageAsync(language, CancellationToken.None).ConfigureAwait(false); return(project);