Exemplo n.º 1
0
        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
                       ));
        }
Exemplo n.º 2
0
        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);
        }
Exemplo n.º 3
0
        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);
            });
        }
Exemplo n.º 4
0
        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);
        }
Exemplo n.º 6
0
        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);