From 84937f94064ddedf52a271f5962d15af1c6e58d1 Mon Sep 17 00:00:00 2001 From: Mitch Capper Date: Wed, 12 Apr 2023 13:19:28 -0700 Subject: [PATCH] CPS Custom In Memory Profile option Prevents overriding existing project profiles not enabled by default --- .../SmartCmdArgs.Shared/CmdArgsOptionPage.cs | 10 +++++ .../SmartCmdArgs.Shared/CmdArgsPackage.cs | 28 ++++++++++++- .../Helper/CpsProjectSupport.cs | 40 ++++++++++++++++--- .../Helper/ProjectArguments.cs | 10 ++--- .../Logic/JsonDataObjects.cs | 2 + .../View/SettingsControl.xaml | 5 +++ .../ViewModel/SettingsViewModel.cs | 11 ++++- 7 files changed, 93 insertions(+), 13 deletions(-) diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs b/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs index f3b2fdd8..b83ecbf0 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs @@ -45,6 +45,7 @@ public CmdArgsOptionPage() : base() private bool _vcsSupportEnabled; private bool _useSolutionDir; private bool _macroEvaluationEnabled; + private bool _CPSCustomProjectEnabled; [Category("General")] [DisplayName("Relative path root")] @@ -126,6 +127,15 @@ public bool MacroEvaluationEnabled set => SetAndNotify(value, ref _macroEvaluationEnabled); } + [Category("Settings Defaults")] + [DisplayName("CPS Custom Project Profile")] + [Description("If enabled CPS style projects will have an additional in memory 'Smart CLI Command' profile added, and our custom args will only run when its selected rather than overriding the active profile.")] + [DefaultValue(false)] + public bool CPSCustomProjectEnabled { + get => _CPSCustomProjectEnabled; + set => SetAndNotify(value, ref _CPSCustomProjectEnabled); + } + public override void SaveSettingsToStorage() { if (_dontSave) diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs b/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs index e2f21116..d50088ce 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs @@ -87,6 +87,7 @@ public sealed class CmdArgsPackage : AsyncPackage public bool SaveSettingsToJson => Settings.SaveSettingsToJson ?? Options.SaveSettingsToJson; public bool IsVcsSupportEnabled => Settings.VcsSupportEnabled ?? Options.VcsSupportEnabled; public bool IsMacroEvaluationEnabled => Settings.MacroEvaluationEnabled ?? Options.MacroEvaluationEnabled; + public bool CPSCustomProjectEnabled => Settings.CPSCustomProjectEnabled ?? Options.CPSCustomProjectEnabled; public bool IsUseSolutionDirEnabled => vsHelper?.GetSolutionFilename() != null && (Settings.UseSolutionDir ?? Options.UseSolutionDir); public bool IsUseMonospaceFontEnabled => Options.UseMonospaceFont; @@ -120,6 +121,24 @@ public CmdArgsPackage() this.AddOptionKey(SolutionOptionKey); } + private void CPSCreateAndSetProfileIfUsed(Guid ProjectGuid) { + if (!CPSCustomProjectEnabled || ProjectGuid == Guid.Empty) + return; + + if (! ToolWindowViewModel.TreeViewModel.AllItems.Any(a=>a is CmdArgument)) + return; + + var ivProject = vsHelper.HierarchyForProjectGuid(ProjectGuid); + if (!ivProject.IsCpsProject()) + return; + + var project = ivProject.GetProject(); + if (CpsProjectSupport.IsActiveLaunchProfileCustomProfile(project)) + return; + + CpsProjectSupport.EnsureCustomProfileCreated(project, true); + } + #region Package Members internal Interface GetService() { @@ -211,6 +230,8 @@ private void SettingsViewModel_PropertyChanged(object sender, System.ComponentMo private void OnTreeContentChangedThrottled(object sender, TreeViewModel.TreeChangedEventArgs e) { + CPSCreateAndSetProfileIfUsed(e.AffectedProject?.Id ?? Guid.Empty); + if (IsVcsSupportEnabled) { Logger.Info($"Tree content changed and VCS support is enabled. Saving all project commands to json file for project '{e.AffectedProject.Id}'."); @@ -282,7 +303,7 @@ private void UpdateConfigurationForProject(IVsHierarchy project) if (commandLineArgs == null) return; - ProjectArguments.SetArguments(project, commandLineArgs); + ProjectArguments.SetArguments(project, commandLineArgs, CPSCustomProjectEnabled); Logger.Info($"Updated Configuration for Project: {project.GetName()}"); } @@ -530,6 +551,8 @@ private void UpdateCommandsForProject(IVsHierarchy project) return; } + CPSCreateAndSetProfileIfUsed(project.GetGuid()); + var solutionData = toolWindowStateLoadedFromSolution ?? new SuoDataJson(); // joins data from solution and project @@ -814,6 +837,9 @@ private void UpdateCurrentStartupProject() ToolWindowViewModel.TreeViewModel.Projects.ForEach(p => p.Value.IsStartupProject = startupProjectGuids.Contains(p.Key)); ToolWindowViewModel.TreeViewModel.UpdateTree(); + + //we don't have to worry if we are empty or not it will check that for us + startupProjectGuids.ForEach(guid => CPSCreateAndSetProfileIfUsed(guid)); } public Task OpenFileInVisualStudioAsync(string path) => vsHelper.OpenFileInVisualStudioAsync(path); diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectSupport.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectSupport.cs index b35191de..fea99d79 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectSupport.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectSupport.cs @@ -54,6 +54,8 @@ public static string GetActiveLaunchProfileName(EnvDTE.Project project) return null; } + public static bool IsActiveLaunchProfileCustomProfile(EnvDTE.Project project) => GetActiveLaunchProfileName(project) == WritableLaunchProfile.CustomProfileName; + public static IEnumerable GetLaunchProfileNames(EnvDTE.Project project) { if (TryGetProjectServices(project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices)) @@ -64,7 +66,12 @@ public static IEnumerable GetLaunchProfileNames(EnvDTE.Project project) return null; } - public static void SetCpsProjectArguments(EnvDTE.Project project, string arguments) + public static void EnsureCustomProfileCreated(EnvDTE.Project project, bool SetActive) + { + SetCpsProjectArguments(project, "", true, SetActive); + } + + public static void SetCpsProjectArguments(EnvDTE.Project project, string arguments, bool cpsUseCustomProfile, bool setActive = false) { IUnconfiguredProjectServices unconfiguredProjectServices; IProjectServices projectServices; @@ -77,7 +84,7 @@ public static void SetCpsProjectArguments(EnvDTE.Project project, string argumen if (activeLaunchProfile == null) return; - WritableLaunchProfile writableLaunchProfile = new WritableLaunchProfile(activeLaunchProfile); + WritableLaunchProfile writableLaunchProfile = new WritableLaunchProfile(activeLaunchProfile, cpsUseCustomProfile); writableLaunchProfile.CommandLineArgs = arguments; // Does not work on VS2015, which should be okay ... @@ -85,7 +92,11 @@ public static void SetCpsProjectArguments(EnvDTE.Project project, string argumen IProjectThreadingService projectThreadingService = projectServices.ThreadingPolicy; projectThreadingService.ExecuteSynchronously(() => { - return launchSettingsProvider.AddOrUpdateProfileAsync(writableLaunchProfile, addToFront: false); + var task = launchSettingsProvider.AddOrUpdateProfileAsync(writableLaunchProfile, addToFront: false); + if (setActive) + task = task.ContinueWith(_ => launchSettingsProvider.SetActiveProfileAsync(writableLaunchProfile.Name)); + + return task; }); } } @@ -117,6 +128,9 @@ public static Dictionary GetCpsProjectAllArguments(EnvDTE.Projec } class WritableLaunchProfile : ILaunchProfile +#if VS17 + , Microsoft.VisualStudio.ProjectSystem.Debug.IPersistOption +#endif { public string Name { set; get; } public string CommandName { set; get; } @@ -127,13 +141,27 @@ class WritableLaunchProfile : ILaunchProfile public string LaunchUrl { set; get; } public ImmutableDictionary EnvironmentVariables { set; get; } public ImmutableDictionary OtherSettings { set; get; } + public bool DoNotPersist { get; set; } - public WritableLaunchProfile(ILaunchProfile launchProfile) + public const string CustomProfileName = "Smart CLI Args"; + public WritableLaunchProfile(ILaunchProfile launchProfile, bool cpsUseCustomProfile) { - Name = launchProfile.Name; + if (!cpsUseCustomProfile) + { + Name = launchProfile.Name; + CommandLineArgs = launchProfile.CommandLineArgs; + } else + { + Name = CustomProfileName; + DoNotPersist = true; + if (launchProfile.Name == CustomProfileName) + CommandLineArgs = launchProfile.CommandLineArgs; + else + CommandLineArgs = "";//ensure we dont get into an odd state where hidden args are being applied + + } ExecutablePath = launchProfile.ExecutablePath; CommandName = launchProfile.CommandName; - CommandLineArgs = launchProfile.CommandLineArgs; WorkingDirectory = launchProfile.WorkingDirectory; LaunchBrowser = launchProfile.LaunchBrowser; LaunchUrl = launchProfile.LaunchUrl; diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Helper/ProjectArguments.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Helper/ProjectArguments.cs index 805658ff..114b5357 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Helper/ProjectArguments.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Helper/ProjectArguments.cs @@ -249,11 +249,11 @@ private static void GetVFProjEngineAllArguments(EnvDTE.Project project, List allArgs) @@ -302,7 +302,7 @@ private static void GetCpsProjectAllArguments(EnvDTE.Project project, List SetCpsProjectArguments(project, arguments), + SetArguments = (project, arguments) => SetCpsProjectArguments(project, arguments, false), GetAllArguments = (project, allArgs) => GetCpsProjectAllArguments(project, allArgs) } }, // F# @@ -356,12 +356,12 @@ public static void AddAllArguments(IVsHierarchy project, List a } } - public static void SetArguments(IVsHierarchy project, string arguments) + public static void SetArguments(IVsHierarchy project, string arguments, bool CpsUseCustomProfile=false) { if (project.IsCpsProject()) { Logger.Info($"Setting arguments on CPS project of type '{project.GetKind()}'."); - SetCpsProjectArguments(project.GetProject(), arguments); + SetCpsProjectArguments(project.GetProject(), arguments, CpsUseCustomProfile); } else { diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Logic/JsonDataObjects.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Logic/JsonDataObjects.cs index 9cc7c7fa..13aea41f 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Logic/JsonDataObjects.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Logic/JsonDataObjects.cs @@ -19,6 +19,7 @@ public class SettingsJson public bool? VcsSupportEnabled { get; set; } public bool? UseSolutionDir { get; set; } public bool? MacroEvaluationEnabled { get; set; } + public bool? CPSCustomProjectEnabled { get; set; } public SettingsJson() { } @@ -28,6 +29,7 @@ public SettingsJson(SettingsViewModel settingsViewModel) VcsSupportEnabled = settingsViewModel.VcsSupportEnabled; UseSolutionDir = settingsViewModel.UseSolutionDir; MacroEvaluationEnabled = settingsViewModel.MacroEvaluationEnabled; + CPSCustomProjectEnabled = settingsViewModel.CPSCustomProjectEnabled; } } diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/View/SettingsControl.xaml b/SmartCmdArgs/SmartCmdArgs.Shared/View/SettingsControl.xaml index 772c2267..8e2b783d 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/View/SettingsControl.xaml +++ b/SmartCmdArgs/SmartCmdArgs.Shared/View/SettingsControl.xaml @@ -41,6 +41,11 @@ If enabled Macros like '$(ProjectDir)' will be evaluated and replaced by the corresponding string. + + + + If enabled CPS style projects will have an additional in memory 'Smart CLI Command' profile added, and our custom args will only run when its selected rather than overriding the active profile. + diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/ViewModel/SettingsViewModel.cs b/SmartCmdArgs/SmartCmdArgs.Shared/ViewModel/SettingsViewModel.cs index 5eb2efbc..2ec5a986 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/ViewModel/SettingsViewModel.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/ViewModel/SettingsViewModel.cs @@ -18,6 +18,7 @@ public class SettingsViewModel : PropertyChangedBase private bool? _vcsSupportEnabled; private bool? _useSolutionDir; private bool? _macroEvaluationEnabled; + private bool? _CPSCustomProjectEnabled; public bool? SaveSettingsToJson { @@ -43,8 +44,16 @@ public bool? MacroEvaluationEnabled set => SetAndNotify(value, ref _macroEvaluationEnabled); } + + public bool? CPSCustomProjectEnabled + { + get => _CPSCustomProjectEnabled; + set => SetAndNotify(value, ref _CPSCustomProjectEnabled); + } + public RelayCommand OpenOptionsCommand { get; } - public CmdArgsPackage Package => _package; + + public CmdArgsPackage Package => _package; public SettingsViewModel(CmdArgsPackage package) {