コード例 #1
0
        /// <summary>
        /// Move project elements based on the given project tree, reference project tree and move action.
        /// Will modify the project if successful, but not save; only dirty.
        /// </summary>
        private static bool TryMove(Project project, IProjectTree projectTree, IProjectTree?referenceProjectTree, MoveAction moveAction)
        {
            if (!HasValidDisplayOrder(projectTree) || !HasValidDisplayOrder(referenceProjectTree))
            {
                return(false);
            }

            if (projectTree == referenceProjectTree)
            {
                return(false);
            }

            if (referenceProjectTree != null)
            {
                // The reference element is the element for which moved items will be above or below it.
                ProjectItemElement?referenceElement = TryGetReferenceElement(project, referenceProjectTree, ImmutableArray <string> .Empty, moveAction);

                if (referenceElement != null)
                {
                    ImmutableArray <ProjectItemElement> elements = GetItemElements(project, projectTree, ImmutableArray <string> .Empty);
                    return(TryMoveElements(elements, referenceElement, moveAction));
                }
            }

            return(false);
        }
コード例 #2
0
        /// <summary>
        /// Move project elements based on the given project tree and move action.
        /// Will modify the project if successful, but not save; only dirty.
        /// </summary>
        private static bool TryMove(Project project, IProjectTree projectTree, MoveAction moveAction)
        {
            // Determine what sibling we want to look at based on if we are moving up or down.
            IProjectTree?sibling = GetSiblingByMoveAction(projectTree, moveAction);

            return(TryMove(project, projectTree, sibling, moveAction));
        }
コード例 #3
0
        /// <summary>
        /// Builds a sub tree under root: target framework or Dependencies node when there is only one target.
        /// </summary>
        private async Task <IProjectTree> BuildSubTreeAsync(
            IProjectTree rootNode,
            TargetedDependenciesSnapshot targetedSnapshot,
            List <IDependency> dependencies,
            bool isActiveTarget,
            bool shouldCleanup)
        {
            HashSet <IProjectTree>?currentNodes = shouldCleanup
                ? new HashSet <IProjectTree>(capacity: dependencies.Count)
                : null;

            foreach (IDependency dependency in dependencies)
            {
                IProjectTree?dependencyNode      = rootNode.FindChildWithCaption(dependency.Caption);
                bool         isNewDependencyNode = dependencyNode == null;

                if (dependencyNode != null &&
                    dependency.Flags.Contains(DependencyTreeFlags.SupportsHierarchy))
                {
                    if ((dependency.Resolved && dependencyNode.Flags.Contains(DependencyTreeFlags.Unresolved)) ||
                        (!dependency.Resolved && dependencyNode.Flags.Contains(DependencyTreeFlags.Resolved)))
                    {
                        // when transition from unresolved to resolved or vise versa - remove old node
                        // and re-add new  one to allow GraphProvider to recalculate children
                        isNewDependencyNode = true;
                        rootNode            = dependencyNode.Remove();
                        dependencyNode      = null;
                    }
                }

                // NOTE this project system supports multiple implicit configuration dimensions (such as target framework)
                // which is a concept not modelled by DTE/VSLangProj. In order to produce a sensible view of the project
                // via automation, we expose only the active target framework at any given time.
                //
                // This is achieved by using IProjectItemTree for active target framework items, and IProjectTree for inactive
                // target frameworks. CPS only creates automation objects for items with "Reference" flag if they implement
                // IProjectItemTree. See SimpleItemNode.Initialize (in CPS) for details.

                dependencyNode = await CreateOrUpdateNodeAsync(
                    dependencyNode,
                    dependency,
                    targetedSnapshot,
                    isProjectItem : isActiveTarget);

                currentNodes?.Add(dependencyNode);

                IProjectTree?parent = isNewDependencyNode
                    ? rootNode.Add(dependencyNode).Parent
                    : dependencyNode.Parent;

                Assumes.NotNull(parent);

                rootNode = parent !;
            }

            return(currentNodes != null // shouldCleanup
                ? CleanupOldNodes(rootNode, currentNodes)
                : rootNode);
        }
