public bool PasteInto(ModelEntity targetEntity)
 {
     return(SourceEntity
            .Select(source =>
                    CopiedTagNames.All(tagName => targetEntity.InsertTaggedValueFrom(source, tagName)))
            .GetOrElse(false));
 }
        /// <summary>
        /// Ensures that <see cref="_currentAggregateProjectContext"/> is updated for the latest TargetFrameworks from the project properties
        /// and returns this value.
        /// </summary>
        private Task <AggregateCrossTargetProjectContext> UpdateProjectContextAsync()
        {
            // Ensure that only single thread is attempting to create a project context.
            AggregateCrossTargetProjectContext previousContextToDispose = null;

            return(ExecuteWithinLockAsync(async() =>
            {
                // Check if we have already computed the project context.
                if (_currentAggregateProjectContext != null)
                {
                    // For non-cross targeting projects, we can use the current project context if the TargetFramework hasn't changed.
                    // For cross-targeting projects, we need to verify that the current project context matches latest frameworks targeted by the project.
                    // If not, we create a new one and dispose the current one.
                    ConfigurationGeneral projectProperties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync().ConfigureAwait(false);

                    if (!_currentAggregateProjectContext.IsCrossTargeting)
                    {
                        ITargetFramework newTargetFramework = _targetFrameworkProvider.GetTargetFramework((string)await projectProperties.TargetFramework.GetValueAsync().ConfigureAwait(false));
                        if (_currentAggregateProjectContext.ActiveProjectContext.TargetFramework.Equals(newTargetFramework))
                        {
                            return _currentAggregateProjectContext;
                        }
                    }
                    else
                    {
                        string targetFrameworks = (string)await projectProperties.TargetFrameworks.GetValueAsync().ConfigureAwait(false);

                        // Check if the current project context is up-to-date for the current active and known project configurations.
                        ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration;
                        IImmutableSet <ProjectConfiguration> knownProjectConfigurations = await _commonServices.Project.Services.ProjectConfigurationsService.GetKnownProjectConfigurationsAsync().ConfigureAwait(false);
                        if (knownProjectConfigurations.All(c => c.IsCrossTargeting()) &&
                            _currentAggregateProjectContext.HasMatchingTargetFrameworks(activeProjectConfiguration, knownProjectConfigurations))
                        {
                            return _currentAggregateProjectContext;
                        }
                    }

                    previousContextToDispose = _currentAggregateProjectContext;
                }

                // Force refresh the CPS active project configuration (needs UI thread).
                await _commonServices.ThreadingService.SwitchToUIThread();
                await _activeProjectConfigurationRefreshService.RefreshActiveProjectConfigurationAsync().ConfigureAwait(false);

                // Dispose the old project context, if one exists.
                if (previousContextToDispose != null)
                {
                    await DisposeAggregateProjectContextAsync(previousContextToDispose).ConfigureAwait(false);
                }

                // Create new project context.
                _currentAggregateProjectContext = await _contextProvider.Value.CreateProjectContextAsync().ConfigureAwait(false);

                OnAggregateContextChanged(previousContextToDispose, _currentAggregateProjectContext);

                return _currentAggregateProjectContext;
            }));
        }
        public Task <CommandStatusResult> GetCommandStatusAsync(IImmutableSet <IProjectTree> items, long commandId, bool focused, string?commandText, CommandStatus progressiveStatus)
        {
            if (IsOpenCommand(commandId) && items.All(CanOpenFile))
            {
                progressiveStatus |= CommandStatus.Enabled | CommandStatus.Supported;
                return(new CommandStatusResult(true, commandText, progressiveStatus).AsTask());
            }

            return(CommandStatusResult.Unhandled.AsTask());
        }
