Skip to content

Commit b346dc2

Browse files
committed
Reimplementation of in memory profile support
#151 and #147
1 parent 5f5fcaa commit b346dc2

11 files changed

Lines changed: 390 additions & 292 deletions

SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsOptionPage.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Microsoft.VisualStudio.Shell;
1+
using Microsoft.VisualStudio.Shell;
22
using SmartCmdArgs.Helper;
33
using System.ComponentModel;
44
using System.Linq;
@@ -78,6 +78,7 @@ public CmdArgsOptionPage() : base()
7878
private bool _manageWorkingDirectories;
7979
private bool _manageLaunchApplication;
8080
private bool _vcsSupportEnabled;
81+
private bool _useCpsVirtualProfile;
8182
private bool _useSolutionDir;
8283
private bool _macroEvaluationEnabled;
8384

@@ -111,6 +112,7 @@ public bool UseMonospaceFont
111112
set => SetAndNotify(value, ref _useMonospaceFont);
112113
}
113114

115+
114116
[Category("Appearance")]
115117
[DisplayName("Display Tags for CLAs")]
116118
[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
201203
set => SetAndNotify(value, ref _vcsSupportEnabled);
202204
}
203205

206+
[Category("Settings Defaults")]
207+
[DisplayName("Use CPS Virtual Profile")]
208+
[Description("If enabled a virtual profile is created for CPS projects and only this profile is changed by the extension.")]
209+
[DefaultValue(false)]
210+
public bool UseCpsVirtualProfile
211+
{
212+
get => _useCpsVirtualProfile;
213+
set => SetAndNotify(value, ref _useCpsVirtualProfile);
214+
}
215+
204216
[Category("Settings Defaults")]
205217
[DisplayName("Use Solution Directory")]
206218
[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)")]

SmartCmdArgs/SmartCmdArgs.Shared/CmdArgsPackage.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//------------------------------------------------------------------------------
1+
//------------------------------------------------------------------------------
22
// <copyright file="CmdArgsPackage.cs" company="Company">
33
// Copyright (c) Company. All rights reserved.
44
// </copyright>
@@ -69,7 +69,8 @@ public sealed class CmdArgsPackage : AsyncPackage
6969
private ISuoDataService suoDataService;
7070
private ILifeCycleService lifeCycleService;
7171
private IVsEventHandlingService vsEventHandling;
72-
private IFileStorageEventHandlingService fileStorageEventHandling;
72+
private IFileStorageEventHandlingService fileStorageEventHandling;
73+
private ICpsProjectConfigService cpsProjectConfigService;
7374

7475
private ToolWindowViewModel toolWindowViewModel;
7576
private TreeViewModel treeViewModel;
@@ -105,7 +106,8 @@ public CmdArgsPackage()
105106
suoDataService = ServiceProvider.GetRequiredService<ISuoDataService>();
106107
lifeCycleService = ServiceProvider.GetRequiredService<ILifeCycleService>();
107108
vsEventHandling = ServiceProvider.GetRequiredService<IVsEventHandlingService>();
108-
fileStorageEventHandling = ServiceProvider.GetRequiredService<IFileStorageEventHandlingService>();
109+
fileStorageEventHandling = ServiceProvider.GetRequiredService<IFileStorageEventHandlingService>();
110+
cpsProjectConfigService = ServiceProvider.GetRequiredService<ICpsProjectConfigService>();
109111
}
110112

111113
protected override void Dispose(bool disposing)
@@ -170,7 +172,8 @@ private ServiceProvider ConfigureServices()
170172
services.AddLazySingleton(x => GetDialogPage<CmdArgsOptionPage>());
171173
services.AddLazySingleton<SettingsViewModel>();
172174
services.AddLazySingleton<ToolWindowViewModel>();
173-
services.AddLazySingleton<TreeViewModel>();
175+
services.AddLazySingleton<TreeViewModel>();
176+
services.AddLazySingleton<ICpsProjectConfigService, CpsProjectConfigService>();
174177
services.AddLazySingleton<IProjectConfigService, ProjectConfigService>();
175178
services.AddSingleton<IVisualStudioHelperService, VisualStudioHelperService>();
176179
services.AddSingleton<IFileStorageService, FileStorageService>();
@@ -264,7 +267,7 @@ public List<string> GetLaunchProfiles(Guid projGuid)
264267
List<string> launchProfiles = null;
265268
if (project?.IsCpsProject() == true)
266269
{
267-
launchProfiles = CpsProjectSupport.GetLaunchProfileNames(project.GetProject())?.ToList();
270+
launchProfiles = cpsProjectConfigService.GetLaunchProfileNames(project.GetProject())?.ToList();
268271
}
269272

