Exemplo n.º 1
0
        private bool IsCurrentContext(DocumentKey documentKey)
        {
            AssertIsForeground();
            var document = documentKey.HostProject.GetCurrentDocumentFromPath(documentKey.Moniker);

            return(document != null && LinkedFileUtilities.IsCurrentContextHierarchy(document, _runningDocumentTable));
        }
        public void AddAdditionalFile(string additionalFilePath)
        {
            var document = this.DocumentProvider.TryGetDocumentForFile(
                this,
                (uint)VSConstants.VSITEMID.Nil,
                filePath: additionalFilePath,
                sourceCodeKind: SourceCodeKind.Regular,
                canUseTextBuffer: _ => true);

            if (document == null)
            {
                return;
            }

            AddAdditionalDocument(document,
                                  isCurrentContext: LinkedFileUtilities.IsCurrentContextHierarchy(document, RunningDocumentTable));
        }
Exemplo n.º 3
0
        /// <summary>
        /// Starts pushing events from the given projects to the workspace hosts and notifies about open documents.
        /// </summary>
        /// <remarks>This method must be called on the foreground thread.</remarks>
        internal void StartPushingToWorkspaceAndNotifyOfOpenDocuments(IEnumerable <AbstractProject> projects)
        {
            AssertIsForeground();

            // If the solution is closing we shouldn't do anything, because all of our state is
            // in the process of going away. This can happen if we receive notification that a document has
            // opened in the middle of the solution close operation.
            if (_solutionIsClosing)
            {
                return;
            }

            // We need to push these projects and any project dependencies we already know about. Therefore, compute the
            // transitive closure of the projects that haven't already been pushed, keeping them in appropriate order.
            var visited       = new HashSet <AbstractProject>();
            var inOrderToPush = new List <AbstractProject>();

            void addToInOrderToPush(AbstractProject project)
            {
                Contract.ThrowIfFalse(ContainsProject(project));

                // Bail out if any of the following is true:
                //  1. We have already started pushing changes for this project OR
                //  2. We have already visited this project in a prior recursive call
                if (_pushedProjects.Contains(project) || !visited.Add(project))
                {
                    return;
                }

                foreach (var projectReference in project.GetCurrentProjectReferences())
                {
                    addToInOrderToPush(GetProject(projectReference.ProjectId));
                }

                inOrderToPush.Add(project);
            }

            foreach (var project in projects)
            {
                addToInOrderToPush(project);
            }

            var projectInfos = inOrderToPush.Select(p => p.CreateProjectInfoForCurrentState()).ToImmutableArray();

            // We need to enable projects to start pushing changes to the workspace even before we add the solution/project to the host.
            // This is required because between the point we capture the project info for current state and the point where we start pushing to the workspace,
            // project system may send new events on the AbstractProject on a background thread, and these won't get pushed over to the workspace hosts as we didn't set the _pushingChangesToWorkspaceHost flag on the AbstractProject.
            // By invoking StartPushingToWorkspaceHosts upfront, any project state changes on the background thread will enqueue notifications to workspace hosts on foreground scheduled tasks.
            foreach (var project in inOrderToPush)
            {
                project.PushingChangesToWorkspace = true;

                Logger.Log(FunctionId.AbstractProject_PushedToWorkspace,
                           KeyValueLogMessage.Create(LogType.Trace, m =>
                {
                    m[AbstractProject.ProjectGuidPropertyName] = project.Guid;
                }));
            }

            using (WorkspaceServices.GetService <IGlobalOperationNotificationService>()?.Start("Add Project to Workspace"))
            {
                if (!_solutionAdded)
                {
                    string       solutionFilePath = null;
                    VersionStamp?version          = default;
                    // Figure out the solution version
                    if (ErrorHandler.Succeeded(_vsSolution.GetSolutionInfo(out var solutionDirectory, out var solutionFileName, out var userOptsFile)) && solutionFileName != null)
                    {
                        solutionFilePath = Path.Combine(solutionDirectory, solutionFileName);
                        if (File.Exists(solutionFilePath))
                        {
                            version = VersionStamp.Create(File.GetLastWriteTimeUtc(solutionFilePath));
                        }
                    }

                    if (version == null)
                    {
                        version = VersionStamp.Create();
                    }

                    var id = SolutionId.CreateNewId(string.IsNullOrWhiteSpace(solutionFileName) ? null : solutionFileName);

                    var solutionInfo = SolutionInfo.Create(id, version.Value, solutionFilePath, projects: projectInfos);

                    NotifyWorkspace(workspace => workspace.OnSolutionAdded(solutionInfo));

                    _solutionAdded = true;

                    var persistenceService = WorkspaceServices.GetRequiredService <IPersistentStorageLocationService>() as VisualStudioPersistentStorageLocationService;
                    persistenceService?.UpdateForVisualStudioWorkspace(_workspace);
                }
                else
                {
                    // The solution is already added, so we'll just do project added notifications from here
                    foreach (var projectInfo in projectInfos)
                    {
                        NotifyWorkspace(workspace => workspace.OnProjectAdded(projectInfo));
                    }
                }

                foreach (var project in inOrderToPush)
                {
                    _pushedProjects.Add(project);

                    foreach (var document in project.GetCurrentDocuments())
                    {
                        if (document.IsOpen)
                        {
                            NotifyWorkspace(workspace =>
                            {
                                workspace.OnDocumentOpened(
                                    document.Id,
                                    document.GetOpenTextBuffer().AsTextContainer(),
                                    isCurrentContext: LinkedFileUtilities.IsCurrentContextHierarchy(document, _runningDocumentTable));
                                (workspace as VisualStudioWorkspaceImpl)?.ConnectToSharedHierarchyEvents(document);
                            });
                        }
                    }
                }
            }
        }