Example #4
0
        protected override Task <CommandStatusResult> GetCommandStatusAsync(IImmutableSet <IProjectTree> nodes, bool focused, string?commandText, CommandStatus progressiveStatus)
        {
            // Only handle when Solution Explorer has focus so that we don't take over Tab Well handling
            if (focused && nodes.All(CanOpen))
            {
                return(GetCommandStatusResult.Handled(commandText, progressiveStatus | CommandStatus.Enabled));
            }

            return(GetCommandStatusResult.Unhandled);
        }
Example #5
0
        /// <summary>
        /// Gets a value indicating whether deleting a given set of items from the project, and optionally from disk,
        /// would be allowed.
        /// Note: CanRemove can be called several times since there two types of remove operations:
        ///   - Remove is a command that can remove project tree items form the tree/project but not from disk.
        ///     For that command requests deleteOptions has DeleteOptions.None flag.
        ///   - Delete is a command that can remove project tree items and form project and from disk.
        ///     For this command requests deleteOptions has DeleteOptions.DeleteFromStorage flag.
        /// We can potentially support only Remove command here, since we don't remove Dependencies form disk,
        /// thus we return false when DeleteOptions.DeleteFromStorage is provided.
        /// </summary>
        /// <param name="nodes">The nodes that should be deleted.</param>
        /// <param name="deleteOptions">
        /// A value indicating whether the items should be deleted from disk as well as from the project file.
        /// </param>
        public override bool CanRemove(IImmutableSet <IProjectTree> nodes,
                                       DeleteOptions deleteOptions = DeleteOptions.None)
        {
            if (deleteOptions.HasFlag(DeleteOptions.DeleteFromStorage))
            {
                return(false);
            }

            return(nodes.All(node => node.Flags.Contains(DependencyTreeFlags.SupportsRemove)));
        }
        public override bool CanRemove(IImmutableSet <IProjectTree> nodes, DeleteOptions deleteOptions = DeleteOptions.None)
        {
            if (deleteOptions.HasFlag(DeleteOptions.DeleteFromStorage))
            {
                // We support "Remove" but not "Delete".
                // We remove the dependency from the project, not delete it from disk.
                return(false);
            }

            return(nodes.All(node => node.Flags.Contains(DependencyTreeFlags.SupportsRemove)));
        }
        /// <summary>
        /// Gets a value indicating whether deleting a given set of items from the project, and optionally from disk,
        /// would be allowed.
        /// Note: CanRemove can be called several times since there two types of remove operations:
        ///   - Remove is a command that can remove project tree items form the tree/project but not from disk.
        ///     For that command requests deleteOptions has DeleteOptions.None flag.
        ///   - Delete is a command that can remove project tree items and form project and from disk.
        ///     For this command requests deleteOptions has DeleteOptions.DeleteFromStorage flag.
        /// We can potentially support only Remove command here, since we don't remove Dependencies form disk,
        /// thus we return false when DeleteOptions.DeleteFromStorage is provided.
        /// </summary>
        /// <param name="nodes">The nodes that should be deleted.</param>
        /// <param name="deleteOptions">
        /// A value indicating whether the items should be deleted from disk as well as from the project file.
        /// </param>
        public override bool CanRemove(IImmutableSet <IProjectTree> nodes,
                                       DeleteOptions deleteOptions = DeleteOptions.None)
        {
            if (deleteOptions.HasFlag(DeleteOptions.DeleteFromStorage))
            {
                return(false);
            }

            return(nodes.All(node => (node.Flags.Contains(DependencyNode.GenericDependencyFlags) &&
                                      node.BrowseObjectProperties != null &&
                                      !node.Flags.Contains(DependencyNode.DoesNotSupportRemove))));
        }
Example #8
0
        protected override async Task <bool> TryHandleCommandAsync(IImmutableSet <IProjectTree> nodes, bool focused, long commandExecuteOptions, IntPtr variantArgIn, IntPtr variantArgOut)
        {
            // Only handle when Solution Explorer has focus so that we don't take over Tab Well handling
            if (focused && nodes.All(CanOpen))
            {
                foreach (IProjectTree node in nodes)
                {
                    string?path = await DependencyServices.GetBrowsePathAsync(_project, node);

                    if (path == null)
                    {
                        continue;
                    }

                    Open(path);
                }

                return(true);
            }

            return(false);
        }
        public Task <bool> TryHandleCommandAsync(IImmutableSet <IProjectTree> items, long commandId, bool focused, long commandExecuteOptions, IntPtr variantArgIn, IntPtr variantArgOut)
        {
            if (IsOpenCommand(commandId) && items.All(CanOpenFile))
            {
                OpenItems();

                return(TaskResult.True);
            }

            return(TaskResult.False);

            void OpenItems()
            {
                Assumes.NotNull(_configuredProject.UnconfiguredProject.Services.HostObject);
                var hierarchy = (IVsUIHierarchy)_configuredProject.UnconfiguredProject.Services.HostObject;
                var rdt       = new RunningDocumentTable(_serviceProvider);

                // Open all items.
                RunAllAndAggregateExceptions(items, OpenItem);

                void OpenItem(IProjectTree item)
                {
                    IVsWindowFrame?windowFrame = null;

                    try
                    {
                        // Open the document.
                        Guid   logicalView = IsOpenWithCommand(commandId) ? LOGVIEWID_UserChooseView : LOGVIEWID.Primary_guid;
                        IntPtr docData     = IntPtr.Zero;

                        ErrorHandler.ThrowOnFailure(
                            _uiShellOpenDocument.Value.OpenStandardEditor(
                                (uint)__VSOSEFLAGS.OSE_ChooseBestStdEditor,
                                item.FilePath,
                                ref logicalView,
                                item.Caption,
                                hierarchy,
                                item.GetHierarchyId(),
                                docData,
                                _oleServiceProvider.Value,
                                out windowFrame));

                        RunningDocumentInfo rdtInfo = rdt.GetDocumentInfo(item.FilePath);

                        // Set it as read only if necessary.
                        bool isReadOnly = item.Flags.Contains(ImportTreeProvider.ProjectImportImplicit);

                        if (isReadOnly && rdtInfo.DocData is IVsTextBuffer textBuffer)
                        {
                            textBuffer.GetStateFlags(out uint flags);
                            textBuffer.SetStateFlags(flags | (uint)BUFFERSTATEFLAGS.BSF_USER_READONLY);
                        }

                        // Detach the document from this project.
                        // Ignore failure. It may be that we've already transferred the item to Miscellaneous Files.
                        _externalFilesManager.Value.TransferDocument(item.FilePath, item.FilePath, windowFrame);

                        // Show the document window
                        if (windowFrame != null)
                        {
                            ErrorHandler.ThrowOnFailure(windowFrame.Show());
                        }
                    }
                    catch
                    {
                        windowFrame?.CloseFrame(0);
                        throw;
                    }
                }
            }
        }
