Merge pull request #19 from zadjii-msft/dev/crutkas/cleanpu

cleanup, whitespace and brackets
This commit is contained in:
Clint Rutkas
2024-08-30 23:54:02 -07:00
committed by GitHub
5 changed files with 164 additions and 78 deletions

View File

@@ -4,9 +4,11 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Microsoft.Terminal.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
@@ -18,17 +20,17 @@ using Microsoft.Windows.CommandPalette.Extensions;
using Windows.ApplicationModel.AppExtensions;
using Windows.Foundation;
using Windows.Foundation.Collections;
using System.Collections.ObjectModel;
using Microsoft.Terminal.UI;
namespace DeveloperCommandPalette;
public sealed class ActionViewModel(ICommand model)
{
public ICommand Command => model;
internal readonly string Name = model.Name;
internal readonly string Icon = model.Icon.Icon;
internal bool CanInvoke => model is IInvokableCommand;
internal IconElement IcoElement => Microsoft.Terminal.UI.IconPathConverter.IconMUX(Icon);
}

View File

@@ -3,12 +3,11 @@
// See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.Common.Contracts;
using Microsoft.CmdPal.Common.Extensions;
using Microsoft.CmdPal.Common.Models;
using Microsoft.CmdPal.Common.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.CmdPal.Common.Extensions;
using Microsoft.UI.Xaml;
using Microsoft.Windows.CommandPalette.Services;
@@ -21,14 +20,14 @@ namespace DeveloperCommandPalette;
/// </summary>
public partial class App : Application, IApp
{
private Window? window;
private Window? _window;
public Window? AppWindow
{
get => window;
get => _window;
private set { }
}
// The .NET Generic Host provides dependency injection, configuration, logging, and other services.
// https://docs.microsoft.com/dotnet/core/extensions/generic-host
// https://docs.microsoft.com/dotnet/core/extensions/dependency-injection
@@ -39,7 +38,9 @@ public partial class App : Application, IApp
get; private set;
}
public T GetService<T>() where T : class => Host.GetService<T>();
public T GetService<T>()
where T : class
=> Host.GetService<T>();
/// <summary>
/// Initializes a new instance of the <see cref="App"/> class.
@@ -50,7 +51,6 @@ public partial class App : Application, IApp
{
this.InitializeComponent();
Host = Microsoft.Extensions.Hosting.Host.
CreateDefaultBuilder()
.UseContentRoot(AppContext.BaseDirectory)
@@ -69,11 +69,11 @@ public partial class App : Application, IApp
//// Main window: Allow access to the main window
//// from anywhere in the application.
//services.AddSingleton(_ => MainWindow);
// services.AddSingleton(_ => MainWindow);
//// DispatcherQueue: Allow access to the DispatcherQueue for
//// the main window for general purpose UI thread access.
//services.AddSingleton(_ => MainWindow.DispatcherQueue);
// services.AddSingleton(_ => MainWindow.DispatcherQueue);
// Configuration
services.Configure<LocalSettingsOptions>(context.Configuration.GetSection(nameof(LocalSettingsOptions)));
@@ -89,8 +89,8 @@ public partial class App : Application, IApp
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
window = new MainWindow();
window.Activate();
_window = new MainWindow();
_window.Activate();
}
private async void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
@@ -100,10 +100,10 @@ public partial class App : Application, IApp
// We are about to crash, so signal the extensions to stop.
await GetService<IExtensionService>().SignalStopExtensionsAsync();
// Log.CloseAndFlush();
// We are very likely in a bad and unrecoverable state, so ensure Dev Home crashes w/ the exception info.
Environment.FailFast(e.Message, e.Exception);
}
}

View File