270273
return launchProfiles ?? new List<string>();

SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectSupport.cs renamed to SmartCmdArgs/SmartCmdArgs.Shared/Helper/CpsProjectConfigService.cs

Lines changed: 82 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.VisualStudio.ProjectSystem;
1+
using EnvDTE;
2+
using Microsoft.VisualStudio.ProjectSystem;
23
using Microsoft.VisualStudio.ProjectSystem.Debug;
34
using Microsoft.VisualStudio.ProjectSystem.Properties;
45
using SmartCmdArgs.DataSerialization;
@@ -19,11 +20,32 @@
1920
// As such, ensuring compatibility requires knowledge of the version Visual Studio redirects to, which varies
2021
// by Visual Studio installation version.
2122

22-
namespace SmartCmdArgs.Helper
23+
namespace SmartCmdArgs.Services
2324
{
24-
public static class CpsProjectSupport
25+
public interface ICpsProjectConfigService
2526
{
26-
private static bool TryGetProjectServices(EnvDTE.Project project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices)
27+
string GetActiveLaunchProfileName(Project project);
28+
void GetItemsFromConfig(Project project, List<CmdItemJson> allArgs, bool includeArgs, bool includeEnvVars, bool includeWorkDir, bool includeLaunchApp);
29+
IEnumerable<string> GetLaunchProfileNames(Project project);
30+
IDisposable ListenToLaunchProfileChanges(Project project, Action listener);
31+
void SetActiveLaunchProfileByName(Project project, string profileName);
32+
void SetActiveLaunchProfileToVirtualProfile(Project project);
33+
void SetConfig(Project project, string arguments, IDictionary<string, string> envVars, string workDir, string launchApp);
34+
}
35+
36+
public class CpsProjectConfigService : ICpsProjectConfigService
37+
{
38+
public static string VirtualProfileName = "Smart CLI Args";
39+
40+
private readonly IOptionsSettingsService optionsSettingsService;
41+
42+
public CpsProjectConfigService(
43+
IOptionsSettingsService optionsSettingsService)
44+
{
45+
this.optionsSettingsService = optionsSettingsService;
46+
}
47+
48+
private bool TryGetProjectServices(EnvDTE.Project project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices)
2749
{
2850
IVsBrowseObjectContext context = project as IVsBrowseObjectContext;
2951
if (context == null && project != null)
@@ -55,7 +77,7 @@ private static bool TryGetProjectServices(EnvDTE.Project project, out IUnconfigu
5577
}
5678
}
5779

58-
public static string GetActiveLaunchProfileName(EnvDTE.Project project)
80+
public string GetActiveLaunchProfileName(EnvDTE.Project project)
5981
{
6082
if (TryGetProjectServices(project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices))
6183
{
@@ -65,7 +87,21 @@ public static string GetActiveLaunchProfileName(EnvDTE.Project project)
6587
return null;
6688
}
6789

68-
public static IEnumerable<string> GetLaunchProfileNames(EnvDTE.Project project)
90+
public void SetActiveLaunchProfileByName(EnvDTE.Project project, string profileName)
91+
{
92+
if (TryGetProjectServices(project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices))
93+
{
94+
var launchSettingsProvider = unconfiguredProjectServices.ExportProvider.GetExportedValue<ILaunchSettingsProvider>();
95+
projectServices.ThreadingPolicy.ExecuteSynchronously(async () =>
96+
{
97+
await launchSettingsProvider.SetActiveProfileAsync(profileName);
98+
});
99+
}
100+
}
101+
102+
public void SetActiveLaunchProfileToVirtualProfile(EnvDTE.Project project) => SetActiveLaunchProfileByName(project, VirtualProfileName);
103+
104+
public IEnumerable<string> GetLaunchProfileNames(EnvDTE.Project project)
69105
{
70106
if (TryGetProjectServices(project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices))
71107
{
@@ -75,10 +111,11 @@ public static IEnumerable<string> GetLaunchProfileNames(EnvDTE.Project project)
75111
return null;
76112
}
77113

78-
public static IDisposable ListenToLaunchProfileChanges(EnvDTE.Project project, Action listener)
114+
public IDisposable ListenToLaunchProfileChanges(EnvDTE.Project project, Action listener)
79115
{
80116
if (TryGetProjectServices(project, out IUnconfiguredProjectServices unconfiguredProjectServices, out IProjectServices projectServices))
81117
{
118+
82119
var launchSettingsProvider = unconfiguredProjectServices.ExportProvider.GetExportedValue<ILaunchSettingsProvider>();
83120

84121
if (launchSettingsProvider == null)
@@ -92,20 +129,29 @@ public static IDisposable ListenToLaunchProfileChanges(EnvDTE.Project project, A
92129
return null;
93130
}
94131

95-
public static void SetCpsProjectConfig(EnvDTE.Project project, string arguments, IDictionary<string, string> envVars, string workDir, string launchApp)
132+
public void SetConfig(EnvDTE.Project project, string arguments, IDictionary<string, string> envVars, string workDir, string launchApp)
96133
{
97134
IUnconfiguredProjectServices unconfiguredProjectServices;
98135
IProjectServices projectServices;
99136

100137
if (TryGetProjectServices(project, out unconfiguredProjectServices, out projectServices))
101138
{
102139
var launchSettingsProvider = unconfiguredProjectServices.ExportProvider.GetExportedValue<ILaunchSettingsProvider>();
103-
var activeLaunchProfile = launchSettingsProvider?.ActiveProfile;
140+
ILaunchProfile baseLaunchProfile = null;
141+
if (optionsSettingsService.UseCpsVirtualProfile)
142+
{
143+
baseLaunchProfile = launchSettingsProvider.CurrentSnapshot.Profiles.FirstOrDefault(x => x.Name == VirtualProfileName);
144+
}
104145

105-
if (activeLaunchProfile == null)
146+
if (baseLaunchProfile == null)
147+
{
148+
baseLaunchProfile = launchSettingsProvider?.ActiveProfile;
149+
}
150+
151+
if (baseLaunchProfile == null)
106152
return;
107153

108-
WritableLaunchProfile writableLaunchProfile = new WritableLaunchProfile(activeLaunchProfile);
154+
WritableLaunchProfile writableLaunchProfile = new WritableLaunchProfile(baseLaunchProfile);
109155

110156
if (arguments != null)
111157
writableLaunchProfile.CommandLineArgs = arguments;
@@ -119,30 +165,31 @@ public static void SetCpsProjectConfig(EnvDTE.Project project, string arguments,
119165
if (launchApp != null)
120166
writableLaunchProfile.CommandName = launchApp;
121167

122-
// Does not work on VS2015, which should be okay ...
123-
// We don't hold references for VS2015, where the interface is called IThreadHandling
124-
IProjectThreadingService projectThreadingService = projectServices.ThreadingPolicy;
125-
projectThreadingService.ExecuteSynchronously(() =>
168+
if (optionsSettingsService.UseCpsVirtualProfile)
169+
{
170+
writableLaunchProfile.Name = VirtualProfileName;
171+
writableLaunchProfile.DoNotPersist = true;
172+
}
173+
174+
projectServices.ThreadingPolicy.ExecuteSynchronously(() =>
126175
{
127176
return launchSettingsProvider.AddOrUpdateProfileAsync(writableLaunchProfile, addToFront: false);
128177
});
129178
}
130179
}
131180

132-
public static List<CmdItemJson> GetCpsProjectAllArguments(EnvDTE.Project project, bool includeArgs, bool includeEnvVars, bool includeWorkDir, bool includeLaunchApp)
181+
public void GetItemsFromConfig(EnvDTE.Project project, List<CmdItemJson> allArgs, bool includeArgs, bool includeEnvVars, bool includeWorkDir, bool includeLaunchApp)
133182
{
134183
IUnconfiguredProjectServices unconfiguredProjectServices;
135184
IProjectServices projectServices;
136185

137-
var result = new List<CmdItemJson>();
138-
139186
if (TryGetProjectServices(project, out unconfiguredProjectServices, out projectServices))
140187
{
141188
var launchSettingsProvider = unconfiguredProjectServices.ExportProvider.GetExportedValue<ILaunchSettingsProvider>();
142189
var launchProfiles = launchSettingsProvider?.CurrentSnapshot?.Profiles;
143190

144191
if (launchProfiles == null)
145-
return result;
192+
return;
146193

147194
foreach (var profile in launchProfiles)
148195
{
@@ -173,17 +220,19 @@ public static List<CmdItemJson> GetCpsProjectAllArguments(EnvDTE.Project project
173220

174221
if (profileGrp.Items.Count > 0)
175222
{
176-
result.Add(profileGrp);
223+
allArgs.Add(profileGrp);
177224
}
178225
}
179226
}
180-
181-
return result;
182227
}
183228
}
184229

185230
class WritableLaunchProfile : ILaunchProfile
231+
#if VS17
232+
, IPersistOption
233+
#endif
186234
{
235+
// ILaunchProfile
187236
public string Name { set; get; }
188237
public string CommandName { set; get; }
189238
public string ExecutablePath { set; get; }
@@ -194,8 +243,12 @@ class WritableLaunchProfile : ILaunchProfile
194243
public ImmutableDictionary<string, string> EnvironmentVariables { set; get; }
195244
public ImmutableDictionary<string, object> OtherSettings { set; get; }
196245

246+
// IPersistOption
247+
public bool DoNotPersist { get; set; }
248+
197249
public WritableLaunchProfile(ILaunchProfile launchProfile)
198250
{
251+
// ILaunchProfile
199252
Name = launchProfile.Name;
200253
ExecutablePath = launchProfile.ExecutablePath;
201254
CommandName = launchProfile.CommandName;
@@ -205,6 +258,13 @@ public WritableLaunchProfile(ILaunchProfile launchProfile)
205258
LaunchUrl = launchProfile.LaunchUrl;
206259
EnvironmentVariables = launchProfile.EnvironmentVariables;
207260
OtherSettings = launchProfile.OtherSettings;
261+
#if VS17
262+
if (launchProfile is IPersistOption persistOptionLaunchProfile)
263+
{
264+
// IPersistOption
265+
DoNotPersist = persistOptionLaunchProfile.DoNotPersist;
266+
}
267+
#endif
208268
}
209269
}
210270
}

SmartCmdArgs/SmartCmdArgs.Shared/Services/ItemAggregationService.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using SmartCmdArgs.Helper;
1+
using SmartCmdArgs.Helper;
22
using SmartCmdArgs.ViewModel;
33
using SmartCmdArgs.Wrapper;
44
using System;
@@ -23,15 +23,19 @@ internal class ItemAggregationService : IItemAggregationService
2323
private readonly IItemEvaluationService itemEvaluation;
2424
private readonly IVisualStudioHelperService vsHelper;
2525
private readonly TreeViewModel treeViewModel;
26+
private readonly ICpsProjectConfigService cpsProjectConfigService;
27+
2628

2729
public ItemAggregationService(
2830
IItemEvaluationService itemEvaluation,
2931
IVisualStudioHelperService vsHelper,
30-
TreeViewModel treeViewModel)
32+
TreeViewModel treeViewModel,
33+
ICpsProjectConfigService cpsProjectConfigService)
3134
{
3235
this.itemEvaluation = itemEvaluation;
3336
this.vsHelper = vsHelper;
3437
this.treeViewModel = treeViewModel;
38+
this.cpsProjectConfigService = cpsProjectConfigService;
3539
}
3640

3741
private TResult AggregateComamndLineItemsForProject<TResult>(IVsHierarchyWrapper project, Func<IEnumerable<CmdBase>, Func<CmdContainer, TResult>, CmdContainer, TResult> joinItems)
@@ -50,7 +54,7 @@ private TResult AggregateComamndLineItemsForProject<TResult>(IVsHierarchyWrapper
5054

5155
string activeLaunchProfile = null;
5256
if (project.IsCpsProject())
53-
activeLaunchProfile = CpsProjectSupport.GetActiveLaunchProfileName(projectObj);
57+
activeLaunchProfile = cpsProjectConfigService.GetActiveLaunchProfileName(projectObj);
5458

5559
TResult JoinContainer(CmdContainer con)
5660
{

SmartCmdArgs/SmartCmdArgs.Shared/Services/OptionsSettingsEventHandlingService.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
using SmartCmdArgs.ViewModel;
1+
using SmartCmdArgs.ViewModel;
22
using System;
3+
using System.Linq;
34

45
namespace SmartCmdArgs.Services
56
{
@@ -18,6 +19,8 @@ internal class OptionsSettingsEventHandlingService : IOptionsSettingsEventHandli
1819
private readonly IViewModelUpdateService viewModelUpdateService;
1920
private readonly ToolWindowViewModel toolWindowViewModel;
2021
private readonly IToolWindowHistory toolWindowHistory;
22+
private readonly IProjectConfigService projectConfigService;
23+
private readonly ICpsProjectConfigService cpsProjectConfigService;
2124

2225
public OptionsSettingsEventHandlingService(
2326
IOptionsSettingsService optionsSettings,
@@ -26,7 +29,9 @@ public OptionsSettingsEventHandlingService(
2629
IVisualStudioHelperService vsHelper,
2730
IViewModelUpdateService viewModelUpdateService,
2831
ToolWindowViewModel toolWindowViewModel,
29-
IToolWindowHistory toolWindowHistory)
32+
IToolWindowHistory toolWindowHistory,
33+
IProjectConfigService projectConfigService,
34+
ICpsProjectConfigService cpsProjectConfigService)
3035
{
3136
this.optionsSettings = optionsSettings;
3237
this.settingsService = settingsService;
@@ -35,6 +40,8 @@ public OptionsSettingsEventHandlingService(
3540
this.viewModelUpdateService = viewModelUpdateService;
3641
this.toolWindowViewModel = toolWindowViewModel;
3742
this.toolWindowHistory = toolWindowHistory;
43+
this.projectConfigService = projectConfigService;
44+
this.cpsProjectConfigService = cpsProjectConfigService;
3845
}
3946

4047
public void Dispose()
@@ -64,6 +71,7 @@ private void OptionsSettings_PropertyChanged(object sender, System.ComponentMode
6471
case nameof(IOptionsSettingsService.JsonRootPath): JsonRootPathChanged(); break;
6572
case nameof(IOptionsSettingsService.VcsSupportEnabled): VcsSupportChanged(); break;
6673
case nameof(IOptionsSettingsService.UseSolutionDir): UseSolutionDirChanged(); break;
74+
case nameof(IOptionsSettingsService.UseCpsVirtualProfile): UseCpsVirtualProfileChanged(); break;
6775
case nameof(IOptionsSettingsService.ManageCommandLineArgs): viewModelUpdateService.UpdateIsActiveForParamsDebounced(); break;
6876
case nameof(IOptionsSettingsService.ManageEnvironmentVars): viewModelUpdateService.UpdateIsActiveForParamsDebounced(); break;
6977
case nameof(IOptionsSettingsService.ManageWorkingDirectories): viewModelUpdateService.UpdateIsActiveForParamsDebounced(); break;
@@ -116,5 +124,13 @@ private void UseSolutionDirChanged()
116124
fileStorage.DeleteAllUnusedArgFiles();
117125
fileStorage.SaveAllProjects();
118126
}
127+
private void UseCpsVirtualProfileChanged()
128+
{
129+
foreach (var project in vsHelper.GetSupportedProjects().Where(x => x.IsCpsProject()))
130+
{
131+
projectConfigService.UpdateProjectConfig(project);
132+
cpsProjectConfigService.SetActiveLaunchProfileToVirtualProfile(project.GetProject());
133+
}
134+
}
119135
}
120136
}

0 commit comments

Comments
 (0)