Example #10
0
        /// <summary>
        /// Determines whether the current project context object is out of date based on the project's target frameworks.
        /// If so, a new one is created and subscriptions are updated accordingly.
        /// </summary>
        private async Task UpdateProjectContextAndSubscriptionsAsync()
        {
            // Ensure that only single thread is attempting to create a project context.
            AggregateCrossTargetProjectContext newProjectContext = await ExecuteWithinLockAsync(TryUpdateCurrentAggregateProjectContextAsync);

            if (newProjectContext != null)
            {
                // Dispose existing subscriptions.
                DisposeAndClearSubscriptions();

                // Add subscriptions for the configured projects in the new project context.
                await AddSubscriptionsAsync(newProjectContext);
            }

            return;

            async Task <AggregateCrossTargetProjectContext> TryUpdateCurrentAggregateProjectContextAsync()
            {
                AggregateCrossTargetProjectContext previousContext = _currentAggregateProjectContext;

                // Check if we have already computed the project context.
                if (previousContext != null)
                {
                    // For non-cross targeting projects, we can use the current project context if the TargetFramework hasn't changed.
                    // For cross-targeting projects, we need to verify that the current project context matches latest frameworks targeted by the project.
                    // If not, we create a new one and dispose the current one.
                    ConfigurationGeneral projectProperties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync();

                    if (!previousContext.IsCrossTargeting)
                    {
                        string newTargetFrameworkName = (string)await projectProperties.TargetFramework.GetValueAsync();

                        ITargetFramework newTargetFramework = _targetFrameworkProvider.GetTargetFramework(newTargetFrameworkName);
                        if (previousContext.ActiveTargetFramework.Equals(newTargetFramework))
                        {
                            // No change
                            return(null);
                        }
                    }
                    else
                    {
                        // Check if the current project context is up-to-date for the current active and known project configurations.
                        ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration;
                        IImmutableSet <ProjectConfiguration> knownProjectConfigurations = await _commonServices.Project.Services.ProjectConfigurationsService.GetKnownProjectConfigurationsAsync();

                        if (knownProjectConfigurations.All(c => c.IsCrossTargeting()) &&
                            HasMatchingTargetFrameworks(previousContext, activeProjectConfiguration, knownProjectConfigurations))
                        {
                            // No change
                            return(null);
                        }
                    }
                }

                // Force refresh the CPS active project configuration (needs UI thread).
                await _commonServices.ThreadingService.SwitchToUIThread();

                await _activeProjectConfigurationRefreshService.RefreshActiveProjectConfigurationAsync();

                // Create new project context.
                AggregateCrossTargetProjectContext newContext = await _contextProvider.Value.CreateProjectContextAsync();

                _currentAggregateProjectContext = newContext;

                OnAggregateContextChanged(previousContext, newContext);

                return(newContext);
            }

            bool HasMatchingTargetFrameworks(
                AggregateCrossTargetProjectContext previousContext,
                ProjectConfiguration activeProjectConfiguration,
                IReadOnlyCollection <ProjectConfiguration> knownProjectConfigurations)
            {
                Assumes.True(activeProjectConfiguration.IsCrossTargeting());

                ITargetFramework activeTargetFramework = _targetFrameworkProvider.GetTargetFramework(activeProjectConfiguration.Dimensions[ConfigurationGeneral.TargetFrameworkProperty]);

                if (!previousContext.ActiveTargetFramework.Equals(activeTargetFramework))
                {
                    // Active target framework is different.
                    return(false);
                }

                var targetFrameworkMonikers = knownProjectConfigurations
                                              .Select(c => c.Dimensions[ConfigurationGeneral.TargetFrameworkProperty])
                                              .Distinct()
                                              .ToList();

                if (targetFrameworkMonikers.Count != previousContext.TargetFrameworks.Length)
                {
                    // Different number of target frameworks.
                    return(false);
                }

                foreach (string targetFrameworkMoniker in targetFrameworkMonikers)
                {
                    ITargetFramework targetFramework = _targetFrameworkProvider.GetTargetFramework(targetFrameworkMoniker);

                    if (!previousContext.TargetFrameworks.Contains(targetFramework))
                    {
                        // Differing TargetFramework
                        return(false);
                    }
                }

                return(true);
            }

            void OnAggregateContextChanged(
                AggregateCrossTargetProjectContext oldContext,
                AggregateCrossTargetProjectContext newContext)
            {
                if (oldContext == null)
                {
                    // all new rules will be sent to new context, we don't need to clean up anything
                    return;
                }

                var targetsToClean = new HashSet <ITargetFramework>();

                ImmutableArray <ITargetFramework> oldTargets = oldContext.TargetFrameworks;

                if (newContext == null)
                {
                    targetsToClean.AddRange(oldTargets);
                }
                else
                {
                    ImmutableArray <ITargetFramework> newTargets = newContext.TargetFrameworks;

                    targetsToClean.AddRange(oldTargets.Except(newTargets));
                }

                if (targetsToClean.Count != 0)
                {
                    TryUpdateSnapshot(snapshot => snapshot.RemoveTargets(targetsToClean));
                }
            }
        }
            public async Task <AggregateCrossTargetProjectContext?> TryUpdateCurrentAggregateProjectContextAsync()
            {
                AggregateCrossTargetProjectContext?previousContext = Current;

                // Check if we have already computed the project context.
                if (previousContext != null)
                {
                    // For non-cross targeting projects, we can use the current project context if the TargetFramework hasn't changed.
                    // For cross-targeting projects, we need to verify that the current project context matches latest frameworks targeted by the project.
                    // If not, we create a new one and dispose the current one.
                    ConfigurationGeneral projectProperties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync();

                    if (!previousContext.IsCrossTargeting)
                    {
                        string?newTargetFrameworkName = (string?)await projectProperties.TargetFrameworkMoniker.GetValueAsync();

                        if (string.IsNullOrEmpty(newTargetFrameworkName) && TargetFramework.Empty.Equals(previousContext.ActiveTargetFramework))
                        {
                            // No change
                            return(null);
                        }

                        TargetFramework?newTargetFramework = _targetFrameworkProvider.GetTargetFramework(newTargetFrameworkName);
                        if (previousContext.ActiveTargetFramework.Equals(newTargetFramework))
                        {
                            // No change
                            return(null);
                        }
                    }
                    else
                    {
                        // Check if the current project context is up-to-date for the current active and known project configurations.
                        Assumes.Present(_commonServices.Project.Services.ProjectConfigurationsService);
                        ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration;
                        IImmutableSet <ProjectConfiguration> knownProjectConfigurations = await _commonServices.Project.Services.ProjectConfigurationsService.GetKnownProjectConfigurationsAsync();

                        if (knownProjectConfigurations.All(c => c.IsCrossTargeting()) &&
                            HasMatchingTargetFrameworks(activeProjectConfiguration, knownProjectConfigurations))
                        {
                            // No change
                            return(null);
                        }
                    }
                }

                // Force refresh the CPS active project configuration (needs UI thread).
                await _commonServices.ThreadingService.SwitchToUIThread();

                await _activeProjectConfigurationRefreshService.RefreshActiveProjectConfigurationAsync();

                // Create new project context.
                AggregateCrossTargetProjectContext newContext = await _contextProvider.Value.CreateProjectContextAsync();

                Current = newContext;

                return(newContext);

                bool HasMatchingTargetFrameworks(
                    ProjectConfiguration activeProjectConfiguration,
                    IReadOnlyCollection <ProjectConfiguration> knownProjectConfigurations)
                {
                    Assumes.NotNull(previousContext);
                    Assumes.True(activeProjectConfiguration.IsCrossTargeting());

                    TargetFramework?activeTargetFramework = _targetFrameworkProvider.GetTargetFramework(activeProjectConfiguration.Dimensions[ConfigurationGeneral.TargetFrameworkProperty]);

                    if (!previousContext.ActiveTargetFramework.Equals(activeTargetFramework))
                    {
                        // Active target framework is different.
                        return(false);
                    }

                    var targetFrameworkMonikers = knownProjectConfigurations
                                                  .Select(c => c.Dimensions[ConfigurationGeneral.TargetFrameworkProperty])
                                                  .Distinct()
                                                  .ToList();

                    if (targetFrameworkMonikers.Count != previousContext.TargetFrameworks.Length)
                    {
                        // Different number of target frameworks.
                        return(false);
                    }

                    foreach (string targetFrameworkMoniker in targetFrameworkMonikers)
                    {
                        TargetFramework?targetFramework = _targetFrameworkProvider.GetTargetFramework(targetFrameworkMoniker);

                        if (targetFramework == null || !previousContext.TargetFrameworks.Contains(targetFramework))
                        {
                            // Differing TargetFramework
                            return(false);
                        }
                    }

                    return(true);
                }
            }