Skip to content

Commit fa4bc0a

Browse files
committed
Working on DI
1 parent 303be86 commit fa4bc0a

File tree

14 files changed

+435
-839
lines changed

14 files changed

+435
-839
lines changed

src/modules/cmdpal/Microsoft.CmdPal.Common/Services/IExtensionService.cs

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/CommandPaletteHost.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// The Microsoft Corporation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using Microsoft.CmdPal.Common.Services;
5+
using Microsoft.CmdPal.UI.ViewModels.Services;
66
using Microsoft.CommandPalette.Extensions;
77
using Microsoft.Extensions.Logging;
88

src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/CommandProviderWrapper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// The Microsoft Corporation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using Microsoft.CmdPal.Common.Services;
65
using Microsoft.CmdPal.UI.ViewModels.Models;
6+
using Microsoft.CmdPal.UI.ViewModels.Services;
77
using Microsoft.CommandPalette.Extensions;
88
using Microsoft.Extensions.Logging;
99

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
// Copyright (c) Microsoft Corporation
2+
// The Microsoft Corporation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Diagnostics;
6+
using Microsoft.CmdPal.UI.ViewModels.Services;
7+
using Microsoft.CommandPalette.Extensions;
8+
using Microsoft.Extensions.Logging;
9+
using Windows.Foundation;
10+
11+
namespace Microsoft.CmdPal.UI.ViewModels.Models;
12+
13+
public partial class BuiltInExtensionService : IExtensionService, IDisposable
14+
{
15+
public event TypedEventHandler<CommandProviderWrapper, IEnumerable<CommandProviderWrapper>>? OnCommandProviderAdded;
16+
17+
public event TypedEventHandler<CommandProviderWrapper, IEnumerable<CommandProviderWrapper>>? OnCommandProviderRemoved;
18+
19+
public event TypedEventHandler<CommandProviderWrapper, IEnumerable<TopLevelViewModel>>? OnCommandsAdded;
20+
21+
public event TypedEventHandler<CommandProviderWrapper, IEnumerable<TopLevelViewModel>>? OnCommandsRemoved;
22+
23+
private readonly ILogger _logger;
24+
private readonly TaskScheduler _taskScheduler;
25+
private readonly HotkeyManager _hotkeyManager;
26+
private readonly AliasManager _aliasManager;
27+
private readonly SettingsService _settingsService;
28+
29+
private readonly IEnumerable<ICommandProvider> _commandProviders;
30+
private readonly Lock _commandProvidersLock = new();
31+
32+
private readonly List<CommandProviderWrapper> _builtInCommandWrappers = [];
33+
private readonly SemaphoreSlim _getBuiltInCommandWrappersLock = new(1, 1);
34+
35+
private readonly List<CommandProviderWrapper> _enabledBuiltInCommandWrappers = [];
36+
private readonly SemaphoreSlim _getEnabledBuiltInCommandWrappersLock = new(1, 1);
37+
38+
private readonly List<TopLevelViewModel> _topLevelCommands = [];
39+
private readonly SemaphoreSlim _getTopLevelCommandsLock = new(1, 1);
40+
41+
private WeakReference<IPageContext>? _weakPageContext;
42+
43+
private bool isLoaded;
44+
45+
public BuiltInExtensionService(
46+
IEnumerable<ICommandProvider> commandProviders,
47+
TaskScheduler taskScheduler,
48+
HotkeyManager hotkeyManager,
49+
AliasManager aliasManager,
50+
SettingsService settingsService,
51+
ILogger logger)
52+
{
53+
_logger = logger;
54+
_taskScheduler = taskScheduler;
55+
_hotkeyManager = hotkeyManager;
56+
_aliasManager = aliasManager;
57+
_settingsService = settingsService;
58+
_commandProviders = commandProviders;
59+
}
60+
61+
public async Task<IEnumerable<CommandProviderWrapper>> GetCommandProviderWrappersAsync(WeakReference<IPageContext> weakPageContext, bool includeDisabledExtensions = false)
62+
{
63+
_weakPageContext = weakPageContext;
64+
65+
if (!isLoaded)
66+
{
67+
await LoadBuiltInsAsync();
68+
}
69+
70+
if (includeDisabledExtensions)
71+
{
72+
await _getBuiltInCommandWrappersLock.WaitAsync();
73+
try
74+
{
75+
return _builtInCommandWrappers;
76+
}
77+
finally
78+
{
79+
_getBuiltInCommandWrappersLock.Release();
80+
}
81+
}
82+
else
83+
{
84+
await _getEnabledBuiltInCommandWrappersLock.WaitAsync();
85+
try
86+
{
87+
return _enabledBuiltInCommandWrappers;
88+
}
89+
finally
90+
{
91+
_getEnabledBuiltInCommandWrappersLock.Release();
92+
}
93+
}
94+
}
95+
96+
public async Task<IEnumerable<TopLevelViewModel>> GetTopLevelCommandsAsync()
97+
{
98+
await _getTopLevelCommandsLock.WaitAsync();
99+
try
100+
{
101+
return _topLevelCommands;
102+
}
103+
finally
104+
{
105+
_getTopLevelCommandsLock.Release();
106+
}
107+
}
108+
109+
public async Task SignalStopExtensionsAsync()
110+
{
111+
// We're buil-in. There's no stopping us.
112+
}
113+
114+
public async Task EnableProviderAsync(string providerId)
115+
{
116+
await _getEnabledBuiltInCommandWrappersLock.WaitAsync();
117+
try
118+
{
119+
if (_enabledBuiltInCommandWrappers.Any(wrapper => wrapper.Id.Equals(providerId, StringComparison.Ordinal)))
120+
{
121+
return;
122+
}
123+
}
124+
finally
125+
{
126+
_getEnabledBuiltInCommandWrappersLock.Release();
127+
}
128+
129+
await _getBuiltInCommandWrappersLock.WaitAsync();
130+
try
131+
{
132+
CommandProviderWrapper? wrapper = _builtInCommandWrappers.FirstOrDefault(wrapper => wrapper.Id.Equals(providerId, StringComparison.Ordinal));
133+
134+
if (wrapper != null)
135+
{
136+
await _getEnabledBuiltInCommandWrappersLock.WaitAsync();
137+
try
138+
{
139+
_enabledBuiltInCommandWrappers.Add(wrapper);
140+
}
141+
finally
142+
{
143+
_getEnabledBuiltInCommandWrappersLock.Release();
144+
}
145+
146+
var commands = await LoadTopLevelCommandsFromProvider(wrapper);
147+
await _getTopLevelCommandsLock.WaitAsync();
148+
try
149+
{
150+
foreach (var c in commands)
151+
{
152+
_topLevelCommands.Add(c);
153+
}
154+
}
155+
finally
156+
{
157+
_getTopLevelCommandsLock.Release();
158+
}
159+
160+
OnCommandsAdded?.Invoke(wrapper, commands);
161+
}
162+
}
163+
finally
164+
{
165+
_getBuiltInCommandWrappersLock.Release();
166+
}
167+
}
168+
169+
public async Task DisableProviderAsync(string providerId)
170+
{
171+
await _getEnabledBuiltInCommandWrappersLock.WaitAsync();
172+
try
173+
{
174+
var wrapper = _enabledBuiltInCommandWrappers.FirstOrDefault(wrapper => wrapper.Id.Equals(providerId, StringComparison.Ordinal));
175+
176+
if (wrapper != null)
177+
{
178+
_enabledBuiltInCommandWrappers.Remove(wrapper);
179+
180+
await _getTopLevelCommandsLock.WaitAsync();
181+
try
182+
{
183+
var commands = _topLevelCommands.Where(command => command.CommandProviderId.Equals(wrapper.Id, StringComparison.Ordinal));
184+
foreach (var c in commands)
185+
{
186+
_topLevelCommands.Remove(c);
187+
}
188+
189+
OnCommandsRemoved?.Invoke(wrapper, commands);
190+
}
191+
finally
192+
{
193+
_getTopLevelCommandsLock.Release();
194+
}
195+
}
196+
}
197+
finally
198+
{
199+
_getEnabledBuiltInCommandWrappersLock.Release();
200+
}
201+
}
202+
203+
private async Task LoadBuiltInsAsync()
204+
{
205+
var s = new Stopwatch();
206+
s.Start();
207+
208+
var builtInProviders = _commandProviders;
209+
foreach (var provider in builtInProviders)
210+
{
211+
CommandProviderWrapper wrapper = new(provider, _taskScheduler, _hotkeyManager, _aliasManager, _logger);
212+
lock (_getBuiltInCommandWrappersLock)
213+
{
214+
_builtInCommandWrappers.Add(wrapper);
215+
}
216+
217+
if (wrapper.IsActive)
218+
{
219+
lock (_getEnabledBuiltInCommandWrappersLock)
220+
{
221+
_enabledBuiltInCommandWrappers.Add(wrapper);
222+
}
223+
224+
var commands = await LoadTopLevelCommandsFromProvider(wrapper);
225+
lock (_getTopLevelCommandsLock)
226+
{
227+
foreach (var c in commands)
228+
{
229+
_topLevelCommands.Add(c);
230+
}
231+
}
232+
}
233+
}
234+
235+
s.Stop();
236+
237+
isLoaded = true;
238+
239+
Log_LoadingBuiltInsTook(s.ElapsedMilliseconds);
240+
}
241+
242+
private async Task<IEnumerable<TopLevelViewModel>> LoadTopLevelCommandsFromProvider(CommandProviderWrapper commandProvider)
243+
{
244+
await commandProvider.LoadTopLevelCommands(_settingsService, _weakPageContext!);
245+
246+
var commands = await Task.Factory.StartNew(
247+
() =>
248+
{
249+
List<TopLevelViewModel> commands = [];
250+
foreach (var item in commandProvider.TopLevelItems)
251+
{
252+
commands.Add(item);
253+
}
254+
255+
foreach (var item in commandProvider.FallbackItems)
256+
{
257+
if (item.IsEnabled)
258+
{
259+
commands.Add(item);
260+
}
261+
}
262+
263+
return commands;
264+
},
265+
CancellationToken.None,
266+
TaskCreationOptions.None,
267+
_taskScheduler);
268+
269+
commandProvider.CommandsChanged -= CommandProvider_CommandsChanged;
270+
commandProvider.CommandsChanged += CommandProvider_CommandsChanged;
271+
272+
return commands;
273+
}
274+
275+
private void CommandProvider_CommandsChanged(CommandProviderWrapper commandProviderWrapper, IItemsChangedEventArgs args)
276+
{
277+
}
278+
279+
public void Dispose()
280+
{
281+
_getBuiltInCommandWrappersLock.Dispose();
282+
_getEnabledBuiltInCommandWrappersLock.Dispose();
283+
_getTopLevelCommandsLock.Dispose();
284+
GC.SuppressFinalize(this);
285+
}
286+
287+
private void Test()
288+
{
289+
OnCommandProviderAdded?.Invoke(null!, null!);
290+
OnCommandProviderRemoved?.Invoke(null!, null!);
291+
}
292+
293+
[LoggerMessage(Level = LogLevel.Debug, Message = "Loading built-ins took {elapsedMs}ms")]
294+
partial void Log_LoadingBuiltInsTook(long elapsedMs);
295+
}

0 commit comments

Comments
 (0)