Exemplo n.º 4
0
            internal void StartPushingToWorkspaceAndNotifyOfOpenDocuments(
                IEnumerable <AbstractProject> projects)
            {
                AssertIsForeground();

                // If the workspace host isn't actually ready yet, we shouldn't do anything.
                // Also, if the solution is closing we shouldn't do anything either, because all of our state is
                // in the process of going away. This can happen if we receive notification that a document has
                // opened in the middle of the solution close operation.
                if (!this.HostReadyForEvents || _tracker._solutionIsClosing)
                {
                    return;
                }

                // We need to push these projects and any project dependencies we already know about. Therefore, compute the
                // transitive closure of the projects that haven't already been pushed, keeping them in appropriate order.
                var visited       = new HashSet <AbstractProject>();
                var inOrderToPush = new List <AbstractProject>();

                foreach (var project in projects)
                {
                    AddToPushListIfNeeded(project, inOrderToPush, visited);
                }

                var projectInfos = inOrderToPush.Select(p => p.CreateProjectInfoForCurrentState()).ToImmutableArray();

                // We need to enable projects to start pushing changes to workspace hosts even before we add the solution/project to the host.
                // This is required because between the point we capture the project info for current state and the point where we start pushing to workspace hosts,
                // project system may send new events on the AbstractProject on a background thread, and these won't get pushed over to the workspace hosts as we didn't set the _pushingChangesToWorkspaceHost flag on the AbstractProject.
                // By invoking StartPushingToWorkspaceHosts upfront, any project state changes on the background thread will enqueue notifications to workspace hosts on foreground scheduled tasks.
                foreach (var project in inOrderToPush)
                {
                    project.StartPushingToWorkspaceHosts();
                }

                if (!_solutionAdded)
                {
                    string       solutionFilePath = null;
                    VersionStamp?version          = default(VersionStamp?);
                    // Figure out the solution version
                    if (ErrorHandler.Succeeded(_tracker._vsSolution.GetSolutionInfo(out var solutionDirectory, out var solutionFileName, out var userOptsFile)) && solutionFileName != null)
                    {
                        solutionFilePath = Path.Combine(solutionDirectory, solutionFileName);
                        if (File.Exists(solutionFilePath))
                        {
                            version = VersionStamp.Create(File.GetLastWriteTimeUtc(solutionFilePath));
                        }
                    }

                    if (version == null)
                    {
                        version = VersionStamp.Create();
                    }

                    var id = SolutionId.CreateNewId(string.IsNullOrWhiteSpace(solutionFileName) ? null : solutionFileName);
                    _tracker.RegisterSolutionProperties(id);

                    var solutionInfo = SolutionInfo.Create(id, version.Value, solutionFilePath, projects: projectInfos);

                    this.Host.OnSolutionAdded(solutionInfo);

                    _solutionAdded = true;
                }
                else
                {
                    // The solution is already added, so we'll just do project added notifications from here
                    foreach (var projectInfo in projectInfos)
                    {
                        this.Host.OnProjectAdded(projectInfo);
                    }
                }

                foreach (var project in inOrderToPush)
                {
                    _pushedProjects.Add(project);

                    foreach (var document in project.GetCurrentDocuments())
                    {
                        if (document.IsOpen)
                        {
                            this.Host.OnDocumentOpened(
                                document.Id,
                                document.GetOpenTextBuffer(),
                                isCurrentContext: LinkedFileUtilities.IsCurrentContextHierarchy(document, _tracker._runningDocumentTable));
                        }
                    }
                }
            }