@@ -14,33 +14,36 @@ using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.Windows.CommandPalette.Extensions;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Microsoft.Windows.CommandPalette.Extensions;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace DeveloperCommandPalette;
public sealed class DetailsViewModel
{
internal string Title { get; init; } = "";
internal string Body { get; init; } = "";
internal IconDataType HeroImage { get; init; } = new("");
internal string Title { get; init; } = string.Empty;
internal string Body { get; init; } = string.Empty;
internal IconDataType HeroImage { get; init; } = new(string.Empty);
internal IconElement IcoElement => Microsoft.Terminal.UI.IconPathConverter.IconMUX(HeroImage.Icon);
internal DetailsViewModel(IDetails details)
{
this.Title = details.Title;
this.Body = details.Body;
this.HeroImage = details.HeroImage ?? new("");
this.HeroImage = details.HeroImage ?? new(string.Empty);
}
}
public sealed partial class DetailsControl : UserControl
{
private readonly DetailsViewModel ViewModel;
public DetailsControl(DetailsViewModel vm)
{
this.ViewModel = vm;

View File

@@ -5,21 +5,25 @@
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using CmdPal.Models;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
using Microsoft.Windows.CommandPalette.Extensions;
using CmdPal.Models;
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
namespace DeveloperCommandPalette;
public sealed class RecentsListSection : ListSection, INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler? CollectionChanged;
private readonly DispatcherQueue DispatcherQueue = DispatcherQueue.GetForCurrentThread();
private readonly MainViewModel _mainViewModel;
internal ObservableCollection<MainListItem> _Items { get; set; } = [];
private bool loadedApps;
public RecentsListSection(MainViewModel viewModel)
{
this.Title = "Recent";
@@ -46,7 +50,9 @@ public sealed class RecentsListSection : ListSection, INotifyCollectionChanged
CollectionChanged?.Invoke(this, e);
});
}
public override IListItem[] Items => _Items.ToArray();
internal void Reset()
{
_Items.Clear();
@@ -55,6 +61,7 @@ public sealed class RecentsListSection : ListSection, INotifyCollectionChanged
AddApps();
}
}
internal void AddApps()
{
var apps = _mainViewModel.Recent;
@@ -69,6 +76,7 @@ public sealed class RecentsListSection : ListSection, INotifyCollectionChanged
public sealed class MainListSection : ISection, INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler? CollectionChanged;
public string Title => "Actions";
private readonly MainViewModel _mainViewModel;
@@ -100,13 +108,13 @@ public sealed class MainListSection : ISection, INotifyCollectionChanged
public MainListSection(MainViewModel viewModel)
{
this._mainViewModel = viewModel;
_Items = new(_mainViewModel.TopLevelCommands.Select(w=>w.Unsafe).Where(li=>li!=null).Select(li => new MainListItem(li!)));
_Items.CollectionChanged += Bubble_CollectionChanged; ;
_Items = new(_mainViewModel.TopLevelCommands.Select(w => w.Unsafe).Where(li => li != null).Select(li => new MainListItem(li!)));
_Items.CollectionChanged += Bubble_CollectionChanged;
}
internal void UpdateQuery(string query)
{
var fallbacks = _Items.Select(i => i?.FallbackHandler).Where(fb => fb != null).Select(fb=>fb!);
var fallbacks = _Items.Select(i => i?.FallbackHandler).Where(fb => fb != null).Select(fb => fb!);
foreach (var fb in fallbacks)
{
fb.UpdateQuery(query);
@@ -120,6 +128,7 @@ public sealed class MainListSection : ISection, INotifyCollectionChanged
CollectionChanged?.Invoke(this, e);
});
}
internal void Reset()
{
_Items.Clear();
@@ -131,7 +140,8 @@ public sealed class MainListSection : ISection, INotifyCollectionChanged
public sealed class FilteredListSection : ISection, INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler? CollectionChanged;
public string Title => "";
public string Title => string.Empty;
private readonly MainViewModel _mainViewModel;
private readonly DispatcherQueue DispatcherQueue = DispatcherQueue.GetForCurrentThread();
@@ -156,7 +166,7 @@ public sealed class FilteredListSection : ISection, INotifyCollectionChanged
lastSearchResults :
_Items.Concat(_apps);
internal string lastQuery = "";
internal string lastQuery = string.Empty;
// Setting this will enumerate all the actions and installed apps.
internal string Query
@@ -176,6 +186,7 @@ public sealed class FilteredListSection : ISection, INotifyCollectionChanged
// Here, we're going from an empty query to one that has an actual string. Reset the last, so we will _also_ include apps now.
this.lastSearchResults = null;
}
lastQuery = value;
var results = ListHelpers.FilterList(itemsToEnumerate, Query);
this.lastSearchResults = string.IsNullOrEmpty(value) ? null : results;
@@ -191,15 +202,15 @@ public sealed class FilteredListSection : ISection, INotifyCollectionChanged
//
// instead run the query once when the action query changes, and store the
// results.
public IListItem[] Items => itemsToEnumerate.Where(i => i!= null).ToArray();
public IListItem[] Items => itemsToEnumerate.Where(i => i != null).ToArray();
public FilteredListSection(MainViewModel viewModel)
{
this._mainViewModel = viewModel;
// TODO: We should probably just get rid of MainListItem entirely, so I'm leaveing these uncaught
_Items = new(_mainViewModel.TopLevelCommands.Where(wrapper=>wrapper.Unsafe!=null).Select(wrapper => new MainListItem(wrapper.Unsafe!)));
_Items.CollectionChanged += Bubble_CollectionChanged; ;
_Items = new(_mainViewModel.TopLevelCommands.Where(wrapper => wrapper.Unsafe != null).Select(wrapper => new MainListItem(wrapper.Unsafe!)));
_Items.CollectionChanged += Bubble_CollectionChanged;
}
private void Bubble_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
@@ -209,12 +220,12 @@ public sealed class FilteredListSection : ISection, INotifyCollectionChanged
CollectionChanged?.Invoke(this, e);
});
}
internal void Reset()
{
_Items.Clear();
lastSearchResults = null;
}
}
public sealed class MainListPage : Microsoft.Windows.CommandPalette.Extensions.Helpers.DynamicListPage
@@ -227,7 +238,7 @@ public sealed class MainListPage : Microsoft.Windows.CommandPalette.Extensions.H
public MainListPage(MainViewModel viewModel)
{
this._mainViewModel= viewModel;
this._mainViewModel = viewModel;
_mainSection = new(_mainViewModel);
_recentsListSection = new(_mainViewModel);
@@ -245,18 +256,23 @@ public sealed class MainListPage : Microsoft.Windows.CommandPalette.Extensions.H
Loading = false;
}
public override ISection[] GetItems() {
public override ISection[] GetItems()
{
return _Sections;
}
public override ISection[] GetItems(string query) {
public override ISection[] GetItems(string query)
{
_filteredSection.Query = query;
_mainSection.UpdateQuery(query);
if (string.IsNullOrEmpty(query))
{
return _Sections;
}
else return [_filteredSection];
else
{
return [_filteredSection];
}
}
private void TopLevelCommands_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
@@ -264,6 +280,7 @@ public sealed class MainListPage : Microsoft.Windows.CommandPalette.Extensions.H
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems != null)
{
foreach (var item in e.NewItems)
{
if (item is ExtensionObject<IListItem> listItem)
{
// Eh, it's fine to be unsafe here, we're probably tossing MainListItem
@@ -271,27 +288,34 @@ public sealed class MainListPage : Microsoft.Windows.CommandPalette.Extensions.H
{
_mainSection._Items.Add(new MainListItem(listItem.Unsafe));
}
_filteredSection._Items.Add(new MainListItem(listItem.Unsafe));
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove && e.OldItems != null)
{
foreach (var item in e.OldItems)
{
if (item is ExtensionObject<IListItem> listItem)
{
foreach (var mainListItem in _mainSection._Items) // MainListItem
{
if (mainListItem.Item == listItem)
{
_mainSection._Items.Remove(mainListItem);
break;
}
}
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Reset)
{
_mainSection.Reset();
_filteredSection.Reset();
}
_recentsListSection.Reset();
}
}

View File

@@ -23,6 +23,7 @@ public sealed class MainViewModel
{
internal readonly AllApps.AllAppsPage apps = new();
internal readonly QuitActionProvider quitActionProvider = new();
public event TypedEventHandler<object, object?>? QuitRequested { add => quitActionProvider.QuitRequested += value; remove => quitActionProvider.QuitRequested -= value; }
internal readonly ObservableCollection<ActionsProviderWrapper> CommandsProviders = new();
@@ -50,7 +51,8 @@ public sealed class MainViewModel
ResetTopLevel();
// On a background thread, warm up the app cache since we want it more often than not
new Task(() => {
new Task(() =>
{
var _ = AllApps.AppCache.Instance.Value;
LoadedApps = true;
AppsReady?.Invoke(this, null);
@@ -101,25 +103,34 @@ public sealed class MainViewModel
return false;
}).Select(i => i!);
public IEnumerable<IListItem> AppItems => LoadedApps? apps.GetItems().First().Items : [];
public IEnumerable<IListItem> AppItems => LoadedApps ? apps.GetItems().First().Items : [];
public IEnumerable<ExtensionObject<IListItem>> Everything => TopLevelCommands
.Concat(AppItems.Select(i => new ExtensionObject<IListItem>(i)))
.Where(i => i!= null);
.Where(i =>
{
var v = i != null;
return v;
});
public IEnumerable<ExtensionObject<IListItem>> Recent => _recentCommandHashes
.Select(hash =>
Everything
.Where(i => {
try {
.Where(i =>
{
try
{
var o = i.Unsafe;
return CreateHash(o.Title, o.Subtitle) == hash;
} catch (COMException) { return false; }
}
catch (COMException)
{
return false;
}
})
.FirstOrDefault()
)
.FirstOrDefault())
.Where(i => i != null)
.Select(i=>i!);
.Select(i => i!);
public bool IsRecentCommand(MainListItem item)
{
@@ -127,10 +138,17 @@ public sealed class MainViewModel
{
foreach (var wraprer in Recent)
{
if (wraprer.Unsafe == item) return true;
if (wraprer.Unsafe == item)
{
return true;
}
}
}
catch (COMException) { return false; }
catch (COMException)
{
return false;
}
return false;
}
@@ -138,19 +156,23 @@ public sealed class MainViewModel
{
foreach (var wrapped in Everything)
{
try{
try
{
var listItem = wrapped?.Unsafe;
if (listItem != null && listItem.Command == action)
{
// Found it, awesome.
var hash = CreateHash(listItem.Title, listItem.Subtitle);
// Remove the old one and push the new one to the front
var recent = new List<string>([hash]).Concat(_recentCommandHashes.Where(h => h != hash)).Take(5).ToArray();
_recentCommandHashes = recent.ToArray();
return;
}
}
catch (COMException) { /* log something */ }
catch (COMException)
{ /* log something */
}
}
}
}
@@ -160,7 +182,7 @@ public sealed class MainViewModel
/// </summary>
public sealed partial class MainPage : Page
{
private string _log = "";
private string _log = string.Empty;
public MainViewModel ViewModel { get; } = new MainViewModel();
@@ -194,13 +216,15 @@ public sealed partial class MainPage : Page
private void _HackyBadClearFilter()
{
// BODGY but I don't care, cause i'm throwing this all out
if ((this.RootFrame.Content as Page)?.FindName("FilterBox") is TextBox tb) {
tb.Text = "";
if ((this.RootFrame.Content as Page)?.FindName("FilterBox") is TextBox tb)
{
tb.Text = string.Empty;
tb.Focus(FocusState.Programmatic);
}
_ = LoadAllCommands();
}
private void ViewModel_SummonRequested(object sender, object? args)
{
if (!RootFrame.CanGoBack)
@@ -216,11 +240,12 @@ public sealed partial class MainPage : Page
private async Task LoadAllCommands()
{
ViewModel.ResetTopLevel();
// Load builtins syncronously...
await LoadBuiltinCommandsAsync();
// ...and extensions on a fire_and_forget
_ = LoadExtensions();
}
public async Task LoadBuiltinCommandsAsync()
@@ -233,7 +258,6 @@ public sealed partial class MainPage : Page
ViewModel.CommandsProviders.Add(wrapper);
await LoadTopLevelCommandsFromProvider(wrapper).ConfigureAwait(false);
}
}
private void InitializePage(PageViewModel vm)
@@ -254,7 +278,8 @@ public sealed partial class MainPage : Page
HandleResult(invokable.Invoke());
return;
}
else if (action is IListPage listPage) {
else if (action is IListPage listPage)
{
GoToList(listPage);
return;
}
@@ -268,6 +293,7 @@ public sealed partial class MainPage : Page
GoToForm(formPage);
return;
}
// This is bad
// TODO! handle this with some sort of badly authored extension error
throw new NotImplementedException();
@@ -277,7 +303,11 @@ public sealed partial class MainPage : Page
{
foreach (var provider in ViewModel.CommandsProviders)
{
if (!provider.IsExtension) continue;
if (!provider.IsExtension)
{
continue;
}
foreach (var item in provider.TopLevelItems)
{
// TODO! We really need a better "SafeWrapper<T>" object that can make sure
@@ -292,7 +322,10 @@ public sealed partial class MainPage : Page
return;
}
}
catch (COMException e){ AppendLog(e.Message); }
catch (COMException e)
{
AppendLog(e.Message);
}
}
}
}
@@ -307,7 +340,10 @@ public sealed partial class MainPage : Page
private void HandleResult(ICommandResult? res)
{
if (res == null) return;
if (res == null)
{
return;
}
DispatcherQueue.TryEnqueue(() =>
{
@@ -325,12 +361,15 @@ public sealed partial class MainPage : Page
private void RequestGoBackHandler(object sender, object args)
{
if (!RootFrame.CanGoBack) {
if (!RootFrame.CanGoBack)
{
ViewModel.RequestHide();
return;
}
RootFrame.GoBack();
if (!RootFrame.CanGoBack){
if (!RootFrame.CanGoBack)
{
_HackyBadClearFilter();
}
}
@@ -346,6 +385,7 @@ public sealed partial class MainPage : Page
{
RootFrame.GoBack();
}
if (!RootFrame.CanGoBack)
{
_HackyBadClearFilter();
@@ -359,18 +399,24 @@ public sealed partial class MainPage : Page
private async Task LoadExtensions()
{
if (ViewModel == null) return;
if (ViewModel == null)
{
return;
}
ViewModel.LoadingExtensions = true;
var extnService = Application.Current.GetService<IExtensionService>();
if (extnService != null)
{
var extensions = await extnService.GetInstalledExtensionsAsync(ProviderType.Commands, includeDisabledExtensions: false);
foreach (var extension in extensions)
{
if (extension == null) continue;
if (extension == null)
{
continue;
}
await LoadActionExtensionObject(extension);
}
}
@@ -411,18 +457,22 @@ public sealed partial class MainPage : Page
{
var listVm = new ListPageViewModel(page) { Nested = true };
InitializePage(listVm);
DispatcherQueue.TryEnqueue(() => {
DispatcherQueue.TryEnqueue(() =>
{
RootFrame.Navigate(typeof(ListPage), listVm, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight });
});
}
private void GoToMarkdown(IMarkdownPage page)
{
var mdVm = new MarkdownPageViewModel(page) { Nested = true };
InitializePage(mdVm);
DispatcherQueue.TryEnqueue(() => {
DispatcherQueue.TryEnqueue(() =>
{
RootFrame.Navigate(typeof(MarkdownPage), mdVm, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight });
});
}
private void GoToForm(IFormPage page)
{
var formVm = new FormPageViewModel(page) { Nested = true };
@@ -452,48 +502,52 @@ public sealed partial class MainPage : Page
sealed class ActionsProviderWrapper
{
public bool IsExtension => extensionWrapper != null;
private readonly bool isValid;
private ICommandProvider ActionProvider { get; }
private readonly IExtensionWrapper? extensionWrapper;
private IListItem[] _topLevelItems = [];
public IListItem[] TopLevelItems => _topLevelItems;
public ActionsProviderWrapper(ICommandProvider provider) {
public ActionsProviderWrapper(ICommandProvider provider)
{
ActionProvider = provider;
isValid = true;
}
public ActionsProviderWrapper(IExtensionWrapper extension)
{
extensionWrapper = extension;
var extensionImpl = extension.GetExtensionObject();
if (extensionImpl?.GetProvider(ProviderType.Commands) is not ICommandProvider provider) throw new ArgumentException("extension didn't actually implement ICommandProvider");
if (extensionImpl?.GetProvider(ProviderType.Commands) is not ICommandProvider provider)
{
throw new ArgumentException("extension didn't actually implement ICommandProvider");
}
ActionProvider = provider;
isValid = true;
}
public async Task LoadTopLevelCommands()
{
if (!isValid) return;
if (!isValid)
{
return;
}
var t = new Task<IListItem[]>(() => ActionProvider.TopLevelCommands());
t.Start();
var commands = await t.ConfigureAwait(false);
// On a BG thread here
if (commands != null)
{
_topLevelItems = commands;
}
}
// public async Task<bool> Ping()
// {
// if (!isValid) return false;
// if (extensionWrapper != null)
// {
// return extensionWrapper.IsRunning();
// }
// return false;
// }
public void AllowSetForeground(bool allow)
{
@@ -501,10 +555,13 @@ sealed class ActionsProviderWrapper
{
return;
}
var iextn = extensionWrapper?.GetExtensionObject();
unsafe
{
PInvoke.CoAllowSetForegroundWindow(iextn);
}
}
public override bool Equals(object? obj) => obj is ActionsProviderWrapper wrapper && isValid == wrapper.isValid;
}