コード例 #4
0
        protected override bool TryGetProjectNode(IProjectTree targetRootNode, IRelatableItem item, [NotNullWhen(returnValue: true)] out IProjectTree?projectTree)
        {
            IProjectTree?typeGroupNode = targetRootNode.FindChildWithFlags(DependencyTreeFlags.ProjectDependencyGroup);

            projectTree = typeGroupNode?.FindChildWithFlags(ProjectTreeFlags.Create("$ID:" + Library.Name));

            return(projectTree != null);
        }
コード例 #5
0
 /// <summary>
 /// Gets the display order for a project tree.
 /// </summary>
 public static int GetDisplayOrder(IProjectTree?projectTree)
 {
     if (projectTree is IProjectTree2 projectTree2)
     {
         return(projectTree2.DisplayOrder);
     }
     // It's safe to return zero here. Project trees that do not have a display order are always assumed zero.
     return(0);
 }
コード例 #6
0
        public override IProjectTree?FindByPath(IProjectTree root, string path)
        {
            // We are _usually_ passed the project root here, and we know that our tree items are limited to the
            // "Dependencies" subtree, so scope the search to that node.
            //
            // If we are passed a root which is not the project node, we will not find any search results.
            // This does not appear to be an issue, but may one day be required.
            IProjectTree?dependenciesRootNode = root.FindChildWithFlags(DependencyTreeFlags.DependenciesRootNode);

            return(dependenciesRootNode?.GetSelfAndDescendentsDepthFirst().FirstOrDefault((node, p) => StringComparers.Paths.Equals(node.FilePath, p), path));
        }
コード例 #7
0
        protected override async Task <IProjectTree?> FindFileAsync(IProjectTreeProvider provider, IProjectTree root)
        {
            // First look for the actual App.xaml first
            IProjectTree?node = FindAppXamlFile(root);

            if (node == null)
            {
                // Otherwise, find a candidate that we might be able to add to the project
                node = await base.FindFileAsync(provider, root);
            }

            return(node);
        }
コード例 #8
0
        private string?FindAppDesignerFolder()
        {
            IProjectTree?root = _projectTree.Value.CurrentTree;

            IProjectTree?folder = root?.GetSelfAndDescendentsBreadthFirst().FirstOrDefault(child => child.Flags.HasFlag(ProjectTreeFlags.Common.AppDesignerFolder));

            if (folder == null)
            {
                return(null);
            }

            return(_projectTree.Value.TreeProvider.GetRootedAddNewItemDirectory(folder));
        }
コード例 #9
0
        protected override Task <CommandStatusResult> GetCommandStatusAsync(IProjectTree node, bool focused, string?commandText, CommandStatus progressiveStatus)
        {
            IProjectTree?nodeToAddTo = GetNodeToAddTo(node);

            if (nodeToAddTo != null && _addItemDialogService.CanAddNewOrExistingItemTo(nodeToAddTo) && CanAdd(node))
            {
                return(GetCommandStatusResult.Handled(commandText, CommandStatus.Enabled));
            }
            else
            {
                return(GetCommandStatusResult.Unhandled);
            }
        }
コード例 #10
0
        protected override async Task <IProjectTree?> FindFileAsync(IProjectTreeProvider provider, IProjectTree root)
        {
            // First look for the actual AppDesigner folder
            IProjectTree?folder = FindAppDesignerFolder(root);

            if (folder == null)
            {
                // Otherwise, find a location that is a candidate
                folder = await FindAppDesignerFolderCandidateAsync(provider, root);
            }

            return(folder);
        }
コード例 #11
0
        private async Task <IProjectTree?> GetParentFolderAsync(bool createIfNotExists)
        {
            if (CreatedByDefaultUnderAppDesignerFolder)
            {
                IProjectTree?tree = await GetAppDesignerFolderAsync(createIfNotExists);

                if (tree != null)
                {
                    return(tree);
                }
            }

            return(_projectTree.CurrentTree);
        }
コード例 #12
0
        public IProjectTree?FindByPath(IProjectTree?root, string path)
        {
            if (root == null)
            {
                return(null);
            }

            IProjectTree?dependenciesNode = root.Flags.Contains(DependencyTreeFlags.DependenciesRootNodeFlags)
                ? root
                : root.GetSubTreeNode(DependencyTreeFlags.DependenciesRootNodeFlags);

            return(dependenciesNode?.GetSelfAndDescendentsBreadthFirst()
                   .FirstOrDefault((node, p) => string.Equals(node.FilePath, p, StringComparisons.Paths), path));
        }
        // TODO remove suppression once CPS annotation corrected
#pragma warning disable CS8613 // Nullability of reference types in return type doesn't match implicitly implemented member.
        public string?GetExtenderCATID(ExtenderCATIDType extenderCATIDType, IProjectTree?treeNode)
#pragma warning restore CS8613 // Nullability of reference types in return type doesn't match implicitly implemented member.
        {
            // CPS's implementation of ExtenderCATIDType incorrectly treats the same "instances" as distinct items based
            // where they are accessed in CPS. It also incorrectly maps "HierarchyExtensionObject" and "HierarchyBrowseObject"
            // as only applying to the hierarchy, when they take ITEMIDs indicating the node they apply to.
            //
            // See https://docs.microsoft.com/en-us/visualstudio/extensibility/internals/extending-the-object-model-of-the-base-project.
            //
            // The latter issue we can do nothing about, however, to address the former, map these types to a truer form it makes
            // it easier on implementors and maintainers of this to understand the objects we're talking about.

            switch (extenderCATIDType)
            {
            case ExtenderCATIDType.HierarchyExtensionObject:                                    // IVsHierarchy.GetProperty(VSITEMID.Root, VSHPROPID_ExtObjectCATID)
            case ExtenderCATIDType.AutomationProject:                                           // DTE.Project
                return(GetExtenderCATID(ExtendeeObject.Project));

            case ExtenderCATIDType.HierarchyBrowseObject:                                       // IVsHierarchy.GetProperty(VSHPROPID_BrowseObjectCATID)
            case ExtenderCATIDType.ProjectBrowseObject:                                         // EnvDTE.Project.Properties
                return(GetExtenderCATID(ExtendeeObject.ProjectBrowseObject));

            case ExtenderCATIDType.ConfigurationBrowseObject:                                   // IVsCfgProvider2.GetCfgProviderProperty(VSCFGPROPID_IntrinsicExtenderCATID)/DTE.Configuration
                return(GetExtenderCATID(ExtendeeObject.Configuration));

            case ExtenderCATIDType.HierarchyConfigurationBrowseObject:                          // IVsHierarchy.GetProperty(VSHPROPID_CfgBrowseObjectCATID)
            case ExtenderCATIDType.ProjectConfigurationBrowseObject:                            // EnvDTE.Configuration.Properties
                return(GetExtenderCATID(ExtendeeObject.ConfigurationBrowseObject));

            case ExtenderCATIDType.AutomationProjectItem:                                       // EnvDTE.ProjectItem
                return(GetExtenderCATID(ExtendeeObject.ProjectItem));

            case ExtenderCATIDType.AutomationReference:                                         // VSLangProject.Reference
            case ExtenderCATIDType.ReferenceBrowseObject:                                       // EnvDTE.ProjectItem.Properties (when reference)
                return(GetExtenderCATID(ExtendeeObject.ReferenceBrowseObject));

            case ExtenderCATIDType.FileBrowseObject:                                            // EnvDTE.ProjectItem.Properties (when file)
                return(GetExtenderCATID(ExtendeeObject.FileBrowseObject));

            case ExtenderCATIDType.AutomationFolderProperties:                                  // FolderProperties
            case ExtenderCATIDType.FolderBrowseObject:                                          // EnvDTE.ProjectItem.Properties (when folder)
                return(GetExtenderCATID(ExtendeeObject.FolderBrowseObject));

            default:
            case ExtenderCATIDType.Unknown:                                                     // EnvDTE.ProjectItem.Properties (when not file, folder, reference)
                BCLDebug.Assert(extenderCATIDType == ExtenderCATIDType.Unknown, $"Unrecognized CATID type {extenderCATIDType}");
                return(null);
            }
        }
