From b346dc246e5116954a17b852918b85f8a421c88a Mon Sep 17 00:00:00 2001 From: Mitch Capper Date: Thu, 1 Aug 2024 02:18:08 -0700 Subject: [PATCH 1/7] Reimplementation of in memory profile support #151 and #147 --- .../SmartCmdArgs.Shared/CmdArgsOptionPage.cs | 14 +- .../SmartCmdArgs.Shared/CmdArgsPackage.cs | 13 +- ...tSupport.cs => CpsProjectConfigService.cs} | 104 +++++-- .../Services/ItemAggregationService.cs | 10 +- .../OptionsSettingsEventHandlingService.cs | 20 +- .../Services/OptionsSettingsService.cs | 8 +- .../Services/ProjectConfigService.cs | 194 ++++++------ .../Services/VisualStudioHelperService.cs | 15 +- .../SmartCmdArgs.Shared.projitems | 286 +++++++++--------- .../SmartCmdArgs17/SmartCmdArgs17.csproj | 11 +- .../Services/ItemAggregationServiceTests.cs | 7 +- 11 files changed, 390 insertions(+), 292 deletions(-) rename SmartCmdArgs/SmartCmdArgs.Shared/Helper/{CpsProjectSupport.cs => CpsProjectConfigService.cs} (68%) diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs b/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs index 12b59e34..d279c559 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs @@ -1,4 +1,4 @@ -using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell; using SmartCmdArgs.Helper; using System.ComponentModel; using System.Linq; @@ -78,6 +78,7 @@ public CmdArgsOptionPage() : base() private bool _manageWorkingDirectories; private bool _manageLaunchApplication; private bool _vcsSupportEnabled; + private bool _useCpsVirtualProfile; private bool _useSolutionDir; private bool _macroEvaluationEnabled; @@ -111,6 +112,7 @@ public bool UseMonospaceFont set => SetAndNotify(value, ref _useMonospaceFont); } + [Category("Appearance")] [DisplayName("Display Tags for CLAs")] [Description("If enabled the item tag 'CLA' is displayed for Command Line Arguments. Normally the tag 'ENV' is only displayed for environment varibales.")] @@ -201,6 +203,16 @@ public bool VcsSupportEnabled set => SetAndNotify(value, ref _vcsSupportEnabled); } + [Category("Settings Defaults")] + [DisplayName("Use CPS Virtual Profile")] + [Description("If enabled a virtual profile is created for CPS projects and only this profile is changed by the extension.")] + [DefaultValue(false)] + public bool UseCpsVirtualProfile + { + get => _useCpsVirtualProfile; + set => SetAndNotify(value, ref _useCpsVirtualProfile); + } + [Category("Settings Defaults")] [DisplayName("Use Solution Directory")] [Description("If enabled all arguments of every project will be stored in a single file next to the *.sln file. (Only if version control support is enabled)")] diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs b/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs index d37d7b74..a85d4c2c 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // Copyright (c) Company. All rights reserved. // @@ -69,7 +69,8 @@ public sealed class CmdArgsPackage : AsyncPackage private ISuoDataService suoDataService; private ILifeCycleService lifeCycleService; private IVsEventHandlingService vsEventHandling; - private IFileStorageEventHandlingService fileStorageEventHandling; + private IFileStorageEventHandlingService fileStorageEventHandling; + private ICpsProjectConfigService cpsProjectConfigService; private ToolWindowViewModel toolWindowViewModel; private TreeViewModel treeViewModel; @@ -105,7 +106,8 @@ public CmdArgsPackage() suoDataService = ServiceProvider.GetRequiredService(); lifeCycleService = ServiceProvider.GetRequiredService(); vsEventHandling = ServiceProvider.GetRequiredService(); - fileStorageEventHandling = ServiceProvider.GetRequiredService(); + fileStorageEventHandling = ServiceProvider.GetRequiredService(); + cpsProjectConfigService = ServiceProvider.GetRequiredService(); } protected override void Dispose(bool disposing) @@ -170,7 +172,8 @@ private ServiceProvider ConfigureServices() services.AddLazySingleton(x => GetDialogPage()); services.AddLazySingleton(); services.AddLazySingleton(); - services.AddLazySingleton(); + services.AddLazySingleton(); + services.AddLazySingleton(); services.AddLazySingleton(); services.AddSingleton(); services.AddSingleton(); @@ -264,7 +267,7 @@ public List GetLaunchProfiles(Guid projGuid) List launchProfiles = null; if (project?.IsCpsProject() == true) { - launchProfiles = CpsProjectSupport.GetLaunchProfileNames(project.GetProject())?.ToList(); + launchProfiles = cpsProjectConfigService.GetLaunchProfileNames(project.GetProject())?.ToList(); } return launchProfiles ?? new List(); diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectSupport.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectConfigService.cs similarity index 68% rename from SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectSupport.cs rename to SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectConfigService.cs index 5b364858..a2d5532a 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectSupport.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectConfigService.cs @@ -1,4 +1,5 @@ -using Microsoft.VisualStudio.ProjectSystem; +using EnvDTE; +using Microsoft.VisualStudio.ProjectSystem; using Microsoft.VisualStudio.ProjectSystem.Debug; using Microsoft.VisualStudio.ProjectSystem.Properties; using SmartCmdArgs.DataSerialization; @@ -19,11 +20,32 @@ // As such, ensuring compatibility requires knowledge of the version Visual Studio redirects to, which varies // by Visual Studio installation version. -namespace SmartCmdArgs.Helper +namespace SmartCmdArgs.Services { - public static class CpsProjectSupport + public interface ICpsProjectConfigService { - private static bool TryGetProjectServices(EnvDTE.Project project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices) + string GetActiveLaunchProfileName(Project project); + void GetItemsFromConfig(Project project, List allArgs, bool includeArgs, bool includeEnvVars, bool includeWorkDir, bool includeLaunchApp); + IEnumerable GetLaunchProfileNames(Project project); + IDisposable ListenToLaunchProfileChanges(Project project, Action listener); + void SetActiveLaunchProfileByName(Project project, string profileName); + void SetActiveLaunchProfileToVirtualProfile(Project project); + void SetConfig(Project project, string arguments, IDictionary envVars, string workDir, string launchApp); + } + + public class CpsProjectConfigService : ICpsProjectConfigService + { + public static string VirtualProfileName = "Smart CLI Args"; + + private readonly IOptionsSettingsService optionsSettingsService; + + public CpsProjectConfigService( + IOptionsSettingsService optionsSettingsService) + { + this.optionsSettingsService = optionsSettingsService; + } + + private bool TryGetProjectServices(EnvDTE.Project project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices) { IVsBrowseObjectContext context = project as IVsBrowseObjectContext; if (context == null && project != null) @@ -55,7 +77,7 @@ private static bool TryGetProjectServices(EnvDTE.Project project, out IUnconfigu } } - public static string GetActiveLaunchProfileName(EnvDTE.Project project) + public string GetActiveLaunchProfileName(EnvDTE.Project project) { if (TryGetProjectServices(project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices)) { @@ -65,7 +87,21 @@ public static string GetActiveLaunchProfileName(EnvDTE.Project project) return null; } - public static IEnumerable GetLaunchProfileNames(EnvDTE.Project project) + public void SetActiveLaunchProfileByName(EnvDTE.Project project, string profileName) + { + if (TryGetProjectServices(project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices)) + { + var launchSettingsProvider = unconfiguredProjectServices.ExportProvider.GetExportedValue(); + projectServices.ThreadingPolicy.ExecuteSynchronously(async () => + { + await launchSettingsProvider.SetActiveProfileAsync(profileName); + }); + } + } + + public void SetActiveLaunchProfileToVirtualProfile(EnvDTE.Project project) => SetActiveLaunchProfileByName(project, VirtualProfileName); + + public IEnumerable GetLaunchProfileNames(EnvDTE.Project project) { if (TryGetProjectServices(project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices)) { @@ -75,10 +111,11 @@ public static IEnumerable GetLaunchProfileNames(EnvDTE.Project project) return null; } - public static IDisposable ListenToLaunchProfileChanges(EnvDTE.Project project, Action listener) + public IDisposable ListenToLaunchProfileChanges(EnvDTE.Project project, Action listener) { if (TryGetProjectServices(project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices)) { + var launchSettingsProvider = unconfiguredProjectServices.ExportProvider.GetExportedValue(); if (launchSettingsProvider == null) @@ -92,7 +129,7 @@ public static IDisposable ListenToLaunchProfileChanges(EnvDTE.Project project, A return null; } - public static void SetCpsProjectConfig(EnvDTE.Project project, string arguments, IDictionary envVars, string workDir, string launchApp) + public void SetConfig(EnvDTE.Project project, string arguments, IDictionary envVars, string workDir, string launchApp) { IUnconfiguredProjectServices unconfiguredProjectServices; IProjectServices projectServices; @@ -100,12 +137,21 @@ public static void SetCpsProjectConfig(EnvDTE.Project project, string arguments, if (TryGetProjectServices(project, out unconfiguredProjectServices, out projectServices)) { var launchSettingsProvider = unconfiguredProjectServices.ExportProvider.GetExportedValue(); - var activeLaunchProfile = launchSettingsProvider?.ActiveProfile; + ILaunchProfile baseLaunchProfile = null; + if (optionsSettingsService.UseCpsVirtualProfile) + { + baseLaunchProfile = launchSettingsProvider.CurrentSnapshot.Profiles.FirstOrDefault(x => x.Name == VirtualProfileName); + } - if (activeLaunchProfile == null) + if (baseLaunchProfile == null) + { + baseLaunchProfile = launchSettingsProvider?.ActiveProfile; + } + + if (baseLaunchProfile == null) return; - WritableLaunchProfile writableLaunchProfile = new WritableLaunchProfile(activeLaunchProfile); + WritableLaunchProfile writableLaunchProfile = new WritableLaunchProfile(baseLaunchProfile); if (arguments != null) writableLaunchProfile.CommandLineArgs = arguments; @@ -119,30 +165,31 @@ public static void SetCpsProjectConfig(EnvDTE.Project project, string arguments, if (launchApp != null) writableLaunchProfile.CommandName = launchApp; - // Does not work on VS2015, which should be okay ... - // We don't hold references for VS2015, where the interface is called IThreadHandling - IProjectThreadingService projectThreadingService = projectServices.ThreadingPolicy; - projectThreadingService.ExecuteSynchronously(() => + if (optionsSettingsService.UseCpsVirtualProfile) + { + writableLaunchProfile.Name = VirtualProfileName; + writableLaunchProfile.DoNotPersist = true; + } + + projectServices.ThreadingPolicy.ExecuteSynchronously(() => { return launchSettingsProvider.AddOrUpdateProfileAsync(writableLaunchProfile, addToFront: false); }); } } - public static List GetCpsProjectAllArguments(EnvDTE.Project project, bool includeArgs, bool includeEnvVars, bool includeWorkDir, bool includeLaunchApp) + public void GetItemsFromConfig(EnvDTE.Project project, List allArgs, bool includeArgs, bool includeEnvVars, bool includeWorkDir, bool includeLaunchApp) { IUnconfiguredProjectServices unconfiguredProjectServices; IProjectServices projectServices; - var result = new List(); - if (TryGetProjectServices(project, out unconfiguredProjectServices, out projectServices)) { var launchSettingsProvider = unconfiguredProjectServices.ExportProvider.GetExportedValue(); var launchProfiles = launchSettingsProvider?.CurrentSnapshot?.Profiles; if (launchProfiles == null) - return result; + return; foreach (var profile in launchProfiles) { @@ -173,17 +220,19 @@ public static List GetCpsProjectAllArguments(EnvDTE.Project project if (profileGrp.Items.Count > 0) { - result.Add(profileGrp); + allArgs.Add(profileGrp); } } } - - return result; } } class WritableLaunchProfile : ILaunchProfile +#if VS17 + , IPersistOption +#endif { + // ILaunchProfile public string Name { set; get; } public string CommandName { set; get; } public string ExecutablePath { set; get; } @@ -194,8 +243,12 @@ class WritableLaunchProfile : ILaunchProfile public ImmutableDictionary EnvironmentVariables { set; get; } public ImmutableDictionary OtherSettings { set; get; } + // IPersistOption + public bool DoNotPersist { get; set; } + public WritableLaunchProfile(ILaunchProfile launchProfile) { + // ILaunchProfile Name = launchProfile.Name; ExecutablePath = launchProfile.ExecutablePath; CommandName = launchProfile.CommandName; @@ -205,6 +258,13 @@ public WritableLaunchProfile(ILaunchProfile launchProfile) LaunchUrl = launchProfile.LaunchUrl; EnvironmentVariables = launchProfile.EnvironmentVariables; OtherSettings = launchProfile.OtherSettings; +#if VS17 + if (launchProfile is IPersistOption persistOptionLaunchProfile) + { + // IPersistOption + DoNotPersist = persistOptionLaunchProfile.DoNotPersist; + } +#endif } } } diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/ItemAggregationService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/ItemAggregationService.cs index 45e435eb..d85a6453 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/ItemAggregationService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/ItemAggregationService.cs @@ -1,4 +1,4 @@ -using SmartCmdArgs.Helper; +using SmartCmdArgs.Helper; using SmartCmdArgs.ViewModel; using SmartCmdArgs.Wrapper; using System; @@ -23,15 +23,19 @@ internal class ItemAggregationService : IItemAggregationService private readonly IItemEvaluationService itemEvaluation; private readonly IVisualStudioHelperService vsHelper; private readonly TreeViewModel treeViewModel; + private readonly ICpsProjectConfigService cpsProjectConfigService; + public ItemAggregationService( IItemEvaluationService itemEvaluation, IVisualStudioHelperService vsHelper, - TreeViewModel treeViewModel) + TreeViewModel treeViewModel, + ICpsProjectConfigService cpsProjectConfigService) { this.itemEvaluation = itemEvaluation; this.vsHelper = vsHelper; this.treeViewModel = treeViewModel; + this.cpsProjectConfigService = cpsProjectConfigService; } private TResult AggregateComamndLineItemsForProject(IVsHierarchyWrapper project, Func, Func, CmdContainer, TResult> joinItems) @@ -50,7 +54,7 @@ private TResult AggregateComamndLineItemsForProject(IVsHierarchyWrapper string activeLaunchProfile = null; if (project.IsCpsProject()) - activeLaunchProfile = CpsProjectSupport.GetActiveLaunchProfileName(projectObj); + activeLaunchProfile = cpsProjectConfigService.GetActiveLaunchProfileName(projectObj); TResult JoinContainer(CmdContainer con) { diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs index b8ed9fd3..f4d85e85 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs @@ -1,5 +1,6 @@ -using SmartCmdArgs.ViewModel; +using SmartCmdArgs.ViewModel; using System; +using System.Linq; namespace SmartCmdArgs.Services { @@ -18,6 +19,8 @@ internal class OptionsSettingsEventHandlingService : IOptionsSettingsEventHandli private readonly IViewModelUpdateService viewModelUpdateService; private readonly ToolWindowViewModel toolWindowViewModel; private readonly IToolWindowHistory toolWindowHistory; + private readonly IProjectConfigService projectConfigService; + private readonly ICpsProjectConfigService cpsProjectConfigService; public OptionsSettingsEventHandlingService( IOptionsSettingsService optionsSettings, @@ -26,7 +29,9 @@ public OptionsSettingsEventHandlingService( IVisualStudioHelperService vsHelper, IViewModelUpdateService viewModelUpdateService, ToolWindowViewModel toolWindowViewModel, - IToolWindowHistory toolWindowHistory) + IToolWindowHistory toolWindowHistory, + IProjectConfigService projectConfigService, + ICpsProjectConfigService cpsProjectConfigService) { this.optionsSettings = optionsSettings; this.settingsService = settingsService; @@ -35,6 +40,8 @@ public OptionsSettingsEventHandlingService( this.viewModelUpdateService = viewModelUpdateService; this.toolWindowViewModel = toolWindowViewModel; this.toolWindowHistory = toolWindowHistory; + this.projectConfigService = projectConfigService; + this.cpsProjectConfigService = cpsProjectConfigService; } public void Dispose() @@ -64,6 +71,7 @@ private void OptionsSettings_PropertyChanged(object sender, System.ComponentMode case nameof(IOptionsSettingsService.JsonRootPath): JsonRootPathChanged(); break; case nameof(IOptionsSettingsService.VcsSupportEnabled): VcsSupportChanged(); break; case nameof(IOptionsSettingsService.UseSolutionDir): UseSolutionDirChanged(); break; + case nameof(IOptionsSettingsService.UseCpsVirtualProfile): UseCpsVirtualProfileChanged(); break; case nameof(IOptionsSettingsService.ManageCommandLineArgs): viewModelUpdateService.UpdateIsActiveForParamsDebounced(); break; case nameof(IOptionsSettingsService.ManageEnvironmentVars): viewModelUpdateService.UpdateIsActiveForParamsDebounced(); break; case nameof(IOptionsSettingsService.ManageWorkingDirectories): viewModelUpdateService.UpdateIsActiveForParamsDebounced(); break; @@ -116,5 +124,13 @@ private void UseSolutionDirChanged() fileStorage.DeleteAllUnusedArgFiles(); fileStorage.SaveAllProjects(); } + private void UseCpsVirtualProfileChanged() + { + foreach (var project in vsHelper.GetSupportedProjects().Where(x => x.IsCpsProject())) + { + projectConfigService.UpdateProjectConfig(project); + cpsProjectConfigService.SetActiveLaunchProfileToVirtualProfile(project.GetProject()); + } + } } } diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsService.cs index 5f1e1aa4..e1e61d54 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsService.cs @@ -1,4 +1,4 @@ -using SmartCmdArgs.Helper; +using SmartCmdArgs.Helper; using SmartCmdArgs.ViewModel; using System; using System.ComponentModel; @@ -24,6 +24,7 @@ public interface IOptionsSettingsService bool? GatherArgsIgnoreCpp { get; } // Options + bool UseCpsVirtualProfile { get; } bool UseMonospaceFont { get; } bool DisplayTagForCla { get; } bool DeleteEmptyFilesAutomatically { get; } @@ -69,6 +70,11 @@ public OptionsSettingsService( public bool? GatherArgsIgnoreCpp => settingsViewModel.GatherArgsIgnoreCpp; // Options +#if VS17 + public bool UseCpsVirtualProfile => OptionsPage.UseCpsVirtualProfile; +#else + public bool UseCpsVirtualProfile => false; +#endif public bool UseMonospaceFont => OptionsPage.UseMonospaceFont; public bool DisplayTagForCla => OptionsPage.DisplayTagForCla; public bool DeleteEmptyFilesAutomatically => OptionsPage.DeleteEmptyFilesAutomatically; diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/ProjectConfigService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/ProjectConfigService.cs index e144f24f..b7d4b2a4 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/ProjectConfigService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/ProjectConfigService.cs @@ -22,15 +22,28 @@ public class ProjectConfigService : IProjectConfigService private readonly Lazy lifeCycleService; private readonly IOptionsSettingsService optionsSettings; private readonly IItemAggregationService itemAggregationService; + private readonly ICpsProjectConfigService cpsProjectConfigService; + + private readonly Dictionary configHandlerForSupportedProjects; + private readonly ProjectConfigHandlers cpsProjectConfigHandlers; public ProjectConfigService( Lazy lifeCycleService, IOptionsSettingsService optionsSettings, - IItemAggregationService itemAggregationService) + IItemAggregationService itemAggregationService, + ICpsProjectConfigService cpsProjectConfigService) { this.lifeCycleService = lifeCycleService; this.optionsSettings = optionsSettings; this.itemAggregationService = itemAggregationService; + this.cpsProjectConfigService = cpsProjectConfigService; + + configHandlerForSupportedProjects = InitConfigHandlerForSupportedProjects(); + cpsProjectConfigHandlers = new ProjectConfigHandlers + { + GetItemsFromConfig = cpsProjectConfigService.GetItemsFromConfig, + SetConfig = cpsProjectConfigService.SetConfig, + }; } private class ProjectConfigHandlers @@ -40,6 +53,79 @@ private class ProjectConfigHandlers public SetConfigDelegate SetConfig; public GetAllArgumentsDelegate GetItemsFromConfig; } + private Dictionary InitConfigHandlerForSupportedProjects() + { + return new Dictionary() + { + // C# + {ProjectKinds.CS, new ProjectConfigHandlers() { + SetConfig = (project, arguments, envVars, workDir, launchApp) => { + SetMultiConfigProperty(project, arguments, "StartArguments"); + SetMultiConfigProperty(project, workDir, "StartWorkingDirectory"); + SetMultiConfigProperty(project, launchApp, "StartProgram"); + }, + GetItemsFromConfig = GetItemsFromMultiConfig("StartArguments", "StartWorkingDirectory", "StartProgram") + } }, + // C# UWP + {ProjectKinds.CS_UWP, new ProjectConfigHandlers() { + SetConfig = (project, arguments, envVars, workDir, launchApp) => SetMultiConfigProperty(project, arguments, "UAPDebug.CommandLineArguments"), + GetItemsFromConfig = GetItemsFromMultiConfig("UAPDebug.CommandLineArguments") + } }, + + // VB.NET + {ProjectKinds.VB, new ProjectConfigHandlers() { + SetConfig = (project, arguments, _, workDir, launchApp) => { + SetMultiConfigProperty(project, arguments, "StartArguments"); + SetMultiConfigProperty(project, workDir, "StartWorkingDirectory"); + SetMultiConfigProperty(project, launchApp, "StartProgram"); + }, + GetItemsFromConfig = GetItemsFromMultiConfig("StartArguments", "StartWorkingDirectory", "StartProgram") + } }, + // C/C++ + {ProjectKinds.CPP, new ProjectConfigHandlers() { + SetConfig = SetVCProjEngineConfig, + GetItemsFromConfig = GetItemsFromVCProjEngineConfig + } }, + // Python + {ProjectKinds.Py, new ProjectConfigHandlers() { + SetConfig = (project, arguments, envVars, workDir, _) => { + SetSingleConfigProperty(project, arguments, "CommandLineArguments"); + SetSingleConfigEnvVars(project, envVars, "Environment"); + SetSingleConfigProperty(project, workDir, "WorkingDirectory"); + }, + GetItemsFromConfig = GetItemsFromSingleConfig("CommandLineArguments", "Environment", "WorkingDirectory", null), + } }, + // Node.js + {ProjectKinds.Node, new ProjectConfigHandlers() { + SetConfig = (project, arguments, envVars, workDir, _) => { + SetSingleConfigProperty(project, arguments, "ScriptArguments"); + SetSingleConfigEnvVars(project, envVars, "Environment"); + SetSingleConfigProperty(project, workDir, "WorkingDirectory"); + }, + GetItemsFromConfig = GetItemsFromSingleConfig("ScriptArguments", "Environment", "WorkingDirectory", null), + } }, + // C# - Lagacy DotNetCore + {ProjectKinds.CSCore, new ProjectConfigHandlers() { + SetConfig = cpsProjectConfigService.SetConfig, + GetItemsFromConfig = cpsProjectConfigService.GetItemsFromConfig, + } }, + // F# + {ProjectKinds.FS, new ProjectConfigHandlers() { + SetConfig = (project, arguments, _, workDir, launchApp) => { + SetMultiConfigProperty(project, arguments, "StartArguments"); + SetMultiConfigProperty(project, workDir, "StartWorkingDirectory"); + SetMultiConfigProperty(project, launchApp, "StartProgram"); + }, + GetItemsFromConfig = GetItemsFromMultiConfig("StartArguments", "StartWorkingDirectory", "StartProgram") + } }, + // Fortran + {ProjectKinds.Fortran, new ProjectConfigHandlers() { + SetConfig = SetVFProjEngineConfig, + GetItemsFromConfig = GetItemsFromVFProjEngineConfig + } }, + }; + } + private static string GetEnvVarStringFromDict(IDictionary envVars) => string.Join(Environment.NewLine, envVars.Select(x => $"{x.Key}={x.Value}")); @@ -623,100 +709,6 @@ private static void GetItemsFromVFProjEngineConfig(EnvDTE.Project project, List< #endregion VFProjEngine (Fortran) - #region Common Project System (CPS) - - private static void SetCpsProjectConfig(EnvDTE.Project project, string arguments, IDictionary envVars, string workDir, string launchApp) - { - // Should only be called in VS 2017 or higher - // .Net Core 2 is not supported by VS 2015, so this should not cause problems - CpsProjectSupport.SetCpsProjectConfig(project, arguments, envVars, workDir, launchApp); - } - - private static void GetItemsFromCpsProjectConfig(EnvDTE.Project project, List allArgs, bool includeArgs, bool includeEnvVars, bool includeWorkDir, bool includeLaunchApp) - { - // Should only be called in VS 2017 or higher - // see SetCpsProjectArguments - allArgs.AddRange(CpsProjectSupport.GetCpsProjectAllArguments(project, includeArgs, includeEnvVars, includeWorkDir, includeLaunchApp)); - } - - #endregion Common Project System (CPS) - - private static Dictionary supportedProjects = new Dictionary() - { - // C# - {ProjectKinds.CS, new ProjectConfigHandlers() { - SetConfig = (project, arguments, envVars, workDir, launchApp) => { - SetMultiConfigProperty(project, arguments, "StartArguments"); - SetMultiConfigProperty(project, workDir, "StartWorkingDirectory"); - SetMultiConfigProperty(project, launchApp, "StartProgram"); - }, - GetItemsFromConfig = GetItemsFromMultiConfig("StartArguments", "StartWorkingDirectory", "StartProgram") - } }, - // C# UWP - {ProjectKinds.CS_UWP, new ProjectConfigHandlers() { - SetConfig = (project, arguments, envVars, workDir, launchApp) => SetMultiConfigProperty(project, arguments, "UAPDebug.CommandLineArguments"), - GetItemsFromConfig = GetItemsFromMultiConfig("UAPDebug.CommandLineArguments") - } }, - - // VB.NET - {ProjectKinds.VB, new ProjectConfigHandlers() { - SetConfig = (project, arguments, _, workDir, launchApp) => { - SetMultiConfigProperty(project, arguments, "StartArguments"); - SetMultiConfigProperty(project, workDir, "StartWorkingDirectory"); - SetMultiConfigProperty(project, launchApp, "StartProgram"); - }, - GetItemsFromConfig = GetItemsFromMultiConfig("StartArguments", "StartWorkingDirectory", "StartProgram") - } }, - // C/C++ - {ProjectKinds.CPP, new ProjectConfigHandlers() { - SetConfig = SetVCProjEngineConfig, - GetItemsFromConfig = GetItemsFromVCProjEngineConfig - } }, - // Python - {ProjectKinds.Py, new ProjectConfigHandlers() { - SetConfig = (project, arguments, envVars, workDir, _) => { - SetSingleConfigProperty(project, arguments, "CommandLineArguments"); - SetSingleConfigEnvVars(project, envVars, "Environment"); - SetSingleConfigProperty(project, workDir, "WorkingDirectory"); - }, - GetItemsFromConfig = GetItemsFromSingleConfig("CommandLineArguments", "Environment", "WorkingDirectory", null), - } }, - // Node.js - {ProjectKinds.Node, new ProjectConfigHandlers() { - SetConfig = (project, arguments, envVars, workDir, _) => { - SetSingleConfigProperty(project, arguments, "ScriptArguments"); - SetSingleConfigEnvVars(project, envVars, "Environment"); - SetSingleConfigProperty(project, workDir, "WorkingDirectory"); - }, - GetItemsFromConfig = GetItemsFromSingleConfig("ScriptArguments", "Environment", "WorkingDirectory", null), - } }, - // C# - Lagacy DotNetCore - {ProjectKinds.CSCore, new ProjectConfigHandlers() { - SetConfig = SetCpsProjectConfig, - GetItemsFromConfig = GetItemsFromCpsProjectConfig - } }, - // F# - {ProjectKinds.FS, new ProjectConfigHandlers() { - SetConfig = (project, arguments, _, workDir, launchApp) => { - SetMultiConfigProperty(project, arguments, "StartArguments"); - SetMultiConfigProperty(project, workDir, "StartWorkingDirectory"); - SetMultiConfigProperty(project, launchApp, "StartProgram"); - }, - GetItemsFromConfig = GetItemsFromMultiConfig("StartArguments", "StartWorkingDirectory", "StartProgram") - } }, - // Fortran - {ProjectKinds.Fortran, new ProjectConfigHandlers() { - SetConfig = SetVFProjEngineConfig, - GetItemsFromConfig = GetItemsFromVFProjEngineConfig - } }, - }; - - private static ProjectConfigHandlers CpsProjectConfigHandlers = new ProjectConfigHandlers - { - GetItemsFromConfig = GetItemsFromCpsProjectConfig, - SetConfig = SetCpsProjectConfig, - }; - public bool IsSupportedProject(IVsHierarchyWrapper project) { if (project == null) @@ -736,14 +728,14 @@ public bool IsSupportedProject(IVsHierarchyWrapper project) if (project.IsSharedAssetsProject()) return false; - return supportedProjects.ContainsKey(project.GetKind()); + return configHandlerForSupportedProjects.ContainsKey(project.GetKind()); } - private static bool TryGetProjectConfigHandlers(IVsHierarchyWrapper project, out ProjectConfigHandlers handler) + private bool TryGetProjectConfigHandlers(IVsHierarchyWrapper project, out ProjectConfigHandlers handler) { if (project.IsCpsProject()) { - handler = CpsProjectConfigHandlers; + handler = cpsProjectConfigHandlers; return true; } @@ -753,14 +745,14 @@ private static bool TryGetProjectConfigHandlers(IVsHierarchyWrapper project, out { foreach (var kind in project.GetAllTypeGuidsFromFile()) { - if (kind != projectKind && supportedProjects.TryGetValue(kind, out handler)) + if (kind != projectKind && configHandlerForSupportedProjects.TryGetValue(kind, out handler)) { return true; } } } - return supportedProjects.TryGetValue(projectKind, out handler); + return configHandlerForSupportedProjects.TryGetValue(projectKind, out handler); } public List GetItemsFromProjectConfig(IVsHierarchyWrapper project) @@ -825,4 +817,4 @@ static class ProjectKinds public static readonly Guid CSCore = Guid.Parse("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"); } -} \ No newline at end of file +} diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/VisualStudioHelperService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/VisualStudioHelperService.cs index c4bf1cf0..9751676f 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/VisualStudioHelperService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/VisualStudioHelperService.cs @@ -1,4 +1,4 @@ -using EnvDTE; +using EnvDTE; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; @@ -113,6 +113,7 @@ class VisualStudioHelperService : IVisualStudioHelperService, IAsyncInitializabl public event EventHandler ProjectAfterRename; private readonly Lazy _projectConfigService; + private readonly Lazy cpsProjectConfigService; class ProjectState : IDisposable { @@ -122,14 +123,14 @@ class ProjectState : IDisposable private IDisposable _launchSettingsChangeListenerDisposable; - public ProjectState(IVsHierarchyWrapper pHierarchy, Action launchProfileChangeAction) + public ProjectState(IVsHierarchyWrapper pHierarchy, ICpsProjectConfigService cpsProjectConfigService, Action launchProfileChangeAction) { ProjectDir = pHierarchy.GetProjectDir(); ProjectName = pHierarchy.GetName(); IsLoaded = pHierarchy.IsLoaded(); if (pHierarchy.IsCpsProject()) - _launchSettingsChangeListenerDisposable = CpsProjectSupport.ListenToLaunchProfileChanges(pHierarchy.GetProject(), launchProfileChangeAction); + _launchSettingsChangeListenerDisposable = cpsProjectConfigService.ListenToLaunchProfileChanges(pHierarchy.GetProject(), launchProfileChangeAction); } public void Dispose() @@ -140,10 +141,14 @@ public void Dispose() private Dictionary ProjectStateMap = new Dictionary(); - public VisualStudioHelperService(Lazy projectConfigService) + public VisualStudioHelperService( + Lazy projectConfigService, + Lazy cpsProjectConfigService) { this.package = CmdArgsPackage.Instance; _projectConfigService = projectConfigService; + this.cpsProjectConfigService = cpsProjectConfigService; + _VSConstants_VSStd97CmdID_GUID = typeof(VSConstants.VSStd97CmdID).GUID.ToString("B").ToUpper(); _VSConstants_VSStd2KCmdID_GUID = typeof(VSConstants.VSStd2KCmdID).GUID.ToString("B").ToUpper(); @@ -187,7 +192,7 @@ private void AddProjectState(IVsHierarchyWrapper pHierarchy) { Guid projectGuid = pHierarchy.GetGuid(); ProjectStateMap.GetValueOrDefault(projectGuid)?.Dispose(); - ProjectStateMap[projectGuid] = new ProjectState(pHierarchy, () => + ProjectStateMap[projectGuid] = new ProjectState(pHierarchy,cpsProjectConfigService.Value, () => { ThreadHelper.JoinableTaskFactory.Run(async () => { diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/SmartCmdArgs.Shared.projitems b/SmartCmdArgs/SmartCmdArgs.Shared/SmartCmdArgs.Shared.projitems index 75f1a27e..afed7876 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/SmartCmdArgs.Shared.projitems +++ b/SmartCmdArgs/SmartCmdArgs.Shared/SmartCmdArgs.Shared.projitems @@ -1,144 +1,144 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - 676c8571-fc9d-43dd-948e-897817a07039 - - - SmartCmdArgs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ArgumentItemView.xaml - - - - - - - - - - - - - - - - - - - - - - GatherArgsQuestionControl.xaml - - - - - - - SettingsControl.xaml - - - - - ToolWindowControl.xaml - - - - - SettingsCheckBox.xaml - - - - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 676c8571-fc9d-43dd-948e-897817a07039 + + + SmartCmdArgs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ArgumentItemView.xaml + + + + + + + + + + + + + + + + + + + + + + GatherArgsQuestionControl.xaml + + + + + + + SettingsControl.xaml + + + + + ToolWindowControl.xaml + + + + + SettingsCheckBox.xaml + + + + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + \ No newline at end of file diff --git a/SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj b/SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj index 5c6cba2e..64f93861 100644 --- a/SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj +++ b/SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj @@ -1,4 +1,4 @@ - + 17.0 @@ -99,11 +99,8 @@ 7.0.0 - - 15.8.243 - - - 2.0.6142705 + + 17.11.1.102 @@ -163,4 +160,4 @@ --> - \ No newline at end of file + diff --git a/SmartCmdArgs/Testing/SmartCmdArgs.Tests/Services/ItemAggregationServiceTests.cs b/SmartCmdArgs/Testing/SmartCmdArgs.Tests/Services/ItemAggregationServiceTests.cs index 99fcbc4a..aafa2c3d 100644 --- a/SmartCmdArgs/Testing/SmartCmdArgs.Tests/Services/ItemAggregationServiceTests.cs +++ b/SmartCmdArgs/Testing/SmartCmdArgs.Tests/Services/ItemAggregationServiceTests.cs @@ -1,4 +1,4 @@ -using Moq; +using Moq; using System; using System.Collections.Generic; using SmartCmdArgs.ViewModel; @@ -19,6 +19,7 @@ public class ItemAggregationServiceTests private readonly Mock itemEvaluationServiceMock; private readonly Mock vsHelperServiceMock; private readonly Mock toolWindowHistoryMock; + private readonly Mock cpsProjectConfigService; private readonly TreeViewModel treeViewModel; private readonly ItemAggregationService itemAggregationService; @@ -29,6 +30,7 @@ public ItemAggregationServiceTests(GlobalServiceProvider sp) itemEvaluationServiceMock = new Mock(); vsHelperServiceMock = new Mock(); toolWindowHistoryMock = new Mock(); + cpsProjectConfigService = new Mock(); treeViewModel = new TreeViewModel(toolWindowHistoryMock.LazyObject()); itemEvaluationServiceMock.Setup(x => x.EvaluateMacros(It.IsAny(), It.IsAny())).Returns((arg, _) => arg); @@ -36,7 +38,8 @@ public ItemAggregationServiceTests(GlobalServiceProvider sp) itemAggregationService = new ItemAggregationService( itemEvaluationServiceMock.Object, vsHelperServiceMock.Object, - treeViewModel + treeViewModel, + cpsProjectConfigService.Object ); } From a0be63269d8e09bc548d17df854086a2143edb97 Mon Sep 17 00:00:00 2001 From: Mitch Capper Date: Thu, 1 Aug 2024 16:06:05 -0700 Subject: [PATCH 2/7] Dynamic support of IPersistOption --- .../Helper/CpsProjectConfigService.cs | 83 +++++++++++++++++-- .../SmartCmdArgs17/SmartCmdArgs17.csproj | 21 ++++- .../SmartCmdArgs17/source.extension.cs | 34 ++++---- 3 files changed, 112 insertions(+), 26 deletions(-) diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectConfigService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectConfigService.cs index a2d5532a..ca7e2fca 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectConfigService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectConfigService.cs @@ -8,6 +8,11 @@ using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks.Dataflow; +#if DYNAMIC_VSProjectManaged +using System.Reflection; +using System.Reflection.Emit; +using Expression = System.Linq.Expressions.Expression; +#endif // This isolation of Microsoft.VisualStudio.ProjectSystem dependencies into one file ensures compatibility // across various Visual Studio installations. This is crucial because not all Visual Studio workloads @@ -151,7 +156,7 @@ public void SetConfig(EnvDTE.Project project, string arguments, IDictionary allArgs } } } - - class WritableLaunchProfile : ILaunchProfile -#if VS17 + public class WritableLaunchProfile : ILaunchProfile //must be public to avoid having to declare our dynamic assembly a friend +#if VS17 && ! DYNAMIC_VSProjectManaged , IPersistOption #endif { @@ -245,7 +249,10 @@ class WritableLaunchProfile : ILaunchProfile // IPersistOption public bool DoNotPersist { get; set; } - +#if DYNAMIC_VSProjectManaged + private static Func LaunchProfileIsDoNotPersistFunc; +#endif + private static Lazy IPersistOptionType = new Lazy(() => typeof(ILaunchProfile).Assembly.GetType("Microsoft.VisualStudio.ProjectSystem.Debug.IPersistOption")); public WritableLaunchProfile(ILaunchProfile launchProfile) { // ILaunchProfile @@ -259,12 +266,78 @@ public WritableLaunchProfile(ILaunchProfile launchProfile) EnvironmentVariables = launchProfile.EnvironmentVariables; OtherSettings = launchProfile.OtherSettings; #if VS17 +#if DYNAMIC_VSProjectManaged + if (LaunchProfileIsDoNotPersistFunc == null) + { + if (IPersistOptionType.Value == null) + LaunchProfileIsDoNotPersistFunc = (_) => false; + else + { + var instanceParam = Expression.Parameter(typeof(ILaunchProfile)); + var asIPersist = Expression.TypeAs(instanceParam, IPersistOptionType.Value); + var expr = Expression.Condition(Expression.Equal(asIPersist, Expression.Constant(null)), Expression.Constant(false), Expression.Property(asIPersist, nameof(DoNotPersist))); + LaunchProfileIsDoNotPersistFunc = Expression.Lambda>(expr, instanceParam).Compile(); + } + } + DoNotPersist = LaunchProfileIsDoNotPersistFunc(launchProfile); + +#else if (launchProfile is IPersistOption persistOptionLaunchProfile) { // IPersistOption DoNotPersist = persistOptionLaunchProfile.DoNotPersist; } +#endif #endif } + + private static Func getWritableProfileFunc; + internal static WritableLaunchProfile GetWritableLaunchProfile(ILaunchProfile profile) + { +#if DYNAMIC_VSProjectManaged + if (getWritableProfileFunc == null && IPersistOptionType.Value != null) + { + var ourType = typeof(WritableLaunchProfile); + var asmName = new AssemblyName() { Name = "SmartCLIArgsDynamicAsm" }; + asmName.SetPublicKey(ourType.Assembly.GetName().GetPublicKey()); + var assemBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run); + + var classBuilder = assemBuilder.DefineDynamicModule("SmartCLIArgsDynamicMod").DefineType("DynamicWritableLaunchProfile", TypeAttributes.NotPublic | TypeAttributes.Class, ourType); + classBuilder.AddInterfaceImplementation(IPersistOptionType.Value); + // not sure why AssemblyBuilder is a baby true IL code doesn't define interface impelmentations that are just inherited + var persist_get = classBuilder.DefineMethod("get_" + nameof(DoNotPersist), MethodAttributes.Virtual | MethodAttributes.Public, typeof(bool), Type.EmptyTypes); + var il = persist_get.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.EmitCall(OpCodes.Callvirt, ourType.GetMethod(persist_get.Name), null); + il.Emit(OpCodes.Ret); + + + classBuilder.DefineMethodOverride(persist_get, IPersistOptionType.Value.GetMethod(persist_get.Name)); + + var constructorArgTypes = new[] { typeof(ILaunchProfile) }; + var constructor = classBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, constructorArgTypes); + var baseConstructor = ourType.GetConstructor(constructorArgTypes); + il = constructor.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Call, baseConstructor); + il.Emit(OpCodes.Nop); + il.Emit(OpCodes.Nop); + il.Emit(OpCodes.Ret); + var DynamicWritableLaunchProfileType = classBuilder.CreateType(); + var constructorInfo = DynamicWritableLaunchProfileType.GetConstructor(constructorArgTypes); + var instanceParam = Expression.Parameter(typeof(ILaunchProfile)); + var expr = Expression.TypeAs(Expression.New(constructorInfo, instanceParam), ourType); + getWritableProfileFunc = Expression.Lambda>(expr, instanceParam).Compile(); + + } + if (IPersistOptionType.Value != null) + return getWritableProfileFunc(profile); +#endif + return new WritableLaunchProfile(profile); + + + } + } } diff --git a/SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj b/SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj index 64f93861..e5231ff6 100644 --- a/SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj +++ b/SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj @@ -32,7 +32,7 @@ full false bin\Debug\ - TRACE;DEBUG;VS17 + TRACE;DEBUG;VS17;DYNAMIC_VSProjectManaged prompt 4 @@ -99,15 +99,28 @@ 7.0.0 - - 17.11.1.102 - runtime; build; native; contentfiles; analyzers; buildtransitive all + + + + + 2.0.6142705 + + + + + + + 17.11.1.102 + + + + CmdArgsPackage.vsct diff --git a/SmartCmdArgs/SmartCmdArgs17/source.extension.cs b/SmartCmdArgs/SmartCmdArgs17/source.extension.cs index 70e0ee5e..9cda4c0a 100644 --- a/SmartCmdArgs/SmartCmdArgs17/source.extension.cs +++ b/SmartCmdArgs/SmartCmdArgs17/source.extension.cs @@ -1,18 +1,18 @@ -// ------------------------------------------------------------------------------ -// -// This file was generated by VSIX Synchronizer -// -// ------------------------------------------------------------------------------ -namespace SmartCmdArgs -{ - internal sealed partial class Vsix - { - public const string Id = "SmartCmdArgs17.6edd462d-d4d6-40b9-a7b4-451a6ce6c527"; - public const string Name = "Smart Command Line Arguments VS2022"; - public const string Description = @"A Visual Studio 2022 Extension which aims to provide a better UI to manage your command line arguments."; - public const string Language = "en-US"; +// ------------------------------------------------------------------------------ +// +// This file was generated by VSIX Synchronizer +// +// ------------------------------------------------------------------------------ +namespace SmartCmdArgs +{ + internal sealed partial class Vsix + { + public const string Id = "SmartCmdArgs17.6edd462d-d4d6-40b9-a7b4-451a6ce6c527"; + public const string Name = "Smart Command Line Arguments VS2022"; + public const string Description = @"A Visual Studio 2022 Extension which aims to provide a better UI to manage your command line arguments."; + public const string Language = "en-US"; public const string Version = "3.2.0.1"; - public const string Author = "Irame & MBulli"; - public const string Tags = "Commandline Command Line Arguments cmd project"; - } -} + public const string Author = "Irame & MBulli"; + public const string Tags = "Commandline Command Line Arguments cmd project"; + } +} From eb98c2707559ab2060df7f0f1a923a39b2421d7f Mon Sep 17 00:00:00 2001 From: Mitch Capper Date: Sat, 24 Aug 2024 09:34:43 -0700 Subject: [PATCH 3/7] Use LaunchProfiles capability detection rather than just CPS Not all CPS projects support launch profiles --- SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs | 2 +- .../SmartCmdArgs.Shared/Services/ItemAggregationService.cs | 2 +- .../Services/OptionsSettingsEventHandlingService.cs | 2 +- .../SmartCmdArgs.Shared/Services/ProjectConfigService.cs | 2 +- .../Services/VisualStudioHelperService.cs | 2 +- .../SmartCmdArgs.Shared/Wrapper/IVsHierarchyWrapper.cs | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs b/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs index a85d4c2c..f78d4091 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs @@ -265,7 +265,7 @@ public List GetLaunchProfiles(Guid projGuid) var project = vsHelper.HierarchyForProjectGuid(projGuid); List launchProfiles = null; - if (project?.IsCpsProject() == true) + if (project?.SupportsLaunchProfiles() == true) { launchProfiles = cpsProjectConfigService.GetLaunchProfileNames(project.GetProject())?.ToList(); } diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/ItemAggregationService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/ItemAggregationService.cs index d85a6453..d275177b 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/ItemAggregationService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/ItemAggregationService.cs @@ -53,7 +53,7 @@ private TResult AggregateComamndLineItemsForProject(IVsHierarchyWrapper string projPlatform = projectObj?.ConfigurationManager?.ActiveConfiguration?.PlatformName; string activeLaunchProfile = null; - if (project.IsCpsProject()) + if (project.SupportsLaunchProfiles()) activeLaunchProfile = cpsProjectConfigService.GetActiveLaunchProfileName(projectObj); TResult JoinContainer(CmdContainer con) diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs index f4d85e85..b38fa185 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs @@ -126,7 +126,7 @@ private void UseSolutionDirChanged() } private void UseCpsVirtualProfileChanged() { - foreach (var project in vsHelper.GetSupportedProjects().Where(x => x.IsCpsProject())) + foreach (var project in vsHelper.GetSupportedProjects().Where(x => x.SupportsLaunchProfiles())) { projectConfigService.UpdateProjectConfig(project); cpsProjectConfigService.SetActiveLaunchProfileToVirtualProfile(project.GetProject()); diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/ProjectConfigService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/ProjectConfigService.cs index b7d4b2a4..44f545dc 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/ProjectConfigService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/ProjectConfigService.cs @@ -733,7 +733,7 @@ public bool IsSupportedProject(IVsHierarchyWrapper project) private bool TryGetProjectConfigHandlers(IVsHierarchyWrapper project, out ProjectConfigHandlers handler) { - if (project.IsCpsProject()) + if (project.SupportsLaunchProfiles()) { handler = cpsProjectConfigHandlers; return true; diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/VisualStudioHelperService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/VisualStudioHelperService.cs index 9751676f..b3e1ae2a 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/VisualStudioHelperService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/VisualStudioHelperService.cs @@ -129,7 +129,7 @@ public ProjectState(IVsHierarchyWrapper pHierarchy, ICpsProjectConfigService cps ProjectName = pHierarchy.GetName(); IsLoaded = pHierarchy.IsLoaded(); - if (pHierarchy.IsCpsProject()) + if (pHierarchy.SupportsLaunchProfiles()) _launchSettingsChangeListenerDisposable = cpsProjectConfigService.ListenToLaunchProfileChanges(pHierarchy.GetProject(), launchProfileChangeAction); } diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Wrapper/IVsHierarchyWrapper.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Wrapper/IVsHierarchyWrapper.cs index 438fffe5..3279abef 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Wrapper/IVsHierarchyWrapper.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Wrapper/IVsHierarchyWrapper.cs @@ -23,7 +23,7 @@ public interface IVsHierarchyWrapper string GetName(); Project GetProject(); string GetProjectDir(); - bool IsCpsProject(); + bool SupportsLaunchProfiles(); bool IsSharedAssetsProject(); bool IsLoaded(); bool TryGetIconMoniker(out ImageMoniker iconMoniker); @@ -81,9 +81,9 @@ public Project GetProject() /// see: https://github.com/dotnet/project-system /// see: https://github.com/Microsoft/VSProjectSystem/blob/master/doc/automation/detect_whether_a_project_is_a_CPS_project.md /// - public bool IsCpsProject() + public bool SupportsLaunchProfiles() { - return hierarchy.IsCapabilityMatch("CPS"); + return hierarchy.IsCapabilityMatch("LaunchProfiles"); // https://github.com/Microsoft/VSProjectSystem/blob/master/doc/overview/project_capabilities.md not all cps projects support profiles https://github.com/microsoft/service-fabric-issues/issues/1095 } public bool IsSharedAssetsProject() From 199a530e9a8bb189e826b94bf2af3807ecb69d9e Mon Sep 17 00:00:00 2001 From: Mitch Capper Date: Sat, 24 Aug 2024 09:45:49 -0700 Subject: [PATCH 4/7] slight dep package version tweaks, default to non-reflective build sdk/buildtools from 17.5 to 17.9, lower ProjectSystem.Managed to 17.7 --- SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj b/SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj index e5231ff6..afbcee96 100644 --- a/SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj +++ b/SmartCmdArgs/SmartCmdArgs17/SmartCmdArgs17.csproj @@ -32,7 +32,7 @@ full false bin\Debug\ - TRACE;DEBUG;VS17;DYNAMIC_VSProjectManaged + TRACE;DEBUG;VS17;DYNAMIC-DISABLED_VSProjectManaged prompt 4 @@ -99,8 +99,8 @@ 7.0.0 - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -108,6 +108,9 @@ + + 17.9.380 + 2.0.6142705 @@ -116,7 +119,7 @@ - 17.11.1.102 + 17.7.37.99 From 85d85de4e6193dd17284b73671339dc91a61677a Mon Sep 17 00:00:00 2001 From: Mitch Capper Date: Sat, 24 Aug 2024 13:20:40 -0700 Subject: [PATCH 5/7] version bump and test update for SupportsLaunchProfiles --- SmartCmdArgs/SmartCmdArgs17/source.extension.vsixmanifest | 1 + SmartCmdArgs/Testing/SmartCmdArgs.Tests/Utils/Extensions.cs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/SmartCmdArgs/SmartCmdArgs17/source.extension.vsixmanifest b/SmartCmdArgs/SmartCmdArgs17/source.extension.vsixmanifest index 80d0e0e0..7597ca05 100644 --- a/SmartCmdArgs/SmartCmdArgs17/source.extension.vsixmanifest +++ b/SmartCmdArgs/SmartCmdArgs17/source.extension.vsixmanifest @@ -9,6 +9,7 @@ Resources\BigIcon.png Resources\vsix_preview_image.png Commandline Command Line Arguments cmd project + true diff --git a/SmartCmdArgs/Testing/SmartCmdArgs.Tests/Utils/Extensions.cs b/SmartCmdArgs/Testing/SmartCmdArgs.Tests/Utils/Extensions.cs index ad819059..af0d4f9c 100644 --- a/SmartCmdArgs/Testing/SmartCmdArgs.Tests/Utils/Extensions.cs +++ b/SmartCmdArgs/Testing/SmartCmdArgs.Tests/Utils/Extensions.cs @@ -1,4 +1,4 @@ -using Microsoft.VisualStudio; +using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell.Interop; using Moq; using SmartCmdArgs.Services; @@ -35,7 +35,7 @@ public static Mock WithGuid(this Mock public static Mock AsCpsProject(this Mock mock) { - mock.Setup(x => x.IsCpsProject()).Returns(true); + mock.Setup(x => x.SupportsLaunchProfiles()).Returns(true); return mock; } From 697fea1fbd873fc71de7dde9457e0d90afecb53b Mon Sep 17 00:00:00 2001 From: Mitch Capper Date: Mon, 13 Jan 2025 10:44:43 -0800 Subject: [PATCH 6/7] Better control on when to set us active, and fixes the VS virtual profile bug --- .../SmartCmdArgs.Shared/CmdArgsOptionPage.cs | 25 ++++++++++++++++ .../Helper/CpsProjectConfigService.cs | 30 ++++++++++++++++--- .../OptionsSettingsEventHandlingService.cs | 2 +- .../Services/OptionsSettingsService.cs | 2 ++ .../Services/ProjectConfigService.cs | 30 +++++++++++-------- .../Services/TreeViewEventHandlingService.cs | 2 +- .../Services/VsEventHandlingService.cs | 2 +- .../ViewModel/ToolWindowViewModel.cs | 9 +++++- 8 files changed, 81 insertions(+), 21 deletions(-) diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs b/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs index d279c559..5661d75c 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.Shell; using SmartCmdArgs.Helper; +using System; using System.ComponentModel; using System.Linq; using System.Reflection; @@ -45,6 +46,19 @@ public enum EnableBehaviour [Description("Enable by default (old behaviour)")] EnableByDefault, } + [Flags] + [TypeConverter(typeof(EnumDescriptionTypeConverter))] + public enum SetActiveProfileBehavior + { + [Description("Never, due to a bug in virtual profiles you will have to reselect Smart CLI Args every time you open a project")] + Never = 1 << 0, + [Description("On Smart CLI Arg tree changed (ie option checked)")] + OnTreeChanged = 1 << 1, + [Description("On first run/debug")] + OnRun = 1 << 2, + [Description("On Smart CLI Arg option checked or first run/debug")] + OnCheckedOrRun = OnTreeChanged | OnRun + } public class CmdArgsOptionPage : DialogPage, INotifyPropertyChanged { @@ -64,6 +78,7 @@ public CmdArgsOptionPage() : base() } private EnableBehaviour _enableBehaviour; + private SetActiveProfileBehavior _setActiveProfileBehavior; private RelativePathRootOption _relativePathRoot; private bool _useMonospaceFont; @@ -92,6 +107,16 @@ public EnableBehaviour EnableBehaviour set => SetAndNotify(value, ref _enableBehaviour); } + [Category("Settings Defaults")] + [DisplayName("Set Active Profile Behavior")] + [Description("When we should automatically make ourselves the active profile")] + [DefaultValue(SetActiveProfileBehavior.OnTreeChanged)] + public SetActiveProfileBehavior SetActiveProfileBehavior + { + get => _setActiveProfileBehavior; + set => SetAndNotify(value, ref _setActiveProfileBehavior); + } + [Category("General")] [DisplayName("Relative path root")] [Description("Sets the base path that is used to resolve relative paths for the open/reveal file/folder context menu option.")] diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectConfigService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectConfigService.cs index ca7e2fca..1de94293 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectConfigService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectConfigService.cs @@ -35,7 +35,7 @@ public interface ICpsProjectConfigService IDisposable ListenToLaunchProfileChanges(Project project, Action listener); void SetActiveLaunchProfileByName(Project project, string profileName); void SetActiveLaunchProfileToVirtualProfile(Project project); - void SetConfig(Project project, string arguments, IDictionary envVars, string workDir, string launchApp); + void SetConfig(Project project, string arguments, IDictionary envVars, string workDir, string launchApp, UpdateProjectConfigReason reason); } public class CpsProjectConfigService : ICpsProjectConfigService @@ -134,7 +134,7 @@ public IDisposable ListenToLaunchProfileChanges(EnvDTE.Project project, Action l return null; } - public void SetConfig(EnvDTE.Project project, string arguments, IDictionary envVars, string workDir, string launchApp) + public void SetConfig(EnvDTE.Project project, string arguments, IDictionary envVars, string workDir, string launchApp, UpdateProjectConfigReason reason) { IUnconfiguredProjectServices unconfiguredProjectServices; IProjectServices projectServices; @@ -143,6 +143,7 @@ public void SetConfig(EnvDTE.Project project, string arguments, IDictionary(); ILaunchProfile baseLaunchProfile = null; + var applyProfileFix=true; if (optionsSettingsService.UseCpsVirtualProfile) { baseLaunchProfile = launchSettingsProvider.CurrentSnapshot.Profiles.FirstOrDefault(x => x.Name == VirtualProfileName); @@ -152,7 +153,12 @@ public void SetConfig(EnvDTE.Project project, string arguments, IDictionary + + projectServices.ThreadingPolicy.ExecuteSynchronously(async () => { - return launchSettingsProvider.AddOrUpdateProfileAsync(writableLaunchProfile, addToFront: false); + + if (applyProfileFix){ + var activeProfile = launchSettingsProvider.ActiveProfile?.Name; + if (! String.IsNullOrWhiteSpace( activeProfile)) + await launchSettingsProvider.SetActiveProfileAsync(activeProfile); + } + + await launchSettingsProvider.AddOrUpdateProfileAsync(writableLaunchProfile, addToFront: false); + if (setActiveProfile) + await launchSettingsProvider.SetActiveProfileAsync(writableLaunchProfile.Name); + }); } } @@ -340,4 +361,5 @@ internal static WritableLaunchProfile GetWritableLaunchProfile(ILaunchProfile pr } } + } diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs index b38fa185..5d2ec0f5 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs @@ -128,7 +128,7 @@ private void UseCpsVirtualProfileChanged() { foreach (var project in vsHelper.GetSupportedProjects().Where(x => x.SupportsLaunchProfiles())) { - projectConfigService.UpdateProjectConfig(project); + projectConfigService.UpdateProjectConfig(project, UpdateProjectConfigReason.UseVirtualProfileChanged); cpsProjectConfigService.SetActiveLaunchProfileToVirtualProfile(project.GetProject()); } } diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsService.cs index e1e61d54..1911f967 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsService.cs @@ -30,6 +30,7 @@ public interface IOptionsSettingsService bool DeleteEmptyFilesAutomatically { get; } bool DeleteUnnecessaryFilesAutomatically { get; } EnableBehaviour EnableBehaviour { get; } + SetActiveProfileBehavior SetActiveProfileBehavior { get; } InactiveDisableMode DisableInactiveItems { get; } RelativePathRootOption RelativePathRoot { get; } @@ -77,6 +78,7 @@ public OptionsSettingsService( #endif public bool UseMonospaceFont => OptionsPage.UseMonospaceFont; public bool DisplayTagForCla => OptionsPage.DisplayTagForCla; + public SetActiveProfileBehavior SetActiveProfileBehavior => OptionsPage.SetActiveProfileBehavior; public bool DeleteEmptyFilesAutomatically => OptionsPage.DeleteEmptyFilesAutomatically; public bool DeleteUnnecessaryFilesAutomatically => OptionsPage.DeleteUnnecessaryFilesAutomatically; public EnableBehaviour EnableBehaviour => OptionsPage.EnableBehaviour; diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/ProjectConfigService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/ProjectConfigService.cs index 44f545dc..89ea8ddc 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/ProjectConfigService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/ProjectConfigService.cs @@ -8,13 +8,16 @@ namespace SmartCmdArgs.Services { + public enum UpdateProjectConfigReason{ RunDebugLaunch, TreeChange,UseVirtualProfileChanged } public interface IProjectConfigService { bool IsSupportedProject(IVsHierarchyWrapper project); List GetItemsFromProjectConfig(IVsHierarchyWrapper project); - void UpdateProjectConfig(IVsHierarchyWrapper project); + void UpdateProjectConfig(IVsHierarchyWrapper project, UpdateProjectConfigReason reason); + + } public class ProjectConfigService : IProjectConfigService @@ -48,7 +51,7 @@ public ProjectConfigService( private class ProjectConfigHandlers { - public delegate void SetConfigDelegate(EnvDTE.Project project, string arguments, IDictionary envVars, string workDir, string launchApp); + public delegate void SetConfigDelegate(EnvDTE.Project project, string arguments, IDictionary envVars, string workDir, string launchApp, UpdateProjectConfigReason reason); public delegate void GetAllArgumentsDelegate(EnvDTE.Project project, List allArgs, bool includeArgs, bool includeEnvVars, bool includeWorkDir, bool includeLaunchApp); public SetConfigDelegate SetConfig; public GetAllArgumentsDelegate GetItemsFromConfig; @@ -59,7 +62,7 @@ private Dictionary InitConfigHandlerForSupportedPro { // C# {ProjectKinds.CS, new ProjectConfigHandlers() { - SetConfig = (project, arguments, envVars, workDir, launchApp) => { + SetConfig = (project, arguments, envVars, workDir, launchApp, reason) => { SetMultiConfigProperty(project, arguments, "StartArguments"); SetMultiConfigProperty(project, workDir, "StartWorkingDirectory"); SetMultiConfigProperty(project, launchApp, "StartProgram"); @@ -68,13 +71,13 @@ private Dictionary InitConfigHandlerForSupportedPro } }, // C# UWP {ProjectKinds.CS_UWP, new ProjectConfigHandlers() { - SetConfig = (project, arguments, envVars, workDir, launchApp) => SetMultiConfigProperty(project, arguments, "UAPDebug.CommandLineArguments"), + SetConfig = (project, arguments, envVars, workDir, launchApp, reason) => SetMultiConfigProperty(project, arguments, "UAPDebug.CommandLineArguments"), GetItemsFromConfig = GetItemsFromMultiConfig("UAPDebug.CommandLineArguments") } }, // VB.NET {ProjectKinds.VB, new ProjectConfigHandlers() { - SetConfig = (project, arguments, _, workDir, launchApp) => { + SetConfig = (project, arguments, _, workDir, launchApp, reason) => { SetMultiConfigProperty(project, arguments, "StartArguments"); SetMultiConfigProperty(project, workDir, "StartWorkingDirectory"); SetMultiConfigProperty(project, launchApp, "StartProgram"); @@ -88,7 +91,7 @@ private Dictionary InitConfigHandlerForSupportedPro } }, // Python {ProjectKinds.Py, new ProjectConfigHandlers() { - SetConfig = (project, arguments, envVars, workDir, _) => { + SetConfig = (project, arguments, envVars, workDir, _, reason) => { SetSingleConfigProperty(project, arguments, "CommandLineArguments"); SetSingleConfigEnvVars(project, envVars, "Environment"); SetSingleConfigProperty(project, workDir, "WorkingDirectory"); @@ -97,7 +100,7 @@ private Dictionary InitConfigHandlerForSupportedPro } }, // Node.js {ProjectKinds.Node, new ProjectConfigHandlers() { - SetConfig = (project, arguments, envVars, workDir, _) => { + SetConfig = (project, arguments, envVars, workDir, _, reason) => { SetSingleConfigProperty(project, arguments, "ScriptArguments"); SetSingleConfigEnvVars(project, envVars, "Environment"); SetSingleConfigProperty(project, workDir, "WorkingDirectory"); @@ -111,7 +114,7 @@ private Dictionary InitConfigHandlerForSupportedPro } }, // F# {ProjectKinds.FS, new ProjectConfigHandlers() { - SetConfig = (project, arguments, _, workDir, launchApp) => { + SetConfig = (project, arguments, _, workDir, launchApp, reason) => { SetMultiConfigProperty(project, arguments, "StartArguments"); SetMultiConfigProperty(project, workDir, "StartWorkingDirectory"); SetMultiConfigProperty(project, launchApp, "StartProgram"); @@ -377,7 +380,7 @@ private static ProjectConfigHandlers.GetAllArgumentsDelegate GetItemsFromMultiCo ("AppHostLocalDebugger", "CommandLineArgs", null, null, null), }; - private static void SetVCProjEngineConfig(EnvDTE.Project project, string arguments, IDictionary envVars, string workDir, string launchApp) + private static void SetVCProjEngineConfig(EnvDTE.Project project, string arguments, IDictionary envVars, string workDir, string launchApp, UpdateProjectConfigReason reason) { ThreadHelper.ThrowIfNotOnUIThread(); @@ -591,7 +594,7 @@ private static string VFFormatConfigName(EnvDTE.Configuration vcCfg) // to optain the right configurations object from `Project.Object.Configurations` // this object is simmilar to the VCProjEngine configuration and has `DebugSettings` // which contain the CommandArguments which we can use to set the args. - private static void SetVFProjEngineConfig(EnvDTE.Project project, string arguments, IDictionary envVars, string workDir, string launchApp) + private static void SetVFProjEngineConfig(EnvDTE.Project project, string arguments, IDictionary envVars, string workDir, string launchApp, UpdateProjectConfigReason reason) { ThreadHelper.ThrowIfNotOnUIThread(); @@ -773,7 +776,7 @@ public List GetItemsFromProjectConfig(IVsHierarchyWrapper project) return result; } - public void UpdateProjectConfig(IVsHierarchyWrapper project) + public void UpdateProjectConfig(IVsHierarchyWrapper project, UpdateProjectConfigReason reason) { if (!lifeCycleService.Value.IsEnabled || project == null) return; @@ -788,10 +791,11 @@ public void UpdateProjectConfig(IVsHierarchyWrapper project) if (TryGetProjectConfigHandlers(project, out ProjectConfigHandlers handler)) { - handler.SetConfig(project.GetProject(), commandLineArgs, envVars, workDir, launchApp); + handler.SetConfig(project.GetProject(), commandLineArgs, envVars, workDir, launchApp, reason); + } - Logger.Info($"Updated Configuration for Project: {project.GetName()}"); + Logger.Info($"Updated Configuration for Project: {project.GetName()} command line: {commandLineArgs}"); } } diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/TreeViewEventHandlingService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/TreeViewEventHandlingService.cs index acedeeb1..3ab878b5 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/TreeViewEventHandlingService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/TreeViewEventHandlingService.cs @@ -86,7 +86,7 @@ private void OnTreeChangedThrottled(object sender, TreeViewModel.TreeChangedEven { var projectGuid = e.AffectedProject.Id; var project = vsHelper.HierarchyForProjectGuid(projectGuid); - projectConfigService.UpdateProjectConfig(project); + projectConfigService.UpdateProjectConfig(project, UpdateProjectConfigReason.TreeChange); } private void OnTreeChanged(object sender, TreeViewModel.TreeChangedEventArgs e) diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/Services/VsEventHandlingService.cs b/SmartCmdArgs/SmartCmdArgs.Shared/Services/VsEventHandlingService.cs index 23afe764..70613744 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/Services/VsEventHandlingService.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/Services/VsEventHandlingService.cs @@ -140,7 +140,7 @@ private void VsHelper_ProjectWillRun(object sender, EventArgs e) foreach (var startupProject in treeViewModel.StartupProjects) { var project = vsHelper.HierarchyForProjectGuid(startupProject.Id); - projectConfigService.UpdateProjectConfig(project); + projectConfigService.UpdateProjectConfig(project, UpdateProjectConfigReason.RunDebugLaunch); fileStorage.SaveProject(project); } } diff --git a/SmartCmdArgs/SmartCmdArgs.Shared/ViewModel/ToolWindowViewModel.cs b/SmartCmdArgs/SmartCmdArgs.Shared/ViewModel/ToolWindowViewModel.cs index 7e657d93..7ce9d92d 100644 --- a/SmartCmdArgs/SmartCmdArgs.Shared/ViewModel/ToolWindowViewModel.cs +++ b/SmartCmdArgs/SmartCmdArgs.Shared/ViewModel/ToolWindowViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -36,6 +36,13 @@ public bool DisplayTagForCla set => SetAndNotify(value, ref _displayTagForCla); } + private SetActiveProfileBehavior _setActiveProfileBehavior; + public SetActiveProfileBehavior SetActiveProfileBehavior + { + get => _setActiveProfileBehavior; + set => SetAndNotify(value, ref _setActiveProfileBehavior); + } + private bool _showDisabledScreen; public bool ShowDisabledScreen { From b9329d74da687d811a2956eef583e04e2ee1ce0a Mon Sep 17 00:00:00 2001 From: Mitch Capper Date: Fri, 31 Jan 2025 23:18:00 -0800 Subject: [PATCH 7/7] Basic editor config for formatting --- .editorconfig | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..93ecaf3b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference +[*] + +#Our EditorConfig + + +indent_style = space +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 + +[*.cs] +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +