Compare commits

..

5 Commits

Author SHA1 Message Date
Michael Jolley
42bf5ad885 More refreshing 2025-12-01 10:20:10 -06:00
Michael Jolley
0b10a15a8a More service stuff 2025-11-25 15:15:31 -06:00
Michael Jolley
c755b8585a More service stuff 2025-11-24 22:48:27 -06:00
Michael Jolley
bfc1bcae6d More refreshing 2025-11-20 21:52:02 -06:00
Michael Jolley
c0f6a3f9f4 First commit of refresh 2025-11-20 17:28:05 -06:00
178 changed files with 1903 additions and 4258 deletions

View File

@@ -2,8 +2,8 @@ AAAAs
abcdefghjkmnpqrstuvxyz
abgr
ABlocked
ABORTIFHUNG
ABOUTBOX
ABORTIFHUNG
Abug
Acceleratorkeys
ACCEPTFILES
@@ -97,8 +97,8 @@ ASSOCSTR
ASYNCWINDOWPLACEMENT
ASYNCWINDOWPOS
atl
ATRIOX
ATX
ATRIOX
aumid
authenticode
AUTOBUDDY
@@ -117,10 +117,10 @@ azman
azureaiinference
azureinference
azureopenai
backticks
bbwe
BCIE
bck
backticks
BESTEFFORT
bezelled
bhid
@@ -148,8 +148,8 @@ bmi
BNumber
BODGY
BOklab
BOOTSTRAPPERINSTALLFOLDER
Bootstrappers
BOOTSTRAPPERINSTALLFOLDER
BOTTOMALIGN
boxmodel
BPBF
@@ -176,16 +176,17 @@ BYPOSITION
CALCRECT
CALG
callbackptr
cabstr
calpwstr
caub
Cangjie
CANRENAME
Carlseibert
Canvascustomlayout
CAPTUREBLT
CAPTURECHANGED
CARETBLINKING
Carlseibert
CAtl
caub
CBN
cch
CCHDEVICENAME
@@ -205,9 +206,11 @@ changecursor
CHILDACTIVATE
CHILDWINDOW
CHOOSEFONT
CIBUILD
cidl
CIELCh
cim
claude
CImage
cla
CLASSDC
@@ -261,6 +264,7 @@ CONFIGW
CONFLICTINGMODIFIERKEY
CONFLICTINGMODIFIERSHORTCUT
CONOUT
coreclr
constexpr
contentdialog
contentfiles
@@ -272,7 +276,6 @@ copiedcolorrepresentation
coppied
copyable
COPYPEN
coreclr
COREWINDOW
Corpor
cotaskmem
@@ -281,18 +284,18 @@ countof
covrun
cpcontrols
cph
cppcoreguidelines
cplusplus
CPower
cppcoreguidelines
cpptools
cppvsdbg
cppwinrt
createdump
creativecommons
CREATEPROCESS
CREATESCHEDULEDTASK
CREATESTRUCT
CREATEWINDOWFAILED
creativecommons
CRECT
CRH
critsec
@@ -328,6 +331,7 @@ CYSCREEN
CYSMICON
CYVIRTUALSCREEN
Czechia
cziplib
Dac
dacl
DAffine
@@ -351,7 +355,9 @@ Deact
debugbreak
decryptor
Dedup
dfx
Deduplicator
Deeplink
DEFAULTBOOTSTRAPPERINSTALLFOLDER
DEFAULTCOLOR
DEFAULTFLAGS
@@ -398,6 +404,7 @@ DISPLAYFREQUENCY
displayname
DISPLAYORIENTATION
divyan
djwsxzxb
Dlg
DLGFRAME
DLGMODALFRAME
@@ -410,6 +417,7 @@ DONTVALIDATEPATH
dotnet
downsampled
downsampling
Downsampled
downscale
DPICHANGED
DPIs
@@ -523,6 +531,7 @@ EXTRINSICPROPERTIES
eyetracker
FANCYZONESDRAWLAYOUTTEST
FANCYZONESEDITOR
FNumber
FARPROC
fdx
fesf
@@ -554,8 +563,8 @@ FIXEDSYS
flac
flyouts
FMask
foundrylocal
fmtid
FNumber
FOF
FOFX
FOLDERID
@@ -566,7 +575,6 @@ FORCEMINIMIZE
FORMATDLGORD
formatetc
FORPARSING
foundrylocal
FRAMECHANGED
frm
FROMTOUCH
@@ -585,13 +593,13 @@ gdi
gdiplus
GDIPVER
GDISCALED
geolocator
GETCLIENTAREAANIMATION
GETCURSEL
GETDESKWALLPAPER
GETDLGCODE
GETDPISCALEDSIZE
getfilesiginforedist
geolocator
GETHOTKEY
GETICON
GETLBTEXT
@@ -602,12 +610,11 @@ GETSCREENSAVERRUNNING
GETSECKEY
GETSTICKYKEYS
GETTEXTLENGTH
GHND
GIFs
gitmodules
GHND
GMEM
GNumber
googleai
googlegemini
gpedit
gpo
GPOCA
@@ -624,6 +631,8 @@ GValue
gwl
GWLP
GWLSTYLE
googleai
googlegemini
hangeul
Hanzi
Hardlines
@@ -734,7 +743,9 @@ IDCANCEL
IDD
idk
idl
IIM
idlist
ifd
IDOK
IDOn
IDR
@@ -743,16 +754,15 @@ ietf
IEXPLORE
IFACEMETHOD
IFACEMETHODIMP
ifd
IGNOREUNKNOWN
IGo
iid
IIM
Iindex
Ijwhost
ILD
IMAGEHLP
IMAGERESIZERCONTEXTMENU
IPTC
IMAGERESIZEREXT
imageresizerinput
imageresizersettings
@@ -788,6 +798,7 @@ INSTALLFOLDERTOPREVIOUSINSTALLFOLDER
INSTALLLOCATION
INSTALLMESSAGE
INSTALLPROPERTY
installscopeperuser
INSTALLSTARTMENUSHORTCUT
INSTALLSTATE
Inste
@@ -800,7 +811,6 @@ invokecommand
ipcmanager
IPREVIEW
ipreviewhandlervisualssetfont
IPTC
irow
irprops
isbi
@@ -844,14 +854,15 @@ keyvault
KILLFOCUS
killrunner
kmph
ksa
kvp
Kybd
LARGEICON
lastcodeanalysissucceeded
LASTEXITCODE
LAYOUTRTL
lbl
LCh
lbl
lcid
LCIDTo
lcl
@@ -867,10 +878,10 @@ LExit
lhwnd
LIBFUZZER
LIBID
lightswitch
LIMITSIZE
LIMITTEXT
lindex
lightswitch
linkid
LINKOVERLAY
LINQTo
@@ -881,7 +892,6 @@ LLKH
llkhf
LMEM
LMENU
lng
LOADFROMFILE
LOBYTE
localappdata
@@ -891,14 +901,17 @@ LOCATIONCHANGE
LOCKTYPE
LOGFONT
LOGFONTW
LOGMSG
logon
lon
LOGMSG
LOGPIXELSX
LOGPIXELSY
lng
lon
longdate
LONGNAMES
lowlevel
lquadrant
LOWORD
lparam
LPBITMAPINFOHEADER
@@ -932,7 +945,6 @@ lpv
LPW
lpwcx
lpwndpl
lquadrant
LReader
LRESULT
LSTATUS
@@ -959,7 +971,6 @@ MAKELONG
MAKELPARAM
makepri
MAKEWPARAM
Malware
manifestdependency
MAPPEDTOSAMEKEY
MAPTOSAMESHORTCUT
@@ -982,8 +993,8 @@ MENUITEMINFO
MENUITEMINFOW
MERGECOPY
MERGEPAINT
metadatamatters
Metadatas
metadatamatters
metafile
mfc
Mgmt
@@ -1029,6 +1040,9 @@ mousepointer
mouseutils
MOVESIZEEND
MOVESIZESTART
muxx
muxxc
muxxh
MRM
MRT
mru
@@ -1061,9 +1075,6 @@ MTND
MULTIPLEUSE
multizone
muxc
muxx
muxxc
muxxh
MVPs
mvvm
MVVMTK
@@ -1146,6 +1157,7 @@ nonstd
NOOWNERZORDER
NOPARENTNOTIFY
NOPREFIX
NPU
NOREDIRECTIONBITMAP
NOREDRAW
NOREMOVE
@@ -1174,7 +1186,6 @@ nowarn
NOZORDER
NPH
npmjs
NPU
NResize
NTAPI
ntdll
@@ -1199,15 +1210,16 @@ oldpath
oldtheme
oleaut
OLECHAR
ollama
onebranch
onnx
OOBEUI
openas
opencode
OPENFILENAME
opensource
openxmlformats
ollama
Olllama
onnx
OPTIMIZEFORINVOKE
ORPHANEDDIALOGTITLE
ORSCANS
@@ -1280,7 +1292,6 @@ pguid
phbm
phbmp
phicon
Photoshop
phwnd
pici
pidl
@@ -1303,6 +1314,7 @@ pnid
PNMLINK
Poc
Podcasts
Photoshop
POINTERID
POINTERUPDATE
Pokedex
@@ -1397,9 +1409,10 @@ pwsz
pwtd
QDC
qit
QNN
Qualcomm
QITAB
QITABENT
QNN
qoi
Quarternary
QUERYENDSESSION
@@ -1409,8 +1422,8 @@ quickaccent
QUNS
RAII
RAlt
randi
RAquadrant
randi
rasterization
Rasterize
RAWINPUTDEVICE
@@ -1437,7 +1450,9 @@ regfile
REGISTERCLASSFAILED
REGISTRYHEADER
REGISTRYPREVIEWEXT
registryroot
regkey
regroot
regsvr
REINSTALLMODE
releaseblog
@@ -1490,6 +1505,7 @@ rstringalpha
rstringdigit
rtb
RTLREADING
rtm
runas
rundll
rungameid
@@ -1546,8 +1562,8 @@ SETRULES
SETSCREENSAVEACTIVE
SETSTICKYKEYS
SETTEXT
SETTINGCHANGE
settingscard
SETTINGCHANGE
SETTINGSCHANGED
settingsheader
settingshotkeycontrol
@@ -1692,7 +1708,6 @@ stringtable
stringval
Strm
strret
STRSAFE
stscanf
sttngs
Stubless
@@ -1704,6 +1719,7 @@ sublang
SUBMODULEUPDATE
subresource
Superbar
suntimes
sut
svchost
SVGIn
@@ -1737,6 +1753,7 @@ SYSTEMMODAL
SYSTEMTIME
TARG
TARGETAPPHEADER
TARGETDIR
targetentrypoint
TARGETHEADER
targetver
@@ -1766,10 +1783,10 @@ textextractor
TEXTINCLUDE
tfopen
tgz
THEMECHANGED
themeresources
THH
THICKFRAME
THEMECHANGED
THISCOMPONENT
throughs
TILEDWINDOW
@@ -1866,6 +1883,7 @@ USEINSTALLERFORTEST
USESHOWWINDOW
USESTDHANDLES
USRDLL
utm
UType
uuidv
uwp
@@ -1938,11 +1956,11 @@ Wca
WCE
wcex
WClass
WCRAPI
wcsicmp
wcsncpy
wcsnicmp
WCT
WCRAPI
WDA
wdm
wdp
@@ -1970,7 +1988,6 @@ WINDOWPLACEMENT
WINDOWPOSCHANGED
WINDOWPOSCHANGING
WINDOWSBUILDNUMBER
windowsml
windowssearch
windowssettings
WINDOWSTYLES
@@ -1986,8 +2003,9 @@ Winhook
WINL
winlogon
winmd
winml
WINNT
windowsml
winml
winres
winrt
winsdk
@@ -2049,21 +2067,20 @@ WTSAT
Wubi
WUX
Wwanpp
xap
XAxis
XButton
xclip
xcopy
xap
XDeployment
xdf
XDimension
xdf
XDocument
XElement
xfd
XFile
XIncrement
XLoc
xmp
XNamespace
Xoshiro
XPels
@@ -2074,22 +2091,23 @@ xsi
XSpeed
XStr
xstyler
xmp
XTimer
XUP
XVIRTUALSCREEN
xxxxxx
YAxis
ycombinator
YDimension
YIncrement
YDimension
yinle
yinyue
YPels
YPos
YResolution
YSpeed
YStr
YTimer
YStr
YVIRTUALSCREEN
ZEROINIT
zonability

View File

@@ -53,17 +53,17 @@ Go to the [PowerToys GitHub releases][github-release-link], click Assets to reve
<!-- items that need to be updated release to release -->
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.97%22
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.96%22
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.1/PowerToysUserSetup-0.96.1-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.1/PowerToysUserSetup-0.96.1-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.1/PowerToysSetup-0.96.1-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.1/PowerToysSetup-0.96.1-arm64.exe
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.0/PowerToysUserSetup-0.96.0-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.0/PowerToysUserSetup-0.96.0-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.0/PowerToysSetup-0.96.0-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.0/PowerToysSetup-0.96.0-arm64.exe
| Description | Filename |
|----------------|----------|
| Per user - x64 | [PowerToysUserSetup-0.96.1-x64.exe][ptUserX64] |
| Per user - ARM64 | [PowerToysUserSetup-0.96.1-arm64.exe][ptUserArm64] |
| Machine wide - x64 | [PowerToysSetup-0.96.1-x64.exe][ptMachineX64] |
| Machine wide - ARM64 | [PowerToysSetup-0.96.1-arm64.exe][ptMachineArm64] |
| Per user - x64 | [PowerToysUserSetup-0.96.0-x64.exe][ptUserX64] |
| Per user - ARM64 | [PowerToysUserSetup-0.96.0-arm64.exe][ptUserArm64] |
| Machine wide - x64 | [PowerToysSetup-0.96.0-x64.exe][ptMachineX64] |
| Machine wide - ARM64 | [PowerToysSetup-0.96.0-arm64.exe][ptMachineArm64] |
</details>

View File

@@ -33,12 +33,9 @@ The **Light Switch** module lets users automatically transition between light an
> **Note:** Using the shortcut overrides the current schedule until the next transition event.
* **LightSwitchService.cpp**
is the heart beat of the module. Controls ticking every minute and depending on user actions (manual override, settings changing, etc) triggers the state manager to perform the corresponding operation.
* **LightSwitchStateManager.cpp**
handles updating the state based on the signals sent by LightSwitchService.
* **LightSwitchService**
Reads settings and applies theming. Runs a check every minute to ensure the state is correct.
* **SettingsXAML/LightSwitch**
Provides the settings UI for configuring schedules, syncing location, and customizing shortcuts.

View File

@@ -64,7 +64,7 @@ public sealed class FoundryLocalModelProvider : ILanguageModelProvider
return new OpenAIClient(
new ApiKeyCredential("none"),
new OpenAIClientOptions { Endpoint = endpointUri, NetworkTimeout = TimeSpan.FromMinutes(5) })
new OpenAIClientOptions { Endpoint = endpointUri })
.GetChatClient(modelId)
.AsIChatClient();
}

View File

@@ -215,6 +215,7 @@ public sealed class AdvancedAIKernelService : KernelServiceBase
return new OpenAIPromptExecutionSettings
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),
Temperature = 0.01,
};
}
}

View File

@@ -146,7 +146,6 @@ public sealed class FoundryLocalPasteProvider : IPasteAIProvider
var options = new ChatOptions
{
ModelId = modelReference,
MaxOutputTokens = 2048,
};
if (!string.IsNullOrWhiteSpace(systemPrompt))

View File

@@ -157,6 +157,8 @@ namespace AdvancedPaste.Services.CustomActions
{
AIServiceType.OpenAI or AIServiceType.AzureOpenAI => new OpenAIPromptExecutionSettings
{
Temperature = 0.01,
MaxTokens = 2000,
FunctionChoiceBehavior = null,
},
_ => new PromptExecutionSettings(),

View File

@@ -350,7 +350,7 @@ namespace Awake.Core
TrayHelper.TimedIcon,
TrayIconAction.Update);
},
() => HandleTimerCompletion("timed"),
_ => HandleTimerCompletion("timed"),
_tokenSource.Token);
}

View File

@@ -1,62 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.CmdPal.Core.Common;
public static class CoreLogger
{
public static void InitializeLogger(ILogger implementation)
{
_logger = implementation;
}
private static ILogger? _logger;
public static void LogError(string message, Exception ex, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogError(message, ex, memberName, sourceFilePath, sourceLineNumber);
}
public static void LogError(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogError(message, memberName, sourceFilePath, sourceLineNumber);
}
public static void LogWarning(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogWarning(message, memberName, sourceFilePath, sourceLineNumber);
}
public static void LogInfo(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogInfo(message, memberName, sourceFilePath, sourceLineNumber);
}
public static void LogDebug(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogDebug(message, memberName, sourceFilePath, sourceLineNumber);
}
public static void LogTrace([System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogTrace(memberName, sourceFilePath, sourceLineNumber);
}
}
public interface ILogger
{
void LogError(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
void LogError(string message, Exception ex, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
void LogWarning(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
void LogInfo(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
void LogDebug(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
void LogTrace([System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
}

View File

@@ -9,4 +9,8 @@
<PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
</ItemGroup>
</Project>

View File

@@ -2,8 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.Foundation;
namespace Microsoft.CmdPal.Core.Common.Services;
@@ -26,12 +24,4 @@ public interface IExtensionService
void EnableExtension(string extensionUniqueId);
void DisableExtension(string extensionUniqueId);
///// <summary>
///// Gets a boolean indicating whether the extension was disabled due to the corresponding Windows optional feature
///// being absent from the machine or in an unknown state.
///// </summary>
///// <param name="extension">The out of proc extension object</param>
///// <returns>True only if the extension was disabled. False otherwise.</returns>
// public Task<bool> DisableExtensionIfWindowsFeatureNotAvailable(IExtensionWrapper extension);
}

View File

@@ -23,12 +23,3 @@ public interface IRunHistoryService
/// <param name="item">The run history item to add.</param>
void AddRunHistoryItem(string item);
}
public interface ITelemetryService
{
void LogRunQuery(string query, int resultCount, ulong durationMs);
void LogRunCommand(string command, bool asAdmin, bool success);
void LogOpenUri(string uri, bool isWeb, bool success);
}

View File

@@ -0,0 +1,10 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.CmdPal.Core.Common.Services.Telemetry;
public interface ITelemetryService
{
void WriteEvent(TelemetryEventBase telemetryEvent);
}

View File

@@ -0,0 +1,14 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.Core.Common.Services.Telemetry;
public abstract class TelemetryEventBase : EventBase, IEvent
{
// Overridden in derived classes
public abstract PartA_PrivTags PartA_PrivTags { get; }
}

View File

@@ -4,9 +4,9 @@
using System.Collections.ObjectModel;
using System.Diagnostics;
using Microsoft.CmdPal.Core.Common;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
using Windows.Foundation;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -14,6 +14,7 @@ namespace Microsoft.CmdPal.Core.ViewModels;
public abstract partial class AppExtensionHost : IExtensionHost
{
private static readonly GlobalLogPageContext _globalLogPageContext = new();
private readonly ILogger _logger;
private static ulong _hostingHwnd;
@@ -27,6 +28,11 @@ public abstract partial class AppExtensionHost : IExtensionHost
public static void SetHostHwnd(ulong hostHwnd) => _hostingHwnd = hostHwnd;
public AppExtensionHost(ILogger logger)
{
_logger = logger;
}
public void DebugLog(string message)
{
#if DEBUG
@@ -60,7 +66,7 @@ public abstract partial class AppExtensionHost : IExtensionHost
return Task.CompletedTask.AsAsyncAction();
}
CoreLogger.LogDebug(message.Message);
Log_DebugMessage(message.Message);
_ = Task.Run(() =>
{
@@ -96,7 +102,7 @@ public abstract partial class AppExtensionHost : IExtensionHost
public void ProcessLogMessage(ILogMessage message)
{
var vm = new LogMessageViewModel(message, _globalLogPageContext);
var vm = new LogMessageViewModel(message, _globalLogPageContext, _logger);
vm.SafeInitializePropertiesSynchronous();
Task.Factory.StartNew(
@@ -127,7 +133,7 @@ public abstract partial class AppExtensionHost : IExtensionHost
return;
}
var vm = new StatusMessageViewModel(message, new(_globalLogPageContext));
var vm = new StatusMessageViewModel(message, new(_globalLogPageContext), _logger);
vm.SafeInitializePropertiesSynchronous();
Task.Factory.StartNew(
@@ -158,6 +164,11 @@ public abstract partial class AppExtensionHost : IExtensionHost
}
public abstract string? GetExtensionDisplayName();
public abstract AppExtensionHost GetHostForCommand(object? context, AppExtensionHost? currentHost);
[LoggerMessage(Level = LogLevel.Debug, Message = "{Message}")]
partial void Log_DebugMessage(string message);
}
public interface IAppHostService

View File

@@ -6,6 +6,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
using Windows.System;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -13,6 +14,8 @@ namespace Microsoft.CmdPal.Core.ViewModels;
public partial class CommandBarViewModel : ObservableObject,
IRecipient<UpdateCommandBarMessage>
{
private readonly ILogger _logger;
public ICommandBarContext? SelectedItem
{
get => field;
@@ -48,8 +51,9 @@ public partial class CommandBarViewModel : ObservableObject,
[ObservableProperty]
public partial PageViewModel? CurrentPage { get; set; }
public CommandBarViewModel()
public CommandBarViewModel(ILogger logger)
{
_logger = logger;
WeakReferenceMessenger.Default.Register<UpdateCommandBarMessage>(this);
}

View File

@@ -5,12 +5,12 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public partial class CommandContextItemViewModel(ICommandContextItem contextItem, WeakReference<IPageContext> context) : CommandItemViewModel(new(contextItem), context), IContextItemViewModel
public partial class CommandContextItemViewModel(ICommandContextItem contextItem, WeakReference<IPageContext> context, ILogger logger) : CommandItemViewModel(new(contextItem), context, logger), IContextItemViewModel
{
private readonly KeyChord nullKeyChord = new(0, 0, 0);

View File

@@ -3,11 +3,11 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using Microsoft.CmdPal.Core.Common;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -86,11 +86,11 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
_errorIcon.InitializeProperties();
}
public CommandItemViewModel(ExtensionObject<ICommandItem> item, WeakReference<IPageContext> errorContext)
: base(errorContext)
public CommandItemViewModel(ExtensionObject<ICommandItem> item, WeakReference<IPageContext> errorContext, ILogger logger)
: base(errorContext, logger)
{
_commandItemModel = item;
Command = new(null, errorContext);
Command = new(null, errorContext, Logger);
}
public void FastInitializeProperties()
@@ -106,7 +106,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
return;
}
Command = new(model.Command, PageContext);
Command = new(model.Command, PageContext, Logger);
Command.FastInitializeProperties();
_itemTitle = model.Title;
@@ -184,7 +184,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
MoreCommands = more
.Select<IContextItem, IContextItemViewModel>(item =>
{
return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext) : new SeparatorViewModel();
return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext, Logger) : new SeparatorViewModel();
})
.ToList();
}
@@ -201,7 +201,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
if (!string.IsNullOrEmpty(model.Command?.Name))
{
_defaultCommandContextItemViewModel = new CommandContextItemViewModel(new CommandContextItem(model.Command!), PageContext)
_defaultCommandContextItemViewModel = new CommandContextItemViewModel(new CommandContextItem(model.Command!), PageContext, Logger)
{
_itemTitle = Name,
Subtitle = Subtitle,
@@ -231,8 +231,8 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
}
catch (Exception ex)
{
CoreLogger.LogError("error fast initializing CommandItemViewModel", ex);
Command = new(null, PageContext);
Log_ErrorFastInitializingCommandItemViewModel(Logger, ex);
Command = new(null, PageContext, Logger);
_itemTitle = "Error";
Subtitle = "Item failed to load";
MoreCommands = [];
@@ -253,7 +253,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
catch (Exception ex)
{
Initialized |= InitializedState.Error;
CoreLogger.LogError("error slow initializing CommandItemViewModel", ex);
Log_ErrorSlowInitializingCommandItemViewModel(Logger, ex);
}
return false;
@@ -268,8 +268,8 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
}
catch (Exception ex)
{
CoreLogger.LogError("error initializing CommandItemViewModel", ex);
Command = new(null, PageContext);
Log_ErrorSlowInitializingCommandItemViewModel(Logger, ex);
Command = new(null, PageContext, Logger);
_itemTitle = "Error";
Subtitle = "Item failed to load";
MoreCommands = [];
@@ -304,7 +304,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
{
case nameof(Command):
Command.PropertyChanged -= Command_PropertyChanged;
Command = new(model.Command, PageContext);
Command = new(model.Command, PageContext, Logger);
Command.InitializeProperties();
Command.PropertyChanged += Command_PropertyChanged;
@@ -351,7 +351,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
var newContextMenu = more
.Select<IContextItem, IContextItemViewModel>(item =>
{
return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext) : new SeparatorViewModel();
return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext, Logger) : new SeparatorViewModel();
})
.ToList();
lock (MoreCommands)
@@ -464,6 +464,15 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
base.SafeCleanup();
Initialized |= InitializedState.CleanedUp;
}
[LoggerMessage(level: LogLevel.Error, message: "error fast initializing CommandItemViewModel")]
static partial void Log_ErrorFastInitializingCommandItemViewModel(ILogger logger, Exception ex);
[LoggerMessage(level: LogLevel.Error, message: "error slow initializing CommandItemViewModel")]
static partial void Log_ErrorSlowInitializingCommandItemViewModel(ILogger logger, Exception ex);
[LoggerMessage(level: LogLevel.Error, message: "error initializing CommandItemViewModel")]
static partial void Log_ErrorInitializingCommandItemViewModel(ILogger logger, Exception ex);
}
[Flags]

View File

@@ -4,6 +4,7 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -38,8 +39,8 @@ public partial class CommandViewModel : ExtensionObjectViewModel
public IReadOnlyDictionary<string, ExtensionObject<object>>? Properties => _properties?.AsReadOnly();
public CommandViewModel(ICommand? command, WeakReference<IPageContext> pageContext)
: base(pageContext)
public CommandViewModel(ICommand? command, WeakReference<IPageContext> pageContext, ILogger logger)
: base(pageContext, logger)
{
Model = new(command);
Icon = new(null);

View File

@@ -4,13 +4,14 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class ConfirmResultViewModel(IConfirmationArgs _args, WeakReference<IPageContext> context) :
ExtensionObjectViewModel(context)
public partial class ConfirmResultViewModel(IConfirmationArgs? args, WeakReference<IPageContext> context, ILogger logger)
: ExtensionObjectViewModel(context, logger)
{
public ExtensionObject<IConfirmationArgs> Model { get; } = new(_args);
public ExtensionObject<IConfirmationArgs> Model { get; private set; } = new(args);
// Remember - "observable" properties from the model (via PropChanged)
// cannot be marked [ObservableProperty]
@@ -20,7 +21,7 @@ public partial class ConfirmResultViewModel(IConfirmationArgs _args, WeakReferen
public bool IsPrimaryCommandCritical { get; private set; }
public CommandViewModel PrimaryCommand { get; private set; } = new(null, context);
public CommandViewModel PrimaryCommand { get; private set; } = new(null, context, logger);
public override void InitializeProperties()
{
@@ -33,7 +34,7 @@ public partial class ConfirmResultViewModel(IConfirmationArgs _args, WeakReferen
Title = model.Title;
Description = model.Description;
IsPrimaryCommandCritical = model.IsPrimaryCommandCritical;
PrimaryCommand = new(model.PrimaryCommand, PageContext);
PrimaryCommand = new(model.PrimaryCommand, PageContext, Logger);
PrimaryCommand.InitializeProperties();
UpdateProperty(nameof(Title));

View File

@@ -11,12 +11,14 @@ using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
{
private readonly ExtensionObject<IContentPage> _model;
private readonly ILogger _logger;
[ObservableProperty]
public partial ObservableCollection<ContentViewModel> Content { get; set; } = [];
@@ -47,10 +49,11 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
// Remember - "observable" properties from the model (via PropChanged)
// cannot be marked [ObservableProperty]
public ContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host)
: base(model, scheduler, host)
public ContentPageViewModel(IContentPage model, AppExtensionHost host, ILogger logger)
: base(model, host, logger)
{
_model = new(model);
_logger = logger;
}
// TODO: Does this need to hop to a _different_ thread, so that we don't block the extension while we're fetching?
@@ -115,7 +118,7 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
{
if (item is ICommandContextItem contextItem)
{
return new CommandContextItemViewModel(contextItem, PageContext);
return new CommandContextItemViewModel(contextItem, PageContext, _logger);
}
else
{
@@ -135,7 +138,7 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
var extensionDetails = model.Details;
if (extensionDetails is not null)
{
Details = new(extensionDetails, PageContext);
Details = new(extensionDetails, PageContext, _logger);
Details.InitializeProperties();
}
@@ -174,7 +177,7 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
{
if (item is ICommandContextItem contextItem)
{
return new CommandContextItemViewModel(contextItem, PageContext) as IContextItemViewModel;
return new CommandContextItemViewModel(contextItem, PageContext, _logger) as IContextItemViewModel;
}
else
{
@@ -216,7 +219,7 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
break;
case nameof(Details):
var extensionDetails = model.Details;
Details = extensionDetails is not null ? new(extensionDetails, PageContext) : null;
Details = extensionDetails is not null ? new(extensionDetails, PageContext, _logger) : null;
UpdateDetails();
break;
}

View File

@@ -2,10 +2,12 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public abstract partial class ContentViewModel(WeakReference<IPageContext> context) :
ExtensionObjectViewModel(context)
public abstract partial class ContentViewModel(WeakReference<IPageContext> context, ILogger logger) :
ExtensionObjectViewModel(context, logger)
{
public bool OnlyControlOnPage { get; internal set; }
}

View File

@@ -5,7 +5,6 @@
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.Common;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
@@ -138,11 +137,7 @@ public partial class ContextMenuViewModel : ObservableObject,
if (item is CommandContextItemViewModel cmd && cmd.HasRequestedShortcut)
{
var key = cmd.RequestedShortcut ?? new KeyChord(0, 0, 0);
var added = result.TryAdd(key, cmd);
if (!added)
{
CoreLogger.LogWarning($"Ignoring duplicate keyboard shortcut {KeyChordHelpers.FormatForDebug(key)} on command '{cmd.Title ?? cmd.Name ?? "(unknown)"}'");
}
_ = result.TryAdd(key, cmd);
}
}

View File

@@ -4,19 +4,26 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class DetailsCommandsViewModel(
IDetailsElement _detailsElement,
WeakReference<IPageContext> context) : DetailsElementViewModel(_detailsElement, context)
public partial class DetailsCommandsViewModel : DetailsElementViewModel
{
private readonly ILogger _logger;
public List<CommandViewModel> Commands { get; private set; } = [];
public bool HasCommands => Commands.Count > 0;
private readonly ExtensionObject<IDetailsCommands> _dataModel =
new(_detailsElement.Data as IDetailsCommands);
private readonly ExtensionObject<IDetailsCommands> _dataModel;
public DetailsCommandsViewModel(IDetailsElement _detailsElement, WeakReference<IPageContext> context, ILogger logger)
: base(_detailsElement, context, logger)
{
_logger = logger;
_dataModel = new(_detailsElement.Data as IDetailsCommands);
}
public override void InitializeProperties()
{
@@ -31,7 +38,7 @@ public partial class DetailsCommandsViewModel(
.Commands?
.Select(c =>
{
var vm = new CommandViewModel(c, PageContext);
var vm = new CommandViewModel(c, PageContext, _logger);
vm.InitializeProperties();
return vm;
})

View File

@@ -2,11 +2,10 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public abstract partial class DetailsDataViewModel(IPageContext context) : ExtensionObjectViewModel(context)
public abstract partial class DetailsDataViewModel(IPageContext context, ILogger logger) : ExtensionObjectViewModel(context, logger)
{
}

View File

@@ -4,10 +4,11 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public abstract partial class DetailsElementViewModel(IDetailsElement _detailsElement, WeakReference<IPageContext> context) : ExtensionObjectViewModel(context)
public abstract partial class DetailsElementViewModel(IDetailsElement _detailsElement, WeakReference<IPageContext> context, ILogger logger) : ExtensionObjectViewModel(context, logger)
{
private readonly ExtensionObject<IDetailsElement> _model = new(_detailsElement);

View File

@@ -6,12 +6,12 @@ using CommunityToolkit.Mvvm.Input;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class DetailsLinkViewModel(
IDetailsElement _detailsElement,
WeakReference<IPageContext> context) : DetailsElementViewModel(_detailsElement, context)
public partial class DetailsLinkViewModel(IDetailsElement _detailsElement, WeakReference<IPageContext> context, ILogger logger)
: DetailsElementViewModel(_detailsElement, context, logger)
{
private static readonly string[] _initProperties = [
nameof(Text),

View File

@@ -4,12 +4,13 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class DetailsSeparatorViewModel(
IDetailsElement _detailsElement,
WeakReference<IPageContext> context) : DetailsElementViewModel(_detailsElement, context)
WeakReference<IPageContext> context, ILogger logger) : DetailsElementViewModel(_detailsElement, context, logger)
{
private readonly ExtensionObject<IDetailsSeparator> _dataModel =
new(_detailsElement.Data as IDetailsSeparator);

View File

@@ -4,19 +4,25 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class DetailsTagsViewModel(
IDetailsElement _detailsElement,
WeakReference<IPageContext> context) : DetailsElementViewModel(_detailsElement, context)
public partial class DetailsTagsViewModel : DetailsElementViewModel
{
public List<TagViewModel> Tags { get; private set; } = [];
public bool HasTags => Tags.Count > 0;
private readonly ExtensionObject<IDetailsTags> _dataModel =
new(_detailsElement.Data as IDetailsTags);
private readonly ExtensionObject<IDetailsTags> _dataModel;
private readonly ILogger _logger;
public DetailsTagsViewModel(IDetailsElement _detailsElement, WeakReference<IPageContext> context, ILogger logger)
: base(_detailsElement, context, logger)
{
_logger = logger;
_dataModel = new(_detailsElement.Data as IDetailsTags);
}
public override void InitializeProperties()
{
@@ -31,7 +37,7 @@ public partial class DetailsTagsViewModel(
.Tags?
.Select(t =>
{
var vm = new TagViewModel(t, PageContext);
var vm = new TagViewModel(t, PageContext, _logger);
vm.InitializeProperties();
return vm;
})

View File

@@ -4,10 +4,11 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class DetailsViewModel(IDetails _details, WeakReference<IPageContext> context) : ExtensionObjectViewModel(context)
public partial class DetailsViewModel(IDetails _details, WeakReference<IPageContext> context, ILogger logger) : ExtensionObjectViewModel(context, logger)
{
private readonly ExtensionObject<IDetails> _detailsModel = new(_details);
@@ -47,10 +48,10 @@ public partial class DetailsViewModel(IDetails _details, WeakReference<IPageCont
{
DetailsElementViewModel? vm = element.Data switch
{
IDetailsSeparator => new DetailsSeparatorViewModel(element, this.PageContext),
IDetailsLink => new DetailsLinkViewModel(element, this.PageContext),
IDetailsCommands => new DetailsCommandsViewModel(element, this.PageContext),
IDetailsTags => new DetailsTagsViewModel(element, this.PageContext),
IDetailsSeparator => new DetailsSeparatorViewModel(element, this.PageContext, Logger),
IDetailsLink => new DetailsLinkViewModel(element, this.PageContext, Logger),
IDetailsCommands => new DetailsCommandsViewModel(element, this.PageContext, Logger),
IDetailsTags => new DetailsTagsViewModel(element, this.PageContext, Logger),
_ => null,
};
if (vm is not null)

View File

@@ -3,23 +3,29 @@
// See the LICENSE file in the project root for more information.
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.CmdPal.Core.Common;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public abstract partial class ExtensionObjectViewModel : ObservableObject
{
private readonly ILogger _logger;
public ILogger Logger => _logger;
public WeakReference<IPageContext> PageContext { get; set; }
internal ExtensionObjectViewModel(IPageContext? context)
internal ExtensionObjectViewModel(IPageContext? context, ILogger logger)
{
var realContext = context ?? (this is IPageContext c ? c : throw new ArgumentException("You need to pass in an IErrorContext"));
_logger = logger;
PageContext = new(realContext);
}
internal ExtensionObjectViewModel(WeakReference<IPageContext> context)
internal ExtensionObjectViewModel(WeakReference<IPageContext> context, ILogger logger)
{
PageContext = context;
_logger = logger;
}
public async virtual Task InitializePropertiesAsync()
@@ -114,7 +120,10 @@ public abstract partial class ExtensionObjectViewModel : ObservableObject
}
catch (Exception ex)
{
CoreLogger.LogDebug(ex.ToString());
Log_CleanupException(ex);
}
}
[LoggerMessage(Level = LogLevel.Debug)]
partial void Log_CleanupException(Exception exception);
}

View File

@@ -4,6 +4,7 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -23,8 +24,8 @@ public partial class FilterItemViewModel : ExtensionObjectViewModel, IFilterItem
public bool IsInErrorState => Initialized.HasFlag(InitializedState.Error);
public FilterItemViewModel(IFilter filter, WeakReference<IPageContext> context)
: base(context)
public FilterItemViewModel(IFilter filter, WeakReference<IPageContext> context, ILogger logger)
: base(context, logger)
{
_model = new(filter);
}

View File

@@ -2,10 +2,9 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -21,8 +20,8 @@ public partial class FiltersViewModel : ExtensionObjectViewModel
public bool ShouldShowFilters => Filters.Length > 0;
public FiltersViewModel(ExtensionObject<IFilters> filters, WeakReference<IPageContext> context)
: base(context)
public FiltersViewModel(ExtensionObject<IFilters> filters, WeakReference<IPageContext> context, ILogger logger)
: base(context, logger)
{
_filtersModel = filters;
}
@@ -71,7 +70,7 @@ public partial class FiltersViewModel : ExtensionObjectViewModel
{
if (filter is IFilter filterItem)
{
var filterItemViewModel = new FilterItemViewModel(filterItem, PageContext);
var filterItemViewModel = new FilterItemViewModel(filterItem, PageContext, Logger);
filterItemViewModel.InitializeProperties();
if (firstFilterItem is null)

View File

@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.Core.ViewModels.Messages;
namespace Microsoft.CmdPal.Core.ViewModels;
// Represents everything the command bar needs to know about to show command
// buttons at the bottom.
//
// This is implemented by both ListItemViewModel and ContentPageViewModel,
// the two things with sub-commands.
public interface ICommandBarContext : IContextMenuContext
{
public string SecondaryCommandName { get; }
public CommandItemViewModel? PrimaryCommand { get; }
public CommandItemViewModel? SecondaryCommand { get; }
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.CmdPal.Core.ViewModels;
public interface IPageContext
{
void ShowException(Exception ex, string? extensionHint = null);
TaskScheduler Scheduler { get; }
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
public interface IPageViewModelFactoryService
{
/// <summary>
/// Creates a new instance of the page view model for the given page type.
/// </summary>
/// <param name="page">The page for which to create the view model.</param>
/// <param name="nested">Indicates whether the page is not the top-level page.</param>
/// <param name="host">The command palette host that will host the page (for status messages)</param>
/// <returns>A new instance of the page view model.</returns>
PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host);
}

View File

@@ -7,13 +7,14 @@ using Microsoft.CmdPal.Core.ViewModels.Commands;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class ListItemViewModel(IListItem model, WeakReference<IPageContext> context)
: CommandItemViewModel(new(model), context)
// Fix for CS9107: Do not capture 'logger' in the primary constructor; use a regular constructor instead.
public partial class ListItemViewModel : CommandItemViewModel
{
public new ExtensionObject<IListItem> Model { get; } = new(model);
public new ExtensionObject<IListItem> Model { get; }
public List<TagViewModel>? Tags { get; set; }
@@ -32,6 +33,15 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
public string AccessibleName { get; private set; } = string.Empty;
private readonly ILogger _logger;
public ListItemViewModel(IListItem model, WeakReference<IPageContext> context, ILogger logger)
: base(new(model), context, logger)
{
Model = new(model);
_logger = logger;
}
public override void InitializeProperties()
{
if (IsInitialized)
@@ -69,7 +79,7 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
var extensionDetails = model.Details;
if (extensionDetails is not null)
{
Details = new(extensionDetails, PageContext);
Details = new(extensionDetails, PageContext, Logger);
Details.InitializeProperties();
UpdateProperty(nameof(Details));
UpdateProperty(nameof(HasDetails));
@@ -104,7 +114,7 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
break;
case nameof(Details):
var extensionDetails = model.Details;
Details = extensionDetails is not null ? new(extensionDetails, PageContext) : null;
Details = extensionDetails is not null ? new(extensionDetails, PageContext, Logger) : null;
Details?.InitializeProperties();
UpdateProperty(nameof(Details));
UpdateProperty(nameof(HasDetails));
@@ -146,7 +156,7 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
// Create the view model for the show details command
var showDetailsCommand = new ShowDetailsCommand(Details);
var showDetailsContextItem = new CommandContextItem(showDetailsCommand);
var showDetailsContextItemViewModel = new CommandContextItemViewModel(showDetailsContextItem, PageContext);
var showDetailsContextItemViewModel = new CommandContextItemViewModel(showDetailsContextItem, PageContext, _logger);
showDetailsContextItemViewModel.SlowInitializeProperties();
MoreCommands.Add(showDetailsContextItemViewModel);
}
@@ -180,7 +190,7 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
// Create the view model for the show details command
var showDetailsCommand = new ShowDetailsCommand(Details);
var showDetailsContextItem = new CommandContextItem(showDetailsCommand);
var showDetailsContextItemViewModel = new CommandContextItemViewModel(showDetailsContextItem, PageContext);
var showDetailsContextItemViewModel = new CommandContextItemViewModel(showDetailsContextItem, PageContext, _logger);
showDetailsContextItemViewModel.SlowInitializeProperties();
MoreCommands.Add(showDetailsContextItemViewModel);
@@ -193,7 +203,7 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
{
var newTags = newTagsFromModel?.Select(t =>
{
var vm = new TagViewModel(t, PageContext);
var vm = new TagViewModel(t, PageContext, Logger);
vm.InitializeProperties();
return vm;
})

View File

@@ -11,6 +11,7 @@ using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
using Windows.Foundation;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -19,6 +20,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
{
// private readonly HashSet<ListItemViewModel> _itemCache = [];
private readonly TaskFactory filterTaskFactory = new(new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler);
private readonly ILogger _logger;
// TODO: Do we want a base "ItemsPageViewModel" for anything that's going to have items?
@@ -90,11 +92,12 @@ public partial class ListViewModel : PageViewModel, IDisposable
}
}
public ListViewModel(IListPage model, TaskScheduler scheduler, AppExtensionHost host)
: base(model, scheduler, host)
public ListViewModel(IListPage model, TaskScheduler scheduler, AppExtensionHost host, ILogger logger)
: base(model, host, logger)
{
_model = new(model);
EmptyContent = new(new(null), PageContext);
EmptyContent = new(new(null), PageContext, logger);
_logger = logger;
}
private void FiltersPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
@@ -232,7 +235,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
return;
}
ListItemViewModel viewModel = new(item, new(this));
ListItemViewModel viewModel = new(item, new(this), _logger);
// If an item fails to load, silently ignore it.
if (viewModel.SafeFastInit())
@@ -594,11 +597,11 @@ public partial class ListViewModel : PageViewModel, IDisposable
UpdateProperty(nameof(SearchText));
UpdateProperty(nameof(InitialSearchText));
EmptyContent = new(new(model.EmptyContent), PageContext);
EmptyContent = new(new(model.EmptyContent), PageContext, _logger);
EmptyContent.SlowInitializeProperties();
Filters?.PropertyChanged -= FiltersPropertyChanged;
Filters = new(new(model.Filters), PageContext);
Filters = new(new(model.Filters), PageContext, _logger);
Filters?.PropertyChanged += FiltersPropertyChanged;
Filters?.InitializeProperties();
@@ -696,12 +699,12 @@ public partial class ListViewModel : PageViewModel, IDisposable
SearchText = model.SearchText;
break;
case nameof(EmptyContent):
EmptyContent = new(new(model.EmptyContent), PageContext);
EmptyContent = new(new(model.EmptyContent), PageContext, _logger);
EmptyContent.SlowInitializeProperties();
break;
case nameof(Filters):
Filters?.PropertyChanged -= FiltersPropertyChanged;
Filters = new(new(model.Filters), PageContext);
Filters = new(new(model.Filters), PageContext, _logger);
Filters?.PropertyChanged += FiltersPropertyChanged;
Filters?.InitializeProperties();
break;
@@ -751,7 +754,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
base.UnsafeCleanup();
EmptyContent?.SafeCleanup();
EmptyContent = new(new(null), PageContext); // necessary?
EmptyContent = new(new(null), PageContext, _logger); // necessary?
_cancellationTokenSource?.Cancel();
filterCancellationTokenSource?.Cancel();

View File

@@ -3,13 +3,14 @@
// See the LICENSE file in the project root for more information.
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class LoadingPageViewModel : PageViewModel
{
public LoadingPageViewModel(IPage? model, TaskScheduler scheduler, AppExtensionHost host)
: base(model, scheduler, host)
public LoadingPageViewModel(IPage? model, AppExtensionHost host, ILogger logger)
: base(model, host, logger)
{
ModelIsLoading = true;
IsInitialized = false;

View File

@@ -4,6 +4,7 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -13,8 +14,8 @@ public partial class LogMessageViewModel : ExtensionObjectViewModel
public string Message { get; private set; } = string.Empty;
public LogMessageViewModel(ILogMessage message, IPageContext context)
: base(context)
public LogMessageViewModel(ILogMessage message, IPageContext context, ILogger logger)
: base(context, logger)
{
_model = new(message);
}

View File

@@ -7,6 +7,4 @@ namespace Microsoft.CmdPal.Core.ViewModels.Messages;
/// <summary>
/// Used to perform a list item's secondary command when the user presses ctrl+enter in the search box
/// </summary>
public record ActivateSecondaryCommandMessage
{
}
public record ActivateSecondaryCommandMessage;

View File

@@ -7,6 +7,4 @@ namespace Microsoft.CmdPal.Core.ViewModels.Messages;
/// <summary>
/// Used to perform a list item's command when the user presses enter in the search box
/// </summary>
public record ActivateSelectedListItemMessage
{
}
public record ActivateSelectedListItemMessage;

View File

@@ -4,6 +4,4 @@
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record ClearSearchMessage()
{
}
public record ClearSearchMessage();

View File

@@ -7,6 +7,4 @@ namespace Microsoft.CmdPal.Core.ViewModels.Messages;
/// <summary>
/// Used to announce that a context menu should close
/// </summary>
public record CloseContextMenuMessage
{
}
public record CloseContextMenuMessage;

View File

@@ -4,6 +4,4 @@
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record DismissMessage()
{
}
public record DismissMessage();

View File

@@ -4,6 +4,4 @@
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record FocusSearchBoxMessage()
{
}
public record FocusSearchBoxMessage();

View File

@@ -4,7 +4,5 @@
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record GoBackMessage(bool WithAnimation = true, bool FocusSearch = true)
{
// TODO! sticking these properties here feels like leaking the UI into the models
}
// TODO! sticking these properties here feels like leaking the UI into the models
public record GoBackMessage(bool WithAnimation = true, bool FocusSearch = true);

View File

@@ -5,6 +5,4 @@
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
// TODO! sticking these properties here feels like leaking the UI into the models
public record GoHomeMessage(bool WithAnimation = true, bool FocusSearch = true)
{
}
public record GoHomeMessage(bool WithAnimation = true, bool FocusSearch = true);

View File

@@ -7,6 +7,4 @@ using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record HandleCommandResultMessage(ExtensionObject<ICommandResult> Result)
{
}
public record HandleCommandResultMessage(ExtensionObject<ICommandResult> Result);

View File

@@ -2,11 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record HideDetailsMessage()
{
}
public record HideDetailsMessage();

View File

@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public interface IContextMenuContext : INotifyPropertyChanged
{
public IEnumerable<IContextItemViewModel> MoreCommands { get; }
public bool HasMoreCommands { get; }
public List<IContextItemViewModel> AllCommands { get; }
/// <summary>
/// Generates a mapping of key -> command item for this particular item's
/// MoreCommands. (This won't include the primary Command, but it will
/// include the secondary one). This map can be used to quickly check if a
/// shortcut key was pressed
/// </summary>
/// <returns>a dictionary of KeyChord -> Context commands, for all commands
/// that have a shortcut key set.</returns>
public Dictionary<KeyChord, CommandContextItemViewModel> Keybindings()
{
var result = new Dictionary<KeyChord, CommandContextItemViewModel>();
var menu = MoreCommands;
if (menu is null)
{
return result;
}
foreach (var item in menu)
{
if (item is CommandContextItemViewModel cmd && cmd.HasRequestedShortcut)
{
var key = cmd.RequestedShortcut ?? new KeyChord(0, 0, 0);
var added = result.TryAdd(key, cmd);
}
}
return result;
}
}

View File

@@ -2,11 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record LaunchUriMessage(Uri Uri)
{
}
public record LaunchUriMessage(Uri Uri);

View File

@@ -4,6 +4,4 @@
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record NavigateBackMessage(bool FromBackspace = false)
{
}
public record NavigateBackMessage(bool FromBackspace = false);

View File

@@ -7,6 +7,4 @@ namespace Microsoft.CmdPal.Core.ViewModels.Commands;
/// <summary>
/// Used to navigate to the next command in the page when pressing the Down key in the SearchBox.
/// </summary>
public record NavigateNextCommand
{
}
public record NavigateNextCommand;

View File

@@ -7,6 +7,4 @@ namespace Microsoft.CmdPal.Core.ViewModels.Messages;
/// <summary>
/// Used to navigate down one page in the page when pressing the PageDown key in the SearchBox.
/// </summary>
public record NavigatePageDownCommand
{
}
public record NavigatePageDownCommand;

View File

@@ -7,6 +7,4 @@ namespace Microsoft.CmdPal.Core.ViewModels.Messages;
/// <summary>
/// Used to navigate up one page in the page when pressing the PageUp key in the SearchBox.
/// </summary>
public record NavigatePageUpCommand
{
}
public record NavigatePageUpCommand;

View File

@@ -7,6 +7,4 @@ namespace Microsoft.CmdPal.Core.ViewModels.Messages;
/// <summary>
/// Used to navigate to the previous command in the page when pressing the Down key in the SearchBox.
/// </summary>
public record NavigatePreviousCommand
{
}
public record NavigatePreviousCommand;

View File

@@ -4,6 +4,4 @@
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record ShowConfirmationMessage(Microsoft.CommandPalette.Extensions.IConfirmationArgs? Args)
{
}
public record ShowConfirmationMessage(Microsoft.CommandPalette.Extensions.IConfirmationArgs? Args);

View File

@@ -2,11 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record ShowDetailsMessage(DetailsViewModel Details)
{
}
public record ShowDetailsMessage(DetailsViewModel Details);

View File

@@ -4,6 +4,4 @@
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record ShowToastMessage(string Message)
{
}
public record ShowToastMessage(string Message);

View File

@@ -4,6 +4,4 @@
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record ShowWindowMessage(IntPtr Hwnd)
{
}
public record ShowWindowMessage(IntPtr Hwnd);

View File

@@ -2,73 +2,9 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using Microsoft.CmdPal.Core.Common;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
/// <summary>
/// Used to update the command bar at the bottom to reflect the commands for a list item
/// </summary>
public record UpdateCommandBarMessage(ICommandBarContext? ViewModel)
{
}
public interface IContextMenuContext : INotifyPropertyChanged
{
public IEnumerable<IContextItemViewModel> MoreCommands { get; }
public bool HasMoreCommands { get; }
public List<IContextItemViewModel> AllCommands { get; }
/// <summary>
/// Generates a mapping of key -> command item for this particular item's
/// MoreCommands. (This won't include the primary Command, but it will
/// include the secondary one). This map can be used to quickly check if a
/// shortcut key was pressed
/// </summary>
/// <returns>a dictionary of KeyChord -> Context commands, for all commands
/// that have a shortcut key set.</returns>
public Dictionary<KeyChord, CommandContextItemViewModel> Keybindings()
{
var result = new Dictionary<KeyChord, CommandContextItemViewModel>();
var menu = MoreCommands;
if (menu is null)
{
return result;
}
foreach (var item in menu)
{
if (item is CommandContextItemViewModel cmd && cmd.HasRequestedShortcut)
{
var key = cmd.RequestedShortcut ?? new KeyChord(0, 0, 0);
var added = result.TryAdd(key, cmd);
if (!added)
{
CoreLogger.LogWarning($"Ignoring duplicate keyboard shortcut {KeyChordHelpers.FormatForDebug(key)} on command '{cmd.Title ?? cmd.Name ?? "(unknown)"}'");
}
}
}
return result;
}
}
// Represents everything the command bar needs to know about to show command
// buttons at the bottom.
//
// This is implemented by both ListItemViewModel and ContentPageViewModel,
// the two things with sub-commands.
public interface ICommandBarContext : IContextMenuContext
{
public string SecondaryCommandName { get; }
public CommandItemViewModel? PrimaryCommand { get; }
public CommandItemViewModel? SecondaryCommand { get; }
}
public record UpdateCommandBarMessage(ICommandBarContext? ViewModel);

View File

@@ -4,6 +4,4 @@
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record UpdateSuggestionMessage(string TextToSuggest)
{
}
public record UpdateSuggestionMessage(string TextToSuggest);

View File

@@ -2,7 +2,9 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
internal sealed partial class NullPageViewModel(TaskScheduler scheduler, AppExtensionHost extensionHost)
: PageViewModel(null, scheduler, extensionHost);
internal sealed partial class NullPageViewModel(AppExtensionHost extensionHost, ILogger logger)
: PageViewModel(null, extensionHost, logger);

View File

@@ -8,15 +8,16 @@ using CommunityToolkit.Mvvm.Input;
using Microsoft.CmdPal.Core.Common.Helpers;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
{
public TaskScheduler Scheduler { get; private set; }
private readonly ExtensionObject<IPage> _pageModel;
public TaskScheduler Scheduler { get; private set; } = TaskScheduler.FromCurrentSynchronizationContext();
public bool IsLoading => ModelIsLoading || (!IsInitialized);
[ObservableProperty]
@@ -76,11 +77,10 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
public IconInfoViewModel Icon { get; protected set; }
public PageViewModel(IPage? model, TaskScheduler scheduler, AppExtensionHost extensionHost)
: base((IPageContext?)null)
public PageViewModel(IPage? model, AppExtensionHost extensionHost, ILogger logger)
: base((IPageContext?)null, logger)
{
_pageModel = new(model);
Scheduler = scheduler;
PageContext = new(this);
ExtensionHost = extensionHost;
Icon = new(null);
@@ -258,22 +258,3 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
}
}
}
public interface IPageContext
{
void ShowException(Exception ex, string? extensionHint = null);
TaskScheduler Scheduler { get; }
}
public interface IPageViewModelFactoryService
{
/// <summary>
/// Creates a new instance of the page view model for the given page type.
/// </summary>
/// <param name="page">The page for which to create the view model.</param>
/// <param name="nested">Indicates whether the page is not the top-level page.</param>
/// <param name="host">The command palette host that will host the page (for status messages)</param>
/// <returns>A new instance of the page view model.</returns>
PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host);
}

View File

@@ -4,6 +4,7 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -15,8 +16,8 @@ public partial class ProgressViewModel : ExtensionObjectViewModel
public uint ProgressPercent { get; private set; }
public ProgressViewModel(IProgressState progress, WeakReference<IPageContext> context)
: base(context)
public ProgressViewModel(IProgressState progress, WeakReference<IPageContext> context, ILogger logger)
: base(context, logger)
{
Model = new(progress);
}

View File

@@ -6,10 +6,10 @@ using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.Common;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -18,9 +18,10 @@ public partial class ShellViewModel : ObservableObject,
IRecipient<HandleCommandResultMessage>
{
private readonly IRootPageService _rootPageService;
private readonly IAppHostService _appHostService;
private readonly TaskScheduler _scheduler;
private readonly AppExtensionHost _appHost;
private readonly TaskScheduler _scheduler = TaskScheduler.FromCurrentSynchronizationContext();
private readonly IPageViewModelFactoryService _pageViewModelFactory;
private readonly ILogger _logger;
private readonly Lock _invokeLock = new();
private Task? _handleInvokeTask;
@@ -60,7 +61,7 @@ public partial class ShellViewModel : ObservableObject,
}
catch (Exception ex)
{
CoreLogger.LogError(ex.ToString());
Log_Exception(ex);
}
}
}
@@ -84,18 +85,18 @@ public partial class ShellViewModel : ObservableObject,
public PageViewModel NullPage { get; private set; }
public ShellViewModel(
TaskScheduler scheduler,
IRootPageService rootPageService,
IPageViewModelFactoryService pageViewModelFactory,
IAppHostService appHostService)
AppExtensionHost appHost,
ILogger<ShellViewModel> logger)
{
_pageViewModelFactory = pageViewModelFactory;
_scheduler = scheduler;
_rootPageService = rootPageService;
_appHostService = appHostService;
_appHost = appHost;
_logger = logger;
NullPage = new NullPageViewModel(_scheduler, appHostService.GetDefaultHost());
_currentPage = new LoadingPageViewModel(null, _scheduler, appHostService.GetDefaultHost());
NullPage = new NullPageViewModel(_appHost, _logger);
_currentPage = new LoadingPageViewModel(null, _appHost, _logger);
// Register to receive messages
WeakReferenceMessenger.Default.Register<PerformCommandMessage>(this);
@@ -162,7 +163,7 @@ public partial class ShellViewModel : ObservableObject,
{
if (viewModel.InitializeCommand.ExecutionTask.Exception is AggregateException ex)
{
CoreLogger.LogError(ex.ToString());
Log_Exception(ex);
}
}
else
@@ -180,7 +181,7 @@ public partial class ShellViewModel : ObservableObject,
}
catch (Exception ex)
{
CoreLogger.LogError(ex.ToString());
Log_Exception(ex);
}
}
@@ -210,7 +211,7 @@ public partial class ShellViewModel : ObservableObject,
}
catch (Exception ex)
{
CoreLogger.LogError(ex.ToString());
Log_Exception(ex);
}
}
@@ -240,7 +241,7 @@ public partial class ShellViewModel : ObservableObject,
}
catch (Exception ex)
{
CoreLogger.LogError(ex.ToString());
Log_Exception(ex);
}
finally
{
@@ -256,7 +257,7 @@ public partial class ShellViewModel : ObservableObject,
return;
}
var host = _appHostService.GetHostForCommand(message.Context, CurrentPage.ExtensionHost);
var host = _appHost.GetHostForCommand(message.Context, CurrentPage.ExtensionHost);
_rootPageService.OnPerformCommand(message.Context, !CurrentPage.IsNested, host);
@@ -264,7 +265,7 @@ public partial class ShellViewModel : ObservableObject,
{
if (command is IPage page)
{
CoreLogger.LogDebug($"Navigating to page");
Log_NavigateToPage();
var isMainPage = command == _rootPage;
_isNested = !isMainPage;
@@ -273,7 +274,7 @@ public partial class ShellViewModel : ObservableObject,
var pageViewModel = _pageViewModelFactory.TryCreatePageViewModel(page, _isNested, host);
if (pageViewModel is null)
{
CoreLogger.LogError($"Failed to create ViewModel for page {page.GetType().Name}");
Log_FailedToCreateViewModel(page.GetType().Name);
throw new NotSupportedException();
}
@@ -303,7 +304,7 @@ public partial class ShellViewModel : ObservableObject,
}
else if (command is IInvokableCommand invokable)
{
CoreLogger.LogDebug($"Invoking command");
Log_InvokingCommand();
WeakReferenceMessenger.Default.Send<BeginInvokeMessage>();
StartInvoke(message, invokable, host);
@@ -369,7 +370,7 @@ public partial class ShellViewModel : ObservableObject,
}
var kind = result.Kind;
CoreLogger.LogDebug($"handling {kind.ToString()}");
Log_HandlingCommandResult(kind.ToString());
WeakReferenceMessenger.Default.Send<CmdPalInvokeResultMessage>(new(kind));
switch (kind)
@@ -460,4 +461,19 @@ public partial class ShellViewModel : ObservableObject,
{
_navigationCts?.Cancel();
}
[LoggerMessage(Level = LogLevel.Error)]
partial void Log_Exception(Exception exception);
[LoggerMessage(Level = LogLevel.Debug, Message = "Navigating to page")]
partial void Log_NavigateToPage();
[LoggerMessage(Level = LogLevel.Error, Message = "Failed to create ViewModel for page {PageTypeName}")]
partial void Log_FailedToCreateViewModel(string pageTypeName);
[LoggerMessage(Level = LogLevel.Debug, Message = "Invoking command")]
partial void Log_InvokingCommand();
[LoggerMessage(Level = LogLevel.Debug, Message = "Handling {CommandResultKind}")]
partial void Log_HandlingCommandResult(string commandResultKind);
}

View File

@@ -4,6 +4,7 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -19,8 +20,8 @@ public partial class StatusMessageViewModel : ExtensionObjectViewModel
public bool HasProgress => Progress is not null;
public StatusMessageViewModel(IStatusMessage message, WeakReference<IPageContext> context)
: base(context)
public StatusMessageViewModel(IStatusMessage message, WeakReference<IPageContext> context, ILogger logger)
: base(context, logger)
{
Model = new(message);
}
@@ -38,7 +39,7 @@ public partial class StatusMessageViewModel : ExtensionObjectViewModel
var modelProgress = model.Progress;
if (modelProgress is not null)
{
Progress = new(modelProgress, this.PageContext);
Progress = new(modelProgress, this.PageContext, Logger);
Progress.InitializeProperties();
UpdateProperty(nameof(HasProgress));
}
@@ -78,7 +79,7 @@ public partial class StatusMessageViewModel : ExtensionObjectViewModel
var modelProgress = model.Progress;
if (modelProgress is not null)
{
Progress = new(modelProgress, this.PageContext);
Progress = new(modelProgress, this.PageContext, Logger);
Progress.InitializeProperties();
}
else

View File

@@ -4,10 +4,11 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class TagViewModel(ITag _tag, WeakReference<IPageContext> context) : ExtensionObjectViewModel(context)
public partial class TagViewModel(ITag _tag, WeakReference<IPageContext> context, ILogger logger) : ExtensionObjectViewModel(context, logger)
{
private readonly ExtensionObject<ITag> _tagModel = new(_tag);

View File

@@ -4,23 +4,20 @@
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class CommandPaletteContentPageViewModel : ContentPageViewModel
public partial class CommandPaletteContentPageViewModel(IContentPage model, AppExtensionHost host, ILogger logger)
: ContentPageViewModel(model, host, logger)
{
public CommandPaletteContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host)
: base(model, scheduler, host)
{
}
public override ContentViewModel? ViewModelFromContent(IContent content, WeakReference<IPageContext> context)
{
ContentViewModel? viewModel = content switch
{
IFormContent form => new ContentFormViewModel(form, context),
IMarkdownContent markdown => new ContentMarkdownViewModel(markdown, context),
ITreeContent tree => new ContentTreeViewModel(tree, context),
IFormContent form => new ContentFormViewModel(form, context, Logger),
IMarkdownContent markdown => new ContentMarkdownViewModel(markdown, context, Logger),
ITreeContent tree => new ContentTreeViewModel(tree, context, Logger),
_ => null,
};
return viewModel;

View File

@@ -5,29 +5,29 @@
using Microsoft.CmdPal.Core.Common.Services;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.UI.ViewModels;
public sealed partial class CommandPaletteHost : AppExtensionHost, IExtensionHost
{
// Static singleton, so that we can access this from anywhere
// Post MVVM - this should probably be like, a dependency injection thing.
public static CommandPaletteHost Instance { get; } = new();
public IExtensionWrapper? Extension { get; }
private readonly ICommandProvider? _builtInProvider;
private CommandPaletteHost()
public CommandPaletteHost(ILogger logger)
: base(logger)
{
}
public CommandPaletteHost(IExtensionWrapper source)
public CommandPaletteHost(IExtensionWrapper source, ILogger logger)
: base(logger)
{
Extension = source;
}
public CommandPaletteHost(ICommandProvider builtInProvider)
public CommandPaletteHost(ICommandProvider builtInProvider, ILogger logger)
: base(logger)
{
_builtInProvider = builtInProvider;
}
@@ -36,4 +36,15 @@ public sealed partial class CommandPaletteHost : AppExtensionHost, IExtensionHos
{
return Extension?.ExtensionDisplayName;
}
public override AppExtensionHost GetHostForCommand(object? context, AppExtensionHost? currentHost)
{
AppExtensionHost? topLevelHost = null;
if (context is TopLevelViewModel topLevelViewModel)
{
topLevelHost = topLevelViewModel.ExtensionHost;
}
return topLevelHost ?? currentHost ?? this;
}
}

View File

@@ -4,25 +4,27 @@
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.UI.ViewModels;
public class CommandPalettePageViewModelFactory
: IPageViewModelFactoryService
{
private readonly TaskScheduler _scheduler;
private readonly TaskScheduler _scheduler = TaskScheduler.FromCurrentSynchronizationContext();
private readonly ILogger _logger;
public CommandPalettePageViewModelFactory(TaskScheduler scheduler)
public CommandPalettePageViewModelFactory(ILogger logger)
{
_scheduler = scheduler;
_logger = logger;
}
public PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host)
{
return page switch
{
IListPage listPage => new ListViewModel(listPage, _scheduler, host) { IsNested = nested },
IContentPage contentPage => new CommandPaletteContentPageViewModel(contentPage, _scheduler, host),
IListPage listPage => new ListViewModel(listPage, _scheduler, host, _logger) { IsNested = nested },
IContentPage contentPage => new CommandPaletteContentPageViewModel(contentPage, host, _logger),
_ => null,
};
}

View File

@@ -2,22 +2,23 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using ManagedCommon;
using Microsoft.CmdPal.Core.Common.Services;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Windows.Foundation;
namespace Microsoft.CmdPal.UI.ViewModels;
public sealed class CommandProviderWrapper
public sealed partial class CommandProviderWrapper
{
public bool IsExtension => Extension is not null;
private readonly bool isValid;
private readonly ILogger _logger;
private readonly AliasManager _aliasManager;
private readonly HotkeyManager _hotKeyManager;
private readonly ExtensionObject<ICommandProvider> _commandProvider;
@@ -51,15 +52,18 @@ public sealed class CommandProviderWrapper
}
}
public CommandProviderWrapper(ICommandProvider provider, TaskScheduler mainThread)
public CommandProviderWrapper(ICommandProvider provider, TaskScheduler mainThread, AliasManager aliasManager, HotkeyManager hotkeyManager, ILogger logger)
{
// This ctor is only used for in-proc builtin commands. So the Unsafe!
// calls are pretty dang safe actually.
_commandProvider = new(provider);
_taskScheduler = mainThread;
_logger = logger;
_aliasManager = aliasManager;
_hotKeyManager = hotkeyManager;
// Hook the extension back into us
ExtensionHost = new CommandPaletteHost(provider);
ExtensionHost = new CommandPaletteHost(provider, logger);
_commandProvider.Unsafe!.InitializeWithHost(ExtensionHost);
_commandProvider.Unsafe!.ItemsChanged += CommandProvider_ItemsChanged;
@@ -72,16 +76,20 @@ public sealed class CommandProviderWrapper
// Note: explicitly not InitializeProperties()ing the settings here. If
// we do that, then we'd regress GH #38321
Settings = new(provider.Settings, this, _taskScheduler);
Settings = new(provider.Settings, this, _taskScheduler, _logger);
Logger.LogDebug($"Initialized command provider {ProviderId}");
Log_CommandProviderInitialized(ProviderId);
}
public CommandProviderWrapper(IExtensionWrapper extension, TaskScheduler mainThread)
public CommandProviderWrapper(IExtensionWrapper extension, TaskScheduler mainThread, AliasManager aliasManager, HotkeyManager hotkeyManager, ILogger logger)
{
_taskScheduler = mainThread;
_logger = logger;
_aliasManager = aliasManager;
_hotKeyManager = hotkeyManager;
Extension = extension;
ExtensionHost = new CommandPaletteHost(extension);
ExtensionHost = new CommandPaletteHost(extension, logger);
if (!Extension.IsRunning())
{
throw new ArgumentException("You forgot to start the extension. This is a CmdPal error - we need to make sure to call StartExtensionAsync");
@@ -106,13 +114,11 @@ public sealed class CommandProviderWrapper
isValid = true;
Logger.LogDebug($"Initialized extension command provider {Extension.PackageFamilyName}:{Extension.ExtensionUniqueId}");
Log_ExtensionInitialized(Extension.PackageFamilyName, Extension.ExtensionUniqueId);
}
catch (Exception e)
{
Logger.LogError("Failed to initialize CommandProvider for extension.");
Logger.LogError($"Extension was {Extension!.PackageFamilyName}");
Logger.LogError(e.ToString());
Log_FailedToInitializeCommandProviderForExtension(Extension!.PackageFamilyName, e);
}
isValid = true;
@@ -123,7 +129,7 @@ public sealed class CommandProviderWrapper
return settings.GetProviderSettings(this);
}
public async Task LoadTopLevelCommands(IServiceProvider serviceProvider, WeakReference<IPageContext> pageContext)
public async Task LoadTopLevelCommands(SettingsModel settingsModel, WeakReference<IPageContext> pageContext)
{
if (!isValid)
{
@@ -131,9 +137,7 @@ public sealed class CommandProviderWrapper
return;
}
var settings = serviceProvider.GetService<SettingsModel>()!;
IsActive = GetProviderSettings(settings).IsEnabled;
IsActive = GetProviderSettings(settingsModel).IsEnabled;
if (!IsActive)
{
return;
@@ -165,30 +169,27 @@ public sealed class CommandProviderWrapper
// Note: explicitly not InitializeProperties()ing the settings here. If
// we do that, then we'd regress GH #38321
Settings = new(model.Settings, this, _taskScheduler);
Settings = new(model.Settings, this, _taskScheduler, _logger);
// We do need to explicitly initialize commands though
InitializeCommands(commands, fallbacks, serviceProvider, pageContext);
InitializeCommands(commands, fallbacks, settingsModel, pageContext);
Logger.LogDebug($"Loaded commands from {DisplayName} ({ProviderId})");
Log_LoadedCommandsFromExtension(DisplayName, ProviderId);
}
catch (Exception e)
{
Logger.LogError("Failed to load commands from extension");
Logger.LogError($"Extension was {Extension!.PackageFamilyName}");
Logger.LogError(e.ToString());
Log_FailedToLoadCommandsFromProvider(Extension!.PackageFamilyName, e);
}
}
private void InitializeCommands(ICommandItem[] commands, IFallbackCommandItem[] fallbacks, IServiceProvider serviceProvider, WeakReference<IPageContext> pageContext)
private void InitializeCommands(ICommandItem[] commands, IFallbackCommandItem[] fallbacks, SettingsModel settingsModel, WeakReference<IPageContext> pageContext)
{
var settings = serviceProvider.GetService<SettingsModel>()!;
var providerSettings = GetProviderSettings(settings);
var providerSettings = GetProviderSettings(settingsModel);
Func<ICommandItem?, bool, TopLevelViewModel> makeAndAdd = (ICommandItem? i, bool fallback) =>
{
CommandItemViewModel commandItemViewModel = new(new(i), pageContext);
TopLevelViewModel topLevelViewModel = new(commandItemViewModel, fallback, ExtensionHost, ProviderId, settings, providerSettings, serviceProvider);
CommandItemViewModel commandItemViewModel = new(new(i), pageContext, _logger);
TopLevelViewModel topLevelViewModel = new(commandItemViewModel, fallback, ExtensionHost, ProviderId, settingsModel, providerSettings, _aliasManager, _hotKeyManager);
topLevelViewModel.InitializeProperties();
return topLevelViewModel;
@@ -211,12 +212,13 @@ public sealed class CommandProviderWrapper
private void UnsafePreCacheApiAdditions(ICommandProvider2 provider)
{
var apiExtensions = provider.GetApiExtensionStubs();
Logger.LogDebug($"Provider supports {apiExtensions.Length} extensions");
Log_ProviderCount(apiExtensions.Length);
foreach (var a in apiExtensions)
{
if (a is IExtendedAttributesProvider command2)
{
Logger.LogDebug($"{ProviderId}: Found an IExtendedAttributesProvider");
Log_IExtendedAttributesProviderFound(ProviderId);
}
}
}
@@ -234,4 +236,25 @@ public sealed class CommandProviderWrapper
// In handling this, a call will be made to `LoadTopLevelCommands` to
// retrieve the new items.
this.CommandsChanged?.Invoke(this, args);
[LoggerMessage(Level = LogLevel.Debug, Message = "Initialized CommandProvider '{ProviderId}'")]
partial void Log_CommandProviderInitialized(string providerId);
[LoggerMessage(Level = LogLevel.Debug, Message = "{ProviderId}: Found an IExtendedAttributesProvider")]
partial void Log_IExtendedAttributesProviderFound(string providerId);
[LoggerMessage(Level = LogLevel.Debug, Message = "Provider exposed {Count} API extensions")]
partial void Log_ProviderCount(int count);
[LoggerMessage(Level = LogLevel.Debug, Message = "Initialized CommandProvider from extension '{PackageFamilyName}' ({ExtensionId})")]
partial void Log_ExtensionInitialized(string packageFamilyName, string extensionId);
[LoggerMessage(Level = LogLevel.Debug, Message = "Loaded commands from {DisplayName} ({ProviderId})")]
partial void Log_LoadedCommandsFromExtension(string displayName, string providerId);
[LoggerMessage(Level = LogLevel.Error, Message = "Failed to load commands from extension '{PackageFamilyName}'")]
partial void Log_FailedToLoadCommandsFromProvider(string packageFamilyName, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "Failed to initialize CommandProvider for extension '{PackageFamilyName}'")]
partial void Log_FailedToInitializeCommandProviderForExtension(string packageFamilyName, Exception exception);
}

View File

@@ -2,14 +2,14 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.Core.Common;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class CommandSettingsViewModel(ICommandSettings? _unsafeSettings, CommandProviderWrapper provider, TaskScheduler mainThread)
public partial class CommandSettingsViewModel(ICommandSettings? _unsafeSettings, CommandProviderWrapper provider, TaskScheduler mainThread, ILogger logger)
{
private readonly ExtensionObject<ICommandSettings> _model = new(_unsafeSettings);
@@ -31,7 +31,7 @@ public partial class CommandSettingsViewModel(ICommandSettings? _unsafeSettings,
if (model.SettingsPage is not null)
{
SettingsPage = new CommandPaletteContentPageViewModel(model.SettingsPage, mainThread, provider.ExtensionHost);
SettingsPage = new CommandPaletteContentPageViewModel(model.SettingsPage, provider.ExtensionHost, logger);
SettingsPage.InitializeProperties();
}
}
@@ -44,7 +44,7 @@ public partial class CommandSettingsViewModel(ICommandSettings? _unsafeSettings,
}
catch (Exception ex)
{
CoreLogger.LogError($"Failed to load settings page", ex: ex);
Log_FailedToLoadSettingsPage(ex);
}
Initialized = true;
@@ -58,4 +58,7 @@ public partial class CommandSettingsViewModel(ICommandSettings? _unsafeSettings,
TaskCreationOptions.None,
mainThread);
}
[LoggerMessage(Level = LogLevel.Error, Message = "Failed to load settings page")]
partial void Log_FailedToLoadSettingsPage(Exception ex);
}

View File

@@ -38,7 +38,6 @@ public partial class MainListPage : DynamicListPage,
"com.microsoft.cmdpal.builtin.datetime",
];
private readonly IServiceProvider _serviceProvider;
private readonly TopLevelCommandManager _tlcManager;
private List<Scored<IListItem>>? _filteredItems;
private List<Scored<IListItem>>? _filteredApps;
@@ -53,14 +52,13 @@ public partial class MainListPage : DynamicListPage,
private CancellationTokenSource? _cancellationTokenSource;
public MainListPage(IServiceProvider serviceProvider)
public MainListPage(TopLevelCommandManager topLevelCommandManager, SettingsModel settingsModel)
{
Title = Resources.builtin_home_name;
Icon = IconHelpers.FromRelativePath("Assets\\StoreLogo.scale-200.png");
PlaceholderText = Properties.Resources.builtin_main_list_page_searchbar_placeholder;
_serviceProvider = serviceProvider;
_tlcManager = _serviceProvider.GetService<TopLevelCommandManager>()!;
_tlcManager = topLevelCommandManager;
_tlcManager.PropertyChanged += TlcManager_PropertyChanged;
_tlcManager.TopLevelCommands.CollectionChanged += Commands_CollectionChanged;
@@ -78,7 +76,7 @@ public partial class MainListPage : DynamicListPage,
WeakReferenceMessenger.Default.Register<ClearSearchMessage>(this);
WeakReferenceMessenger.Default.Register<UpdateFallbackItemsMessage>(this);
var settings = _serviceProvider.GetService<SettingsModel>()!;
var settings = settingsModel;
settings.SettingsChanged += SettingsChangedHandler;
HotReloadSettings(settings);
_includeApps = _tlcManager.IsProviderActive(AllAppsCommandProvider.WellKnownId);

View File

@@ -7,19 +7,26 @@ using System.Text.Json;
using AdaptiveCards.ObjectModel.WinUI3;
using AdaptiveCards.Templating;
using CommunityToolkit.Mvvm.Messaging;
using ManagedCommon;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
using Windows.Data.Json;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class ContentFormViewModel(IFormContent _form, WeakReference<IPageContext> context) :
ContentViewModel(context)
public partial class ContentFormViewModel : ContentViewModel
{
private readonly ExtensionObject<IFormContent> _formModel = new(_form);
private readonly ExtensionObject<IFormContent> _formModel;
private readonly ILogger _logger;
public ContentFormViewModel(IFormContent _form, WeakReference<IPageContext> context, ILogger logger)
: base(context, logger)
{
_formModel = new(_form);
_logger = logger;
}
// Remember - "observable" properties from the model (via PropChanged)
// cannot be marked [ObservableProperty]
@@ -38,7 +45,8 @@ public partial class ContentFormViewModel(IFormContent _form, WeakReference<IPag
string templateJson,
string dataJson,
out AdaptiveCardParseResult? card,
out Exception? error)
out Exception? error,
ILogger logger)
{
card = null;
error = null;
@@ -52,7 +60,7 @@ public partial class ContentFormViewModel(IFormContent _form, WeakReference<IPag
}
catch (Exception ex)
{
Logger.LogError("Error building card from template", ex);
Log_ErrorBuildindCard(logger, ex);
error = ex;
return false;
}
@@ -70,7 +78,7 @@ public partial class ContentFormViewModel(IFormContent _form, WeakReference<IPag
StateJson = model.StateJson;
DataJson = model.DataJson;
if (TryBuildCard(TemplateJson, DataJson, out var builtCard, out var renderingError))
if (TryBuildCard(TemplateJson, DataJson, out var builtCard, out var renderingError, _logger))
{
Card = builtCard;
UpdateProperty(nameof(Card));
@@ -87,7 +95,7 @@ public partial class ContentFormViewModel(IFormContent _form, WeakReference<IPag
}
""";
if (TryBuildCard(ErrorCardJson, errorPayload, out var errorCard, out var _))
if (TryBuildCard(ErrorCardJson, errorPayload, out var errorCard, out var _, _logger))
{
Card = errorCard;
UpdateProperty(nameof(Card));
@@ -173,4 +181,7 @@ public partial class ContentFormViewModel(IFormContent _form, WeakReference<IPag
]
}
""";
[LoggerMessage(Level = LogLevel.Error, Message = "Error building adaptive card for form.")]
static partial void Log_ErrorBuildindCard(ILogger logger, Exception ex);
}

View File

@@ -5,11 +5,12 @@
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class ContentMarkdownViewModel(IMarkdownContent _markdown, WeakReference<IPageContext> context) :
ContentViewModel(context)
public partial class ContentMarkdownViewModel(IMarkdownContent _markdown, WeakReference<IPageContext> context, ILogger logger) :
ContentViewModel(context, logger)
{
public ExtensionObject<IMarkdownContent> Model { get; } = new(_markdown);

View File

@@ -7,11 +7,12 @@ using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPageContext> context) :
ContentViewModel(context)
public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPageContext> context, ILogger logger) :
ContentViewModel(context, logger)
{
public ExtensionObject<ITreeContent> Model { get; } = new(_tree);
@@ -55,9 +56,9 @@ public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPag
{
ContentViewModel? viewModel = content switch
{
IFormContent form => new ContentFormViewModel(form, context),
IMarkdownContent markdown => new ContentMarkdownViewModel(markdown, context),
ITreeContent tree => new ContentTreeViewModel(tree, context),
IFormContent form => new ContentFormViewModel(form, context, Logger),
IMarkdownContent markdown => new ContentMarkdownViewModel(markdown, context, Logger),
ITreeContent tree => new ContentTreeViewModel(tree, context, Logger),
_ => null,
};
return viewModel;

View File

@@ -2,9 +2,9 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using ManagedCommon;
using Microsoft.CmdPal.Core.Common.Services;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
using Windows.ApplicationModel;
using Windows.ApplicationModel.AppExtensions;
using Windows.Foundation;
@@ -22,6 +22,7 @@ public partial class ExtensionService : IExtensionService, IDisposable
private static readonly Lock _lock = new();
private readonly SemaphoreSlim _getInstalledExtensionsLock = new(1, 1);
private readonly SemaphoreSlim _getInstalledWidgetsLock = new(1, 1);
private readonly ILogger _logger;
// private readonly ILocalSettingsService _localSettingsService;
private bool _disposedValue;
@@ -32,8 +33,9 @@ public partial class ExtensionService : IExtensionService, IDisposable
private static readonly List<IExtensionWrapper> _installedExtensions = [];
private static readonly List<IExtensionWrapper> _enabledExtensions = [];
public ExtensionService()
public ExtensionService(ILogger logger)
{
_logger = logger;
_catalog.PackageInstalling += Catalog_PackageInstalling;
_catalog.PackageUninstalling += Catalog_PackageUninstalling;
_catalog.PackageUpdating += Catalog_PackageUpdating;
@@ -92,14 +94,14 @@ public partial class ExtensionService : IExtensionService, IDisposable
var extension = isCmdPalExtensionResult.Extension;
if (isExtension && extension is not null)
{
CommandPaletteHost.Instance.DebugLog($"Installed new extension app {extension.DisplayName}");
Log_ExtensionInstalled(extension.DisplayName);
Task.Run(async () =>
{
await _getInstalledExtensionsLock.WaitAsync();
try
{
var wrappers = await CreateWrappersForExtension(extension);
var wrappers = await CreateWrappersForExtension(extension, _logger);
UpdateExtensionsListsFromWrappers(wrappers);
@@ -120,7 +122,7 @@ public partial class ExtensionService : IExtensionService, IDisposable
{
if (extension.PackageFullName == package.Id.FullName)
{
CommandPaletteHost.Instance.DebugLog($"Uninstalled extension app {extension.PackageDisplayName}");
Log_ExtensionUninstalled(extension.PackageDisplayName);
removedExtensions.Add(extension);
}
@@ -199,7 +201,7 @@ public partial class ExtensionService : IExtensionService, IDisposable
var extensions = await GetInstalledAppExtensionsAsync();
foreach (var extension in extensions)
{
var wrappers = await CreateWrappersForExtension(extension);
var wrappers = await CreateWrappersForExtension(extension, _logger);
UpdateExtensionsListsFromWrappers(wrappers);
}
}
@@ -233,7 +235,7 @@ public partial class ExtensionService : IExtensionService, IDisposable
}
}
private static async Task<List<ExtensionWrapper>> CreateWrappersForExtension(AppExtension extension)
private static async Task<List<ExtensionWrapper>> CreateWrappersForExtension(AppExtension extension, ILogger logger)
{
var (cmdPalProvider, classIds) = await GetCmdPalExtensionPropertiesAsync(extension);
@@ -245,14 +247,14 @@ public partial class ExtensionService : IExtensionService, IDisposable
List<ExtensionWrapper> wrappers = [];
foreach (var classId in classIds)
{
var extensionWrapper = CreateExtensionWrapper(extension, cmdPalProvider, classId);
var extensionWrapper = CreateExtensionWrapper(extension, cmdPalProvider, classId, logger);
wrappers.Add(extensionWrapper);
}
return wrappers;
}
private static ExtensionWrapper CreateExtensionWrapper(AppExtension extension, IPropertySet cmdPalProvider, string classId)
private static ExtensionWrapper CreateExtensionWrapper(AppExtension extension, IPropertySet cmdPalProvider, string classId, ILogger logger)
{
var extensionWrapper = new ExtensionWrapper(extension, classId);
@@ -269,7 +271,7 @@ public partial class ExtensionService : IExtensionService, IDisposable
else
{
// log warning that extension declared unsupported extension interface
CommandPaletteHost.Instance.DebugLog($"Extension {extension.DisplayName} declared an unsupported interface: {supportedInterface.Key}");
Log_InvalidExtensionInterface(logger, extension.DisplayName, supportedInterface.Key);
}
}
}
@@ -288,7 +290,8 @@ public partial class ExtensionService : IExtensionService, IDisposable
var installedExtensions = await GetInstalledExtensionsAsync();
foreach (var installedExtension in installedExtensions)
{
Logger.LogDebug($"Signaling dispose to {installedExtension.ExtensionUniqueId}");
Log_SignalingDispose(installedExtension.ExtensionUniqueId);
try
{
if (installedExtension.IsRunning())
@@ -298,7 +301,7 @@ public partial class ExtensionService : IExtensionService, IDisposable
}
catch (Exception ex)
{
Logger.LogError($"Failed to send dispose signal to extension {installedExtension.ExtensionUniqueId}", ex);
Log_ErrorSignalingDispose(installedExtension.ExtensionUniqueId, ex);
}
}
}
@@ -400,6 +403,21 @@ public partial class ExtensionService : IExtensionService, IDisposable
_enabledExtensions.Remove(extension.First());
}
[LoggerMessage(Level = LogLevel.Information, Message = "Installed new extension app {ExtensionName}")]
partial void Log_ExtensionInstalled(string extensionName);
[LoggerMessage(Level = LogLevel.Information, Message = "Uninstalled extension app {ExtensionName}")]
partial void Log_ExtensionUninstalled(string extensionName);
[LoggerMessage(Level = LogLevel.Debug, Message = "Signaling dispose to {ExtensionUniqueId}")]
partial void Log_SignalingDispose(string extensionUniqueId);
[LoggerMessage(Level = LogLevel.Error, Message = "Failed to send dispose signal to extension {ExtensionUniqueId}")]
partial void Log_ErrorSignalingDispose(string extensionUniqueId, Exception exception);
[LoggerMessage(Level = LogLevel.Warning, Message = "Extension {ExtensionName} declared unsupported extension interface: {InterfaceName}")]
static partial void Log_InvalidExtensionInterface(ILogger logger, string extensionName, string interfaceName);
/*
///// <inheritdoc cref="IExtensionService.DisableExtensionIfWindowsFeatureNotAvailable(IExtensionWrapper)"/>
//public async Task<bool> DisableExtensionIfWindowsFeatureNotAvailable(IExtensionWrapper extension)

View File

@@ -6,9 +6,7 @@ using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using CommunityToolkit.Mvvm.ComponentModel;
using ManagedCommon;
using Microsoft.CmdPal.UI.ViewModels.Settings;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.Foundation;
@@ -17,8 +15,6 @@ namespace Microsoft.CmdPal.UI.ViewModels;
public partial class SettingsModel : ObservableObject
{
private const string DeprecatedHotkeyGoesHomeKey = "HotkeyGoesHome";
[JsonIgnore]
public static readonly string FilePath;
@@ -34,6 +30,8 @@ public partial class SettingsModel : ObservableObject
public bool ShowAppDetails { get; set; }
public bool HotkeyGoesHome { get; set; }
public bool BackspaceGoesBack { get; set; }
public bool SingleClickActivates { get; set; }
@@ -58,8 +56,6 @@ public partial class SettingsModel : ObservableObject
public WindowPosition? LastWindowPosition { get; set; }
public TimeSpan AutoGoHomeInterval { get; set; } = Timeout.InfiniteTimeSpan;
// END SETTINGS
///////////////////////////////////////////////////////////////////////////
@@ -102,29 +98,12 @@ public partial class SettingsModel : ObservableObject
{
// Read the JSON content from the file
var jsonContent = File.ReadAllText(FilePath);
var loaded = JsonSerializer.Deserialize<SettingsModel>(jsonContent, JsonSerializationContext.Default.SettingsModel) ?? new();
var migratedAny = false;
try
{
if (JsonNode.Parse(jsonContent) is JsonObject root)
{
migratedAny |= ApplyMigrations(root, loaded);
}
}
catch (Exception ex)
{
Debug.WriteLine($"Migration check failed: {ex}");
}
var loaded = JsonSerializer.Deserialize<SettingsModel>(jsonContent, JsonSerializationContext.Default.SettingsModel);
Debug.WriteLine("Loaded settings file");
Debug.WriteLine(loaded is not null ? "Loaded settings file" : "Failed to parse");
if (migratedAny)
{
SaveSettings(loaded);
}
return loaded;
return loaded ?? new();
}
catch (Exception ex)
{
@@ -134,51 +113,6 @@ public partial class SettingsModel : ObservableObject
return new();
}
private static bool ApplyMigrations(JsonObject root, SettingsModel model)
{
var migrated = false;
// Migration #1: HotkeyGoesHome (bool) -> AutoGoHomeInterval (TimeSpan)
// The old 'HotkeyGoesHome' boolean indicated whether the "go home" action should happen immediately (true) or never (false).
// The new 'AutoGoHomeInterval' uses a TimeSpan: 'TimeSpan.Zero' means immediate, 'Timeout.InfiniteTimeSpan' means never.
migrated |= TryMigrate(
"Migration #1: HotkeyGoesHome (bool) -> AutoGoHomeInterval (TimeSpan)",
root,
model,
nameof(AutoGoHomeInterval),
DeprecatedHotkeyGoesHomeKey,
(settingsModel, goesHome) => settingsModel.AutoGoHomeInterval = goesHome ? TimeSpan.Zero : Timeout.InfiniteTimeSpan,
JsonSerializationContext.Default.Boolean);
return migrated;
}
private static bool TryMigrate<T>(string migrationName, JsonObject root, SettingsModel model, string newKey, string oldKey, Action<SettingsModel, T> apply, JsonTypeInfo<T> jsonTypeInfo)
{
try
{
// If new key already present, skip migration
if (root.ContainsKey(newKey) && root[newKey] is not null)
{
return false;
}
// If old key present, try to deserialize and apply
if (root.TryGetPropertyValue(oldKey, out var oldNode) && oldNode is not null)
{
var value = oldNode.Deserialize<T>(jsonTypeInfo);
apply(model, value!);
return true;
}
}
catch (Exception ex)
{
Logger.LogError($"Error during migration {migrationName}.", ex);
}
return false;
}
public static void SaveSettings(SettingsModel model)
{
if (string.IsNullOrEmpty(FilePath))
@@ -205,9 +139,6 @@ public partial class SettingsModel : ObservableObject
savedSettings[item.Key] = item.Value?.DeepClone();
}
// Remove deprecated keys
savedSettings.Remove(DeprecatedHotkeyGoesHomeKey);
var serialized = savedSettings.ToJsonString(JsonSerializationContext.Default.Options);
File.WriteAllText(FilePath, serialized);

View File

@@ -11,19 +11,6 @@ namespace Microsoft.CmdPal.UI.ViewModels;
public partial class SettingsViewModel : INotifyPropertyChanged
{
private static readonly List<TimeSpan> AutoGoHomeIntervals =
[
Timeout.InfiniteTimeSpan,
TimeSpan.Zero,
TimeSpan.FromSeconds(10),
TimeSpan.FromSeconds(20),
TimeSpan.FromSeconds(30),
TimeSpan.FromSeconds(60),
TimeSpan.FromSeconds(90),
TimeSpan.FromSeconds(120),
TimeSpan.FromSeconds(180),
];
private readonly SettingsModel _settings;
private readonly IServiceProvider _serviceProvider;
@@ -71,6 +58,16 @@ public partial class SettingsViewModel : INotifyPropertyChanged
}
}
public bool HotkeyGoesHome
{
get => _settings.HotkeyGoesHome;
set
{
_settings.HotkeyGoesHome = value;
Save();
}
}
public bool BackspaceGoesBack
{
get => _settings.BackspaceGoesBack;
@@ -141,25 +138,6 @@ public partial class SettingsViewModel : INotifyPropertyChanged
}
}
public int AutoGoBackIntervalIndex
{
get
{
var index = AutoGoHomeIntervals.IndexOf(_settings.AutoGoHomeInterval);
return index >= 0 ? index : 0;
}
set
{
if (value >= 0 && value < AutoGoHomeIntervals.Count)
{
_settings.AutoGoHomeInterval = AutoGoHomeIntervals[value];
}
Save();
}
}
public ObservableCollection<ProviderSettingsViewModel> CommandProviders { get; } = [];
public SettingsExtensionsViewModel Extensions { get; }

View File

@@ -8,14 +8,13 @@ using System.Diagnostics;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using ManagedCommon;
using Microsoft.CmdPal.Core.Common.Helpers;
using Microsoft.CmdPal.Core.Common.Services;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.UI.ViewModels;
@@ -24,8 +23,14 @@ public partial class TopLevelCommandManager : ObservableObject,
IPageContext,
IDisposable
{
private readonly IServiceProvider _serviceProvider;
private readonly TaskScheduler _taskScheduler;
private readonly TaskScheduler _taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
private readonly ILogger _logger;
private readonly AppExtensionHost _commandPaletteHost;
private readonly IExtensionService _extensionService;
private readonly IEnumerable<ICommandProvider> _builtInProviders;
private readonly SettingsModel _settingsModel;
private readonly AliasManager _aliasManager;
private readonly HotkeyManager _hotkeyManager;
private readonly List<CommandProviderWrapper> _builtInCommands = [];
private readonly List<CommandProviderWrapper> _extensionCommandProviders = [];
@@ -34,10 +39,22 @@ public partial class TopLevelCommandManager : ObservableObject,
TaskScheduler IPageContext.Scheduler => _taskScheduler;
public TopLevelCommandManager(IServiceProvider serviceProvider)
public TopLevelCommandManager(
AppExtensionHost commandPaletteHost,
IExtensionService extensionService,
IEnumerable<ICommandProvider> builtInProviders,
SettingsModel settingsModel,
AliasManager aliasManager,
HotkeyManager hotkeyManager,
ILogger logger)
{
_serviceProvider = serviceProvider;
_taskScheduler = _serviceProvider.GetService<TaskScheduler>()!;
_logger = logger;
_commandPaletteHost = commandPaletteHost;
_extensionService = extensionService;
_builtInProviders = builtInProviders;
_settingsModel = settingsModel;
_aliasManager = aliasManager;
_hotkeyManager = hotkeyManager;
WeakReferenceMessenger.Default.Register<ReloadCommandsMessage>(this);
_reloadCommandsGate = new(ReloadAllCommandsAsyncCore);
}
@@ -70,10 +87,9 @@ public partial class TopLevelCommandManager : ObservableObject,
// Load built-In commands first. These are all in-proc, and
// owned by our ServiceProvider.
var builtInCommands = _serviceProvider.GetServices<ICommandProvider>();
foreach (var provider in builtInCommands)
foreach (var provider in _builtInProviders)
{
CommandProviderWrapper wrapper = new(provider, _taskScheduler);
CommandProviderWrapper wrapper = new(provider, _taskScheduler, _aliasManager, _hotkeyManager, _logger);
lock (_commandProvidersLock)
{
_builtInCommands.Add(wrapper);
@@ -91,7 +107,7 @@ public partial class TopLevelCommandManager : ObservableObject,
s.Stop();
Logger.LogDebug($"Loading built-ins took {s.ElapsedMilliseconds}ms");
Log_BuiltInsLoaded(s.ElapsedMilliseconds);
return true;
}
@@ -101,7 +117,7 @@ public partial class TopLevelCommandManager : ObservableObject,
{
WeakReference<IPageContext> weakSelf = new(this);
await commandProvider.LoadTopLevelCommands(_serviceProvider, weakSelf);
await commandProvider.LoadTopLevelCommands(_settingsModel, weakSelf);
var commands = await Task.Factory.StartNew(
() =>
@@ -149,7 +165,7 @@ public partial class TopLevelCommandManager : ObservableObject,
private async Task UpdateCommandsForProvider(CommandProviderWrapper sender, IItemsChangedEventArgs args)
{
WeakReference<IPageContext> weakSelf = new(this);
await sender.LoadTopLevelCommands(_serviceProvider, weakSelf);
await sender.LoadTopLevelCommands(_settingsModel, weakSelf);
List<TopLevelViewModel> newItems = [.. sender.TopLevelItems];
foreach (var i in sender.FallbackItems)
@@ -216,8 +232,7 @@ public partial class TopLevelCommandManager : ObservableObject,
private async Task ReloadAllCommandsAsyncCore(CancellationToken cancellationToken)
{
IsLoading = true;
var extensionService = _serviceProvider.GetService<IExtensionService>()!;
await extensionService.SignalStopExtensionsAsync();
await _extensionService.SignalStopExtensionsAsync();
lock (TopLevelCommands)
{
@@ -238,12 +253,10 @@ public partial class TopLevelCommandManager : ObservableObject,
[RelayCommand]
public async Task<bool> LoadExtensionsAsync()
{
var extensionService = _serviceProvider.GetService<IExtensionService>()!;
_extensionService.OnExtensionAdded -= ExtensionService_OnExtensionAdded;
_extensionService.OnExtensionRemoved -= ExtensionService_OnExtensionRemoved;
extensionService.OnExtensionAdded -= ExtensionService_OnExtensionAdded;
extensionService.OnExtensionRemoved -= ExtensionService_OnExtensionRemoved;
var extensions = (await extensionService.GetInstalledExtensionsAsync()).ToImmutableList();
var extensions = (await _extensionService.GetInstalledExtensionsAsync()).ToImmutableList();
lock (_commandProvidersLock)
{
_extensionCommandProviders.Clear();
@@ -254,8 +267,8 @@ public partial class TopLevelCommandManager : ObservableObject,
await StartExtensionsAndGetCommands(extensions);
}
extensionService.OnExtensionAdded += ExtensionService_OnExtensionAdded;
extensionService.OnExtensionRemoved += ExtensionService_OnExtensionRemoved;
_extensionService.OnExtensionAdded += ExtensionService_OnExtensionAdded;
_extensionService.OnExtensionRemoved += ExtensionService_OnExtensionRemoved;
IsLoading = false;
@@ -310,20 +323,20 @@ public partial class TopLevelCommandManager : ObservableObject,
}
timer.Stop();
Logger.LogDebug($"Loading extensions took {timer.ElapsedMilliseconds} ms");
Log_ExtensionsLoaded(timer.ElapsedMilliseconds);
}
private async Task<CommandProviderWrapper?> StartExtensionWithTimeoutAsync(IExtensionWrapper extension)
{
Logger.LogDebug($"Starting {extension.PackageFullName}");
Log_StartingExtension(extension.PackageFullName);
try
{
await extension.StartExtensionAsync().WaitAsync(TimeSpan.FromSeconds(10));
return new CommandProviderWrapper(extension, _taskScheduler);
return new CommandProviderWrapper(extension, _taskScheduler, _aliasManager, _hotkeyManager, _logger);
}
catch (Exception ex)
{
Logger.LogError($"Failed to start extension {extension.PackageFullName}: {ex}");
Log_FailedToStartExtension(extension.PackageFullName, ex);
return null; // Return null for failed extensions
}
}
@@ -336,11 +349,11 @@ public partial class TopLevelCommandManager : ObservableObject,
}
catch (TimeoutException)
{
Logger.LogError($"Loading commands from {wrapper!.ExtensionHost?.Extension?.PackageFullName} timed out");
Log_LoadingCommandsTimedOut(wrapper!.ExtensionHost?.Extension?.PackageFullName);
}
catch (Exception ex)
{
Logger.LogError($"Failed to load commands for extension {wrapper!.ExtensionHost?.Extension?.PackageFullName}: {ex}");
Log_FailedToLoadCommandsForExtension(wrapper!.ExtensionHost?.Extension?.PackageFullName, ex);
}
return null;
@@ -414,7 +427,7 @@ public partial class TopLevelCommandManager : ObservableObject,
void IPageContext.ShowException(Exception ex, string? extensionHint)
{
var message = DiagnosticsHelper.BuildExceptionMessage(ex, extensionHint ?? "TopLevelCommandManager");
CommandPaletteHost.Instance.Log(message);
_commandPaletteHost.Log(message);
}
internal bool IsProviderActive(string id)
@@ -431,4 +444,22 @@ public partial class TopLevelCommandManager : ObservableObject,
_reloadCommandsGate.Dispose();
GC.SuppressFinalize(this);
}
[LoggerMessage(Level = LogLevel.Debug, Message = "Loading built-ins took {ElapsedMilliseconds}ms")]
partial void Log_BuiltInsLoaded(long elapsedMilliseconds);
[LoggerMessage(Level = LogLevel.Debug, Message = "Loading extensions took {ElapsedMilliseconds}ms")]
partial void Log_ExtensionsLoaded(long elapsedMilliseconds);
[LoggerMessage(Level = LogLevel.Error, Message = "Failed to load commands for extension {ExtensionName}")]
partial void Log_FailedToLoadCommandsForExtension(string? extensionName, Exception exception);
[LoggerMessage(Level = LogLevel.Warning, Message = "Loading commands for extension {ExtensionName} timed out")]
partial void Log_LoadingCommandsTimedOut(string? extensionName);
[LoggerMessage(Level = LogLevel.Error, Message = "Failed to start extension {ExtensionName}")]
partial void Log_FailedToStartExtension(string extensionName, Exception exception);
[LoggerMessage(Level = LogLevel.Debug, Message = "Starting extension {ExtensionName}")]
partial void Log_StartingExtension(string extensionName);
}

View File

@@ -12,7 +12,6 @@ using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Settings;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.DependencyInjection;
using Windows.Foundation;
using WyHash;
@@ -22,7 +21,8 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
{
private readonly SettingsModel _settings;
private readonly ProviderSettings _providerSettings;
private readonly IServiceProvider _serviceProvider;
private readonly HotkeyManager _hotKeyManager;
private readonly AliasManager _aliasManager;
private readonly CommandItemViewModel _commandItemViewModel;
private readonly string _commandProviderId;
@@ -99,7 +99,7 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
get => _hotkey;
set
{
_serviceProvider.GetService<HotkeyManager>()!.UpdateHotkey(Id, value);
_hotKeyManager.UpdateHotkey(Id, value);
UpdateHotkey();
UpdateTags();
Save();
@@ -177,9 +177,11 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
string commandProviderId,
SettingsModel settings,
ProviderSettings providerSettings,
IServiceProvider serviceProvider)
AliasManager aliasManager,
HotkeyManager hotkeyManager)
{
_serviceProvider = serviceProvider;
_hotKeyManager = hotkeyManager;
_aliasManager = aliasManager;
_settings = settings;
_providerSettings = providerSettings;
_commandProviderId = commandProviderId;
@@ -268,16 +270,15 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
? null
: new CommandAlias(Alias.Alias, Alias.CommandId, Alias.IsDirect);
_serviceProvider.GetService<AliasManager>()!.UpdateAlias(Id, commandAlias);
_aliasManager.UpdateAlias(Id, commandAlias);
UpdateTags();
}
private void FetchAliasFromAliasManager()
{
var am = _serviceProvider.GetService<AliasManager>();
if (am is not null)
if (_aliasManager is not null)
{
var commandAlias = am.AliasFromId(Id);
var commandAlias = _aliasManager.AliasFromId(Id);
if (commandAlias is not null)
{
// Decouple from the alias manager alias object

View File

@@ -2,52 +2,21 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.CmdPal.UI.ViewModels;
public sealed class WindowPosition
{
/// <summary>
/// Gets or sets left position in device pixels.
/// </summary>
public int X { get; set; }
/// <summary>
/// Gets or sets top position in device pixels.
/// </summary>
public int Y { get; set; }
/// <summary>
/// Gets or sets width in device pixels.
/// </summary>
public int Width { get; set; }
/// <summary>
/// Gets or sets height in device pixels.
/// </summary>
public int Height { get; set; }
/// <summary>
/// Gets or sets width of the screen in device pixels where the window is located.
/// </summary>
public int ScreenWidth { get; set; }
/// <summary>
/// Gets or sets height of the screen in device pixels where the window is located.
/// </summary>
public int ScreenHeight { get; set; }
/// <summary>
/// Gets or sets DPI (dots per inch) of the display where the window is located.
/// </summary>
public int Dpi { get; set; }
/// <summary>
/// Converts the window position properties to a <see cref="RectInt32"/> structure representing the physical window rectangle.
/// </summary>
public RectInt32 ToPhysicalWindowRectangle()
{
return new RectInt32(X, Y, Width, Height);
}
}

View File

@@ -2,33 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using ManagedCommon;
using Microsoft.CmdPal.Core.Common;
using Microsoft.CmdPal.Core.Common.Helpers;
using Microsoft.CmdPal.Core.Common.Services;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Ext.Apps;
using Microsoft.CmdPal.Ext.Bookmarks;
using Microsoft.CmdPal.Ext.Calc;
using Microsoft.CmdPal.Ext.ClipboardHistory;
using Microsoft.CmdPal.Ext.Indexer;
using Microsoft.CmdPal.Ext.Registry;
using Microsoft.CmdPal.Ext.Shell;
using Microsoft.CmdPal.Ext.System;
using Microsoft.CmdPal.Ext.TimeDate;
using Microsoft.CmdPal.Ext.WebSearch;
using Microsoft.CmdPal.Ext.WindowsServices;
using Microsoft.CmdPal.Ext.WindowsSettings;
using Microsoft.CmdPal.Ext.WindowsTerminal;
using Microsoft.CmdPal.Ext.WindowWalker;
using Microsoft.CmdPal.Ext.WinGet;
using Microsoft.CmdPal.UI.Helpers;
using Microsoft.CmdPal.UI.ViewModels;
using Microsoft.CmdPal.UI.ViewModels.BuiltinCommands;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Xaml;
// To learn more about WinUI, the WinUI project structure,
@@ -40,8 +13,6 @@ namespace Microsoft.CmdPal.UI;
/// </summary>
public partial class App : Application
{
private readonly GlobalErrorHandler _globalErrorHandler = new();
/// <summary>
/// Gets the current <see cref="App"/> instance in use.
/// </summary>
@@ -49,43 +20,16 @@ public partial class App : Application
public Window? AppWindow { get; private set; }
public ETWTrace EtwTrace { get; private set; } = new ETWTrace();
/// <summary>
/// Gets the <see cref="IServiceProvider"/> instance to resolve application services.
/// </summary>
public IServiceProvider Services { get; }
/// <summary>
/// Initializes a new instance of the <see cref="App"/> class.
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
public App(MainWindow mainWindow)
{
#if !CMDPAL_DISABLE_GLOBAL_ERROR_HANDLER
_globalErrorHandler.Register(this);
#endif
Services = ConfigureServices();
AppWindow = mainWindow;
this.InitializeComponent();
// Ensure types used in XAML are preserved for AOT compilation
TypePreservation.PreserveTypes();
NativeEventWaiter.WaitForEventLoop(
"Local\\PowerToysCmdPal-ExitEvent-eb73f6be-3f22-4b36-aee3-62924ba40bfd", () =>
{
EtwTrace?.Dispose();
AppWindow?.Close();
Environment.Exit(0);
});
// Connect the PT logging to the core project's logging.
// This way, log statements from the core project will be captured by the PT logs
var logWrapper = new LogWrapper();
CoreLogger.InitializeLogger(logWrapper);
}
/// <summary>
@@ -94,84 +38,7 @@ public partial class App : Application
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
AppWindow = new MainWindow();
var activatedEventArgs = Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs();
((MainWindow)AppWindow).HandleLaunchNonUI(activatedEventArgs);
}
/// <summary>
/// Configures the services for the application
/// </summary>
private static ServiceProvider ConfigureServices()
{
// TODO: It's in the Labs feed, but we can use Sergio's AOT-friendly source generator for this: https://github.com/CommunityToolkit/Labs-Windows/discussions/463
ServiceCollection services = new();
// Root services
services.AddSingleton(TaskScheduler.FromCurrentSynchronizationContext());
// Built-in Commands. Order matters - this is the order they'll be presented by default.
var allApps = new AllAppsCommandProvider();
var files = new IndexerCommandsProvider();
files.SuppressFallbackWhen(ShellCommandsProvider.SuppressFileFallbackIf);
services.AddSingleton<ICommandProvider>(allApps);
services.AddSingleton<ICommandProvider, ShellCommandsProvider>();
services.AddSingleton<ICommandProvider, CalculatorCommandProvider>();
services.AddSingleton<ICommandProvider>(files);
services.AddSingleton<ICommandProvider, BookmarksCommandProvider>(_ => BookmarksCommandProvider.CreateWithDefaultStore());
services.AddSingleton<ICommandProvider, WindowWalkerCommandsProvider>();
services.AddSingleton<ICommandProvider, WebSearchCommandsProvider>();
services.AddSingleton<ICommandProvider, ClipboardHistoryCommandsProvider>();
// GH #38440: Users might not have WinGet installed! Or they might have
// a ridiculously old version. Or might be running as admin.
// We shouldn't explode in the App ctor if we fail to instantiate an
// instance of PackageManager, which will happen in the static ctor
// for WinGetStatics
try
{
var winget = new WinGetExtensionCommandsProvider();
var callback = allApps.LookupApp;
winget.SetAllLookup(callback);
services.AddSingleton<ICommandProvider>(winget);
}
catch (Exception ex)
{
Logger.LogError("Couldn't load winget");
Logger.LogError(ex.ToString());
}
services.AddSingleton<ICommandProvider, WindowsTerminalCommandsProvider>();
services.AddSingleton<ICommandProvider, WindowsSettingsCommandsProvider>();
services.AddSingleton<ICommandProvider, RegistryCommandsProvider>();
services.AddSingleton<ICommandProvider, WindowsServicesCommandsProvider>();
services.AddSingleton<ICommandProvider, BuiltInsCommandProvider>();
services.AddSingleton<ICommandProvider, TimeDateCommandsProvider>();
services.AddSingleton<ICommandProvider, SystemCommandExtensionProvider>();
// Models
services.AddSingleton<TopLevelCommandManager>();
services.AddSingleton<AliasManager>();
services.AddSingleton<HotkeyManager>();
var sm = SettingsModel.LoadSettings();
services.AddSingleton(sm);
var state = AppStateModel.LoadState();
services.AddSingleton(state);
services.AddSingleton<IExtensionService, ExtensionService>();
services.AddSingleton<TrayIconService>();
services.AddSingleton<IRunHistoryService, RunHistoryService>();
services.AddSingleton<IRootPageService, PowerToysRootPageService>();
services.AddSingleton<IAppHostService, PowerToysAppHostService>();
services.AddSingleton<ITelemetryService, TelemetryForwarder>();
// ViewModels
services.AddSingleton<ShellViewModel>();
services.AddSingleton<IPageViewModelFactoryService, CommandPalettePageViewModelFactory>();
return services.BuildServiceProvider();
((MainWindow)AppWindow!).HandleLaunchNonUI(activatedEventArgs);
}
}

View File

@@ -20,7 +20,7 @@ public sealed partial class CommandBar : UserControl,
IRecipient<TryCommandKeybindingMessage>,
ICurrentPageAware
{
public CommandBarViewModel ViewModel { get; } = new();
public CommandBarViewModel ViewModel { get; set; }
public PageViewModel? CurrentPageViewModel
{
@@ -32,9 +32,10 @@ public sealed partial class CommandBar : UserControl,
public static readonly DependencyProperty CurrentPageViewModelProperty =
DependencyProperty.Register(nameof(CurrentPageViewModel), typeof(PageViewModel), typeof(CommandBar), new PropertyMetadata(null));
public CommandBar()
public CommandBar(CommandBarViewModel commandBarViewModel)
{
this.InitializeComponent();
ViewModel = commandBarViewModel;
// RegisterAll isn't AOT compatible
WeakReferenceMessenger.Default.Register<OpenContextMenuMessage>(this);

View File

@@ -21,6 +21,7 @@ public sealed partial class ContextMenu : UserControl,
IRecipient<UpdateCommandBarMessage>,
IRecipient<TryCommandKeybindingMessage>
{
// Fix for CS8618: Mark ViewModel property as required to ensure it is initialized by the constructor.
public ContextMenuViewModel ViewModel { get; } = new();
public ContextMenu()

View File

@@ -4,18 +4,18 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CmdPal.Core.Common.Services.Telemetry;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class BeginInvoke : EventBase, IEvent
public class BeginInvokeEvent : TelemetryEventBase
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public override PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public BeginInvoke()
public BeginInvokeEvent()
{
EventName = "CmdPal_BeginInvoke";
}

View File

@@ -1,18 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CommandPalette.Extensions;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class CmdPalDismissedOnLostFocus : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -1,18 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CommandPalette.Extensions;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class CmdPalProcessStarted : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -4,18 +4,18 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CmdPal.Core.Common.Services.Telemetry;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class ColdLaunch : EventBase, IEvent
public class ColdLaunchEvent : TelemetryEventBase
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public override PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public ColdLaunch()
public ColdLaunchEvent()
{
EventName = "CmdPal_ColdLaunch";
}

View File

@@ -4,15 +4,19 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CmdPal.Core.Common.Services.Telemetry;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class CmdPalDismissedOnEsc : EventBase, IEvent
public class DismissedOnEscEvent : TelemetryEventBase
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public override PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public DismissedOnEscEvent()
{
EventName = "CmdPal_DismissedOnEsc";
}
}

View File

@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CmdPal.Core.Common.Services.Telemetry;
using Microsoft.PowerToys.Telemetry;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class DismissedOnLostFocusEvent : TelemetryEventBase
{
public override PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public DismissedOnLostFocusEvent()
{
EventName = "CmdPal_DismissedOnLostFocus";
}
}

View File

@@ -4,22 +4,22 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CmdPal.Core.Common.Services.Telemetry;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class CmdPalHotkeySummoned : EventBase, IEvent
public class HotkeySummonedEvent : TelemetryEventBase
{
public bool Global { get; set; }
public CmdPalHotkeySummoned(bool global)
public HotkeySummonedEvent(bool global)
{
Global = global;
EventName = "CmdPal_HotkeySummoned";
}
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public override PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -4,22 +4,23 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CmdPal.Core.Common.Services.Telemetry;
using Microsoft.CommandPalette.Extensions;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class CmdPalInvokeResult : EventBase, IEvent
public class InvokeResultEvent : TelemetryEventBase
{
public string ResultKind { get; set; }
public CmdPalInvokeResult(CommandResultKind resultKind)
public InvokeResultEvent(CommandResultKind resultKind)
{
EventName = "CmdPal_InvokeResult";
ResultKind = resultKind.ToString();
}
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public override PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -4,20 +4,20 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CmdPal.Core.Common.Services.Telemetry;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class OpenPage : EventBase, IEvent
public class OpenPageEvent : TelemetryEventBase
{
public int PageDepth { get; set; }
public string Id { get; set; }
public OpenPage(int pageDepth, string id)
public OpenPageEvent(int pageDepth, string id)
{
PageDepth = pageDepth;
Id = id;
@@ -25,5 +25,5 @@ public class OpenPage : EventBase, IEvent
EventName = "CmdPal_OpenPage";
}
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public override PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CmdPal.Core.Common.Services.Telemetry;
using Microsoft.PowerToys.Telemetry;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class OpenUriEvent : TelemetryEventBase
{
public override PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public string Uri { get; set; }
public bool IsWeb { get; set; }
public bool Success { get; set; }
public OpenUriEvent(string uri, bool isWeb, bool success)
{
EventName = "CmdPal_OpenUri";
Uri = uri;
IsWeb = isWeb;
Success = success;
}
}

View File

@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CmdPal.Core.Common.Services.Telemetry;
using Microsoft.PowerToys.Telemetry;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class ProcessStartedEvent : TelemetryEventBase
{
public override PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public ProcessStartedEvent()
{
EventName = "CmdPal_ProcessStarted";
}
}

View File

@@ -4,18 +4,18 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CmdPal.Core.Common.Services.Telemetry;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class ReactivateInstance : EventBase, IEvent
public class ReactivateInstanceEvent : TelemetryEventBase
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public override PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public ReactivateInstance()
public ReactivateInstanceEvent()
{
EventName = "CmdPal_ReactivateInstance";
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.CmdPal.Core.Common.Services.Telemetry;
using Microsoft.PowerToys.Telemetry;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class RunCommandEvent : TelemetryEventBase
{
public override PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public string Command { get; set; }
public bool AsAdmin { get; set; }
public bool Success { get; set; }
public RunCommandEvent(string command, bool asAdmin, bool success)
{
EventName = "CmdPal_RunCommand";
Command = command;
AsAdmin = asAdmin;
Success = success;
}
}

Some files were not shown because too many files have changed in this diff Show More