コード例 #14
0
        /// <summary>
        /// Efficiently finds a descendent with the given path in the given tree.
        /// </summary>
        /// <param name="root">The root of the tree.</param>
        /// <param name="path">The absolute or project-relative path to the item sought.</param>
        /// <returns>The item in the tree if found; otherwise <c>null</c>.</returns>
        public override IProjectTree?FindByPath(IProjectTree root, string path)
        {
            // We override this since we need to find children under either:
            //
            // - our dependencies root node
            // - dependency sub tree nodes
            // - dependency sub tree top level nodes
            //
            // Deeper levels will be attached items with additional info, not direct dependencies
            // specified in the project file.

            IProjectTree?projectTree = _viewProviders.FirstOrDefault()?.Value.FindByPath(root, path);

            return(projectTree);
        }
コード例 #15
0
        /// <summary>
        /// When the task runs, if the receiver picks up that we will be adding an item, it will capture the MSBuild project's includes.
        /// If any items were added as a result of the task running, the hint receiver will perform the specified action on those items.
        /// </summary>
        public async Task Capture(OrderingMoveAction action, IProjectTree target, Func <Task> task)
        {
            Requires.NotNull(target, nameof(target));
            Requires.NotNull(task, nameof(task));

            _action = action;
            _target = target;
            await task();

            // We need to be sure we are not hinting before we reset, otherwise everything would get reset before HintedAsync gets called.
            // This is for sanity.
            if (!_isHinting)
            {
                Reset();
            }
        }
コード例 #16
0
        protected override async Task <bool> TryHandleCommandAsync(IProjectTree node, bool focused, long commandExecuteOptions, IntPtr variantArgIn, IntPtr variantArgOut)
        {
            IProjectTree?nodeToAddTo = GetNodeToAddTo(node);

            if (nodeToAddTo == null)
            {
                return(false);
            }

            // We use a hint receiver that listens for when a file gets added.
            // The reason is so we can modify the MSBuild project inside the same write lock of when a file gets added internally in CPS.
            // This ensures that we only perform actions on the items that were added as result of a e.g. a add new/existing item dialog.
            await _orderAddItemHintReceiver.Capture(Action, node, () => OnAddingNodesAsync(nodeToAddTo));

            return(true);
        }
コード例 #17
0
        public void Search(IRelationshipSearchParameters parameters, Action <ISearchResult> resultAccumulator)
        {
            Requires.NotNull(parameters, nameof(parameters));
            Requires.NotNull(resultAccumulator, nameof(resultAccumulator));

            if (_providers.Length == 0)
            {
                // No providers registered
                return;
            }

            if (!parameters.Options.SearchExternalItems)
            {
                // Consider the dependencies tree as containing 'external items', allowing the
                // tree to be excluded from search results via this option.
                return;
            }

            using var context = new DependenciesTreeSearchContext(parameters, resultAccumulator);

            _joinableTaskContext.Factory.Run(SearchSolutionAsync);

            Task SearchSolutionAsync()
            {
                // Search projects concurrently
                return(Task.WhenAll(_projectServiceAccessor.GetProjectService().LoadedUnconfiguredProjects.Select(SearchProjectAsync)));
            }

            async Task SearchProjectAsync(UnconfiguredProject unconfiguredProject)
            {
                IUnconfiguredProjectVsServices?  projectVsServices         = unconfiguredProject.Services.ExportProvider.GetExportedValue <IUnconfiguredProjectVsServices>();
                IActiveConfigurationGroupService?configurationGroupService = unconfiguredProject.Services.ExportProvider.GetExportedValue <IActiveConfigurationGroupService>();
                IProjectTree?dependenciesNode = projectVsServices?.ProjectTree.CurrentTree?.FindChildWithFlags(DependencyTreeFlags.DependenciesRootNode);

                if (projectVsServices != null &&
                    dependenciesNode != null &&
                    configurationGroupService is IActiveConfigurationGroupService2 activeConfigurationGroupService)
                {
                    IConfigurationGroup <ConfiguredProject> configuredProjects = await activeConfigurationGroupService.GetActiveLoadedConfiguredProjectGroupAsync();

                    var projectContext = new DependenciesTreeProjectSearchContext(context, unconfiguredProject, dependenciesNode, _hierarchyItemManager, projectVsServices, _relationProvider);

                    // Search providers concurrently
                    await Task.WhenAll(_providers.Select(provider => provider.SearchAsync(projectContext)));
                }
            }
        }
