public VisualStudioProject CreateAndAddToWorkspace(string projectSystemName, string language, VisualStudioProjectCreationInfo creationInfo) { // 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. _visualStudioWorkspaceImpl.Services.GetRequiredService <VisualStudioMetadataReferenceManager>(); // HACK: since we're on the UI thread, ensure we initialize our options provider which depends on a UI-affinitized experimentation service _visualStudioWorkspaceImpl.EnsureDocumentOptionProvidersInitialized(); 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(); _visualStudioWorkspaceImpl.AddProjectToInternalMaps(project, creationInfo.Hierarchy, creationInfo.ProjectGuid, projectSystemName); _visualStudioWorkspaceImpl.ApplyChangeToWorkspace(w => { 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 if (w.CurrentSolution.ProjectIds.Count == 0) { // Fetch the current solution path. Since we're on the UI thread right now, we can do that. string?solutionFilePath = null; var solution = (IVsSolution)Shell.ServiceProvider.GlobalProvider.GetService(typeof(SVsSolution)); if (solution != null) { if (ErrorHandler.Failed(solution.GetSolutionInfo(out _, out solutionFilePath, out _))) { // Paranoia: if the call failed, we definitely don't want to use any stuff that was set solutionFilePath = null; } } 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); } _visualStudioWorkspaceImpl.RefreshProjectExistsUIContextForLanguage(language); }); return(project);
public VisualStudioProject CreateAndAddToWorkspace(string projectSystemName, string language, VisualStudioProjectCreationInfo creationInfo) { // 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. _visualStudioWorkspaceImpl.Services.GetRequiredService <VisualStudioMetadataReferenceManager>(); // HACK: since we're on the UI thread, ensure we initialize our options provider which depends on a UI-affinitized experimentation service _visualStudioWorkspaceImpl.EnsureDocumentOptionProvidersInitialized(); var id = ProjectId.CreateNewId(projectSystemName); var directoryNameOpt = creationInfo.FilePath != null?Path.GetDirectoryName(creationInfo.FilePath) : null; // 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, directoryNameOpt); var versionStamp = creationInfo.FilePath != null?VersionStamp.Create(File.GetLastWriteTimeUtc(creationInfo.FilePath)) : VersionStamp.Create(); var assemblyName = creationInfo.AssemblyName ?? projectSystemName; _visualStudioWorkspaceImpl.AddProjectToInternalMaps(project, creationInfo.Hierarchy, creationInfo.ProjectGuid, projectSystemName); _visualStudioWorkspaceImpl.ApplyChangeToWorkspace(w => { var projectInfo = ProjectInfo.Create( id, versionStamp, name: projectSystemName, assemblyName: assemblyName, language: language, filePath: creationInfo.FilePath, compilationOptions: creationInfo.CompilationOptions, parseOptions: creationInfo.ParseOptions); // If we don't have any projects and this is our first project being added, then we'll create a new SolutionId if (w.CurrentSolution.ProjectIds.Count == 0) { // Fetch the current solution path. Since we're on the UI thread right now, we can do that. string solutionFilePath = null; var solution = (IVsSolution)Shell.ServiceProvider.GlobalProvider.GetService(typeof(SVsSolution)); if (solution != null) { if (ErrorHandler.Failed(solution.GetSolutionInfo(out _, out solutionFilePath, out _))) { // Paranoia: if the call failed, we definitely don't want to use any stuff that was set solutionFilePath = null; } } w.OnSolutionAdded( SolutionInfo.Create( SolutionId.CreateNewId(solutionFilePath), VersionStamp.Create(), solutionFilePath, projects: new[] { projectInfo })); // set working folder for the persistent service var persistenceService = w.Services.GetRequiredService <IPersistentStorageLocationService>() as VisualStudioPersistentStorageLocationService; persistenceService?.UpdateForVisualStudioWorkspace(w); } else { w.OnProjectAdded(projectInfo); } }); // We do all these sets after the w.OnProjectAdded, as the setting of these properties is going to try to modify the workspace // again. Those modifications will all implicitly do nothing, since the workspace already has the values from above. // We could pass these all through the constructor (but that gets verbose), or have some other control to ignore these, // but that seems like overkill. project.AssemblyName = assemblyName; project.CompilationOptions = creationInfo.CompilationOptions; project.FilePath = creationInfo.FilePath; project.ParseOptions = creationInfo.ParseOptions; return(project); }
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>(); // 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; await _visualStudioWorkspaceImpl.EnsureDocumentOptionProvidersInitializedAsync(cancellationToken).ConfigureAwait(true); // 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(); _visualStudioWorkspaceImpl.AddProjectToInternalMaps(project, creationInfo.Hierarchy, creationInfo.ProjectGuid, projectSystemName); _visualStudioWorkspaceImpl.ApplyChangeToWorkspace(w => { 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 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); } }); _visualStudioWorkspaceImpl.RefreshProjectExistsUIContextForLanguage(language); return(project);