コード例 #18
0
        public string?GetExtenderCATID(ExtenderCATIDType extenderCATIDType, IProjectTree?treeNode)
        {
            // CPS's implementation of ExtenderCATIDType incorrectly treats the same "instances" as distinct items based
            // where they are accessed in CPS. It also incorrectly maps "HierarchyExtensionObject" and "HierarchyBrowseObject"
            // as only applying to the hierarchy, when they take ITEMIDs indicating the node they apply to.
            //
            // See https://docs.microsoft.com/en-us/visualstudio/extensibility/internals/extending-the-object-model-of-the-base-project.
            //
            // The latter issue we can do nothing about, however, to address the former, map these types to a truer form it makes
            // it easier on implementors and maintainers of this to understand the objects we're talking about.

            return(extenderCATIDType switch
            {
                ExtenderCATIDType.HierarchyExtensionObject or                       // IVsHierarchy.GetProperty(VSITEMID.Root, VSHPROPID_ExtObjectCATID)
                ExtenderCATIDType.AutomationProject =>                              // DTE.Project
                GetExtenderCATID(ExtendeeObject.Project),

                ExtenderCATIDType.HierarchyBrowseObject or                          // IVsHierarchy.GetProperty(VSHPROPID_BrowseObjectCATID)
                ExtenderCATIDType.ProjectBrowseObject =>                            // EnvDTE.Project.Properties
                GetExtenderCATID(ExtendeeObject.ProjectBrowseObject),

                ExtenderCATIDType.ConfigurationBrowseObject =>                      // IVsCfgProvider2.GetCfgProviderProperty(VSCFGPROPID_IntrinsicExtenderCATID)/DTE.Configuration
                GetExtenderCATID(ExtendeeObject.Configuration),

                ExtenderCATIDType.HierarchyConfigurationBrowseObject or             // IVsHierarchy.GetProperty(VSHPROPID_CfgBrowseObjectCATID)
                ExtenderCATIDType.ProjectConfigurationBrowseObject =>               // EnvDTE.Configuration.Properties
                GetExtenderCATID(ExtendeeObject.ConfigurationBrowseObject),

                ExtenderCATIDType.AutomationProjectItem =>                          // EnvDTE.ProjectItem
                GetExtenderCATID(ExtendeeObject.ProjectItem),

                ExtenderCATIDType.AutomationReference or                            // VSLangProject.Reference
                ExtenderCATIDType.ReferenceBrowseObject =>                          // EnvDTE.ProjectItem.Properties (when reference)
                GetExtenderCATID(ExtendeeObject.ReferenceBrowseObject),

                ExtenderCATIDType.FileBrowseObject =>                               // EnvDTE.ProjectItem.Properties (when file)
                GetExtenderCATID(ExtendeeObject.FileBrowseObject),

                ExtenderCATIDType.AutomationFolderProperties or                     // FolderProperties
                ExtenderCATIDType.FolderBrowseObject =>                             // EnvDTE.ProjectItem.Properties (when folder)
                GetExtenderCATID(ExtendeeObject.FolderBrowseObject),

                ExtenderCATIDType.Unknown or _ =>                                   // EnvDTE.ProjectItem.Properties (when not file, folder, reference)
                UnknownOrDefault()
            });
コード例 #19
0
        /// <summary>
        /// Builds a sub tree under root: target framework or Dependencies node when there is only one target.
        /// </summary>
        private async Task <IProjectTree> BuildSubTreeAsync(
            IProjectTree rootNode,
            TargetedDependenciesSnapshot targetedSnapshot,
            List <IDependency> dependencies,
            bool isActiveTarget,
            bool shouldCleanup)
        {
            HashSet <IProjectTree>?currentNodes = shouldCleanup
                ? new HashSet <IProjectTree>(capacity: dependencies.Count)
                : null;

            foreach (IDependency dependency in dependencies)
            {
                IProjectTree?dependencyNode      = rootNode.FindChildWithCaption(dependency.Caption);
                bool         isNewDependencyNode = dependencyNode == null;

                // NOTE this project system supports multiple implicit configuration dimensions (such as target framework)
                // which is a concept not modelled by DTE/VSLangProj. In order to produce a sensible view of the project
                // via automation, we expose only the active target framework at any given time.
                //
                // This is achieved by using IProjectItemTree for active target framework items, and IProjectTree for inactive
                // target frameworks. CPS only creates automation objects for items with "Reference" flag if they implement
                // IProjectItemTree. See SimpleItemNode.Initialize (in CPS) for details.

                dependencyNode = await CreateOrUpdateNodeAsync(
                    dependencyNode,
                    dependency,
                    targetedSnapshot,
                    isProjectItem : isActiveTarget);

                currentNodes?.Add(dependencyNode);

                IProjectTree?parent = isNewDependencyNode
                    ? rootNode.Add(dependencyNode).Parent
                    : dependencyNode.Parent;

                Assumes.NotNull(parent);

                rootNode = parent;
            }

            return(currentNodes != null // shouldCleanup
                ? CleanupOldNodes(rootNode, currentNodes)
                : rootNode);
        }
        protected override async Task <IProjectTree?> FindFileAsync(IProjectTreeProvider provider, IProjectTree root)
        {
            // Search AppDesigner folder first if it exists
            IProjectTree?appDesignerFolder = await GetAppDesignerFolderAsync(provider, root);

            if (appDesignerFolder != null)
            {
                IProjectTree?node = await base.FindFileAsync(provider, appDesignerFolder);

                if (node != null)
                {
                    return(node);
                }
            }

            // Then fallback to project root
            return(await base.FindFileAsync(provider, root));
        }
コード例 #21
0
        private async Task <IProjectTree> BuildSubTreeAsync(
            IProjectTree rootNode,
            ITargetedDependenciesSnapshot targetedSnapshot,
            List <IDependency> dependencies,
            bool isActiveTarget,
            bool shouldCleanup)
        {
            List <IProjectTree>?currentNodes = shouldCleanup
                ? new List <IProjectTree>(capacity: dependencies.Count)
                : null;

            foreach (IDependency dependency in dependencies)
            {
                IProjectTree?dependencyNode      = rootNode.FindChildWithCaption(dependency.Caption);
                bool         isNewDependencyNode = dependencyNode == null;

                if (dependencyNode != null &&
                    dependency.Flags.Contains(DependencyTreeFlags.SupportsHierarchy))
                {
                    if ((dependency.Resolved && dependencyNode.Flags.Contains(DependencyTreeFlags.UnresolvedFlags)) ||
                        (!dependency.Resolved && dependencyNode.Flags.Contains(DependencyTreeFlags.ResolvedFlags)))
                    {
                        // when transition from unresolved to resolved or vise versa - remove old node
                        // and re-add new  one to allow GraphProvider to recalculate children
                        isNewDependencyNode = true;
                        rootNode            = dependencyNode.Remove();
                        dependencyNode      = null;
                    }
                }

                dependencyNode = await CreateOrUpdateNodeAsync(dependencyNode, dependency, targetedSnapshot, isActiveTarget);

                currentNodes?.Add(dependencyNode);

                rootNode = isNewDependencyNode
                    ? rootNode.Add(dependencyNode).Parent
                    : dependencyNode.Parent;
            }

            return(currentNodes != null // shouldCleanup
                ? CleanupOldNodes(rootNode, currentNodes)
                : rootNode);
        }
コード例 #22
0
        private async Task <string?> FindFileAsync(IProjectTreeProvider provider, IProjectTree root, SpecialFileFlags flags)
        {
            IProjectTree?node = await FindFileAsync(provider, root);

            if (node == null)
            {
                return(null);
            }

            string?path = GetFilePath(provider, node);

            if (path != null && flags.HasFlag(SpecialFileFlags.CreateIfNotExist))
            {
                // Similar to legacy, we only verify state if we've been asked to create it
                await VerifyStateAsync(node, path);
            }

            return(path);
        }
コード例 #23
0
        private async Task <string?> GetDefaultAppDesignerFolderPathAsync()
        {
            IProjectTree?currentTree = _projectTree.Value.CurrentTree;

            if (currentTree == null)
            {
                return(null);
            }

            string?rootPath = _projectTree.Value.TreeProvider.GetRootedAddNewItemDirectory(currentTree);

            string folderName = await GetDefaultAppDesignerFolderNameAsync();

            if (string.IsNullOrEmpty(folderName))
            {
                return(null); // Developer has set the AppDesigner path to empty
            }
            return(Path.Combine(rootPath, folderName));
        }
コード例 #24
0
        private async Task <IProjectTree> CreateOrUpdateNodeAsync(
            IProjectTree?node,
            IDependency dependency,
            TargetedDependenciesSnapshot targetedSnapshot,
            bool isProjectItem,
            ProjectTreeFlags?additionalFlags = null,
            ProjectTreeFlags?excludedFlags   = null)
        {
            IRule?browseObjectProperties = dependency.Flags.Contains(DependencyTreeFlags.SupportsRuleProperties)
                ? await _treeServices.GetBrowseObjectRuleAsync(dependency, targetedSnapshot.Catalogs)
                : null;

            return(CreateOrUpdateNode(
                       node,
                       dependency.ToViewModel(targetedSnapshot),
                       browseObjectProperties,
                       isProjectItem,
                       additionalFlags,
                       excludedFlags));
        }
コード例 #25
0
        public static IProjectTreeService Create(IProjectTree?tree = null, IProjectTreeProvider?treeProvider = null)
        {
            var mock = new Mock <IProjectTreeService>();

            var treeState = IProjectTreeServiceStateFactory.ImplementTree(() => tree, () => treeProvider ?? IProjectTreeProviderFactory.Create());

            mock.Setup(s => s.PublishAnyNonLoadingTreeAsync(It.IsAny <CancellationToken>()))
            .ReturnsAsync(treeState);

            mock.Setup(s => s.PublishAnyNonNullTreeAsync(It.IsAny <CancellationToken>()))
            .ReturnsAsync(treeState);

            mock.Setup(s => s.PublishLatestTreeAsync(It.IsAny <bool>(), It.IsAny <bool>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(treeState);

            mock.SetupGet(s => s.CurrentTree)
            .Returns(treeState);

            return(mock.Object);
        }
コード例 #26
0
        public async Task <IDependenciesTreeConfiguredProjectSearchContext?> ForConfiguredProjectAsync(ConfiguredProject configuredProject, CancellationToken cancellationToken = default)
        {
            Requires.NotNull(configuredProject, nameof(configuredProject));

            IProjectTree targetRootNode;

            if (_dependenciesNode.FindChildWithFlags(DependencyTreeFlags.TargetNode) == null)
            {
                // Tree does not show any target nodes
                targetRootNode = _dependenciesNode;
            }
            else
            {
                if (configuredProject.Services.ProjectSubscription == null)
                {
                    return(null);
                }

                IProjectSubscriptionUpdate subscriptionUpdate = (await configuredProject.Services.ProjectSubscription.ProjectRuleSource.GetLatestVersionAsync(configuredProject, cancellationToken: cancellationToken)).Value;

                if (!subscriptionUpdate.CurrentState.TryGetValue(ConfigurationGeneral.SchemaName, out IProjectRuleSnapshot configurationGeneralSnapshot) ||
                    !configurationGeneralSnapshot.Properties.TryGetValue(ConfigurationGeneral.TargetFrameworkProperty, out string tf))
                {
                    return(null);
                }

                IProjectTree?targetNode = _dependenciesNode.FindChildWithFlags(ProjectTreeFlags.Create("$TFM:" + tf));

                if (targetNode == null)
                {
                    TraceUtilities.TraceError("Should not fail to find the target node.");
                    return(null);
                }

                targetRootNode = targetNode;
            }

            return(new DependenciesTreeConfiguredProjectSearchContext(_inner, targetRootNode, _hierarchyItemManager, _projectVsServices, _relationProvider));
        }
コード例 #27
0
        /// <summary>
        /// Gets a sibling based on the given project tree. Can return null.
        /// </summary>
        /// <param name="projectTree">the given project tree</param>
        /// <param name="returnSibling">passes the index of the given project tree from the given ordered sequence, expecting to return a sibling</param>
        /// <returns>a sibling</returns>
        private static IProjectTree2?GetSiblingByDisplayOrder(IProjectTree projectTree, Func <int, ImmutableArray <IProjectTree>, IProjectTree2?> returnSibling)
        {
            IProjectTree?parent       = projectTree.Parent;
            int          displayOrder = GetDisplayOrder(projectTree);

            if (!IsValidDisplayOrder(displayOrder) || parent == null)
            {
                return(null);
            }

            ImmutableArray <IProjectTree> orderedChildren = GetChildren(parent);

            for (int i = 0; i < orderedChildren.Length; ++i)
            {
                IProjectTree sibling = orderedChildren[i];
                if (GetDisplayOrder(sibling) == displayOrder)
                {
                    return(returnSibling(i, orderedChildren));
                }
            }

            return(null);
        }
コード例 #28
0
        /// <summary>
        /// We follow this algorithm for looking up files:
        ///
        /// if (not asked to create)
        ///      Look in AppDesigner folder
        ///      Look in root folder
        ///
        /// if (asked to create)
        ///      Look in AppDesigner folder
        ///      Look in root folder
        ///      Force-create in app-designer folder unless that file is not created there by default.
        ///      In that case create under the root node.
        /// </summary>
        public async Task <string?> GetFileAsync(SpecialFiles fileId, SpecialFileFlags flags, CancellationToken cancellationToken = default)
        {
            // Search for the file in the app designer and root folders.
            IProjectTree?specialFileNode = await FindFileAsync(Name);

            if (specialFileNode != null)
            {
                if (await IsNodeInSyncWithDiskAsync(specialFileNode, forceSync: flags.HasFlag(SpecialFileFlags.CreateIfNotExist), cancellationToken))
                {
                    return(specialFileNode.FilePath);
                }
            }

            // File doesn't exist. Create it if we've been asked to.
            if (flags.HasFlag(SpecialFileFlags.CreateIfNotExist))
            {
                string createdFilePath = await CreateFileAsync(Name);

                if (createdFilePath != null)
                {
                    return(createdFilePath);
                }
            }

            // We haven't found the file but return the default file path as that's the contract.
            IProjectTree?rootNode = _projectTree.CurrentTree;

            if (rootNode == null)
            {
                return(null);
            }

            string rootFilePath = _projectTree.TreeProvider.GetPath(rootNode);
            string fullPath     = Path.Combine(Path.GetDirectoryName(rootFilePath), Name);

            return(fullPath);
        }
コード例 #29
0
        /// <summary>
        /// Move the respective item elements to the top of the target's children.
        /// </summary>
        public static bool TryMoveElementsToTop(Project project, ImmutableArray <ProjectItemElement> elements, IProjectTree target)
        {
            Requires.NotNull(project, nameof(project));
            Requires.NotNull(target, nameof(target));

            IProjectTree?newTarget = target;

            // This is to handle adding files to empty folders since empty folders do not have a valid display order yet.
            // We need to find a target up the tree that has a valid display order, because it most likely will have our reference element that we want.
            while (!HasValidDisplayOrder(newTarget) && !newTarget !.Flags.Contains(ProjectTreeFlags.ProjectRoot))
            {
                newTarget = newTarget.Parent;
            }

            var excludeIncludes = elements.Select(x => x.Include).ToImmutableArray();
            ProjectItemElement?referenceElement = GetChildren(newTarget !).Select(x => TryGetReferenceElement(project, x, excludeIncludes, MoveAction.Above)).FirstOrDefault(x => x != null);

            if (referenceElement == null)
            {
                return(false);
            }

            return(TryMoveElements(elements, referenceElement, MoveAction.Above));
        }
コード例 #30
0
 public bool CanCopy(IImmutableSet <IProjectTree> nodes, IProjectTree?receiver, bool deleteOriginal = false)
 {
     throw new NotImplementedException();
 }