mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-08 05:17:03 +01:00
Compare commits
20 Commits
dev/vanzue
...
yuleng/aot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
264839b470 | ||
|
|
371b7f0868 | ||
|
|
b6bcc92eb4 | ||
|
|
2ac464279a | ||
|
|
8ce198a47b | ||
|
|
15ef9189ba | ||
|
|
2c555e2c2b | ||
|
|
83817700e1 | ||
|
|
7e92a9a5e9 | ||
|
|
fe067def65 | ||
|
|
6b9c99c2f6 | ||
|
|
ba6af794ac | ||
|
|
9cb99be4e9 | ||
|
|
ad974bd679 | ||
|
|
49e5bbb5f0 | ||
|
|
7efbd2f013 | ||
|
|
ba230eca07 | ||
|
|
30df5e0df2 | ||
|
|
9a6c64f9c0 | ||
|
|
7dc2a05c45 |
@@ -3,5 +3,5 @@
|
||||
"notificationAliases": ["powertoys@microsoft.com"],
|
||||
"instanceUrl": "https://microsoft.visualstudio.com",
|
||||
"projectName": "OS",
|
||||
"areaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\PowerToys"
|
||||
"areaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\DIVE\\PowerToys"
|
||||
}
|
||||
|
||||
@@ -344,6 +344,11 @@ jobs:
|
||||
flattenFolders: True
|
||||
OverWrite: True
|
||||
|
||||
# Check if all projects (located in src sub-folder) import common props
|
||||
- pwsh: |-
|
||||
& '.pipelines/verifyCommonProps.ps1' -sourceDir '$(build.sourcesdirectory)\src'
|
||||
displayName: Audit shared common props for CSharp projects in src sub-folder
|
||||
|
||||
# Check if deps.json files don't reference different dll versions.
|
||||
- pwsh: |-
|
||||
& '.pipelines/verifyDepsJsonLibraryVersions.ps1' -targetDir '$(build.sourcesdirectory)\$(BuildPlatform)\$(BuildConfiguration)'
|
||||
|
||||
54
.pipelines/verifyCommonProps.ps1
Normal file
54
.pipelines/verifyCommonProps.ps1
Normal file
@@ -0,0 +1,54 @@
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(Mandatory = $True, Position = 1)]
|
||||
[string]$sourceDir
|
||||
)
|
||||
|
||||
# scan all csharp project in the source directory
|
||||
function Get-CSharpProjects {
|
||||
param (
|
||||
[string]$path
|
||||
)
|
||||
|
||||
# Get all .csproj files under the specified path
|
||||
return Get-ChildItem -Path $path -Recurse -Filter *.csproj | Select-Object -ExpandProperty FullName
|
||||
}
|
||||
|
||||
# Check if the project file imports 'Common.Dotnet.CsWinRT.props'
|
||||
function Test-ImportSharedCsWinRTProps {
|
||||
param (
|
||||
[string]$filePath
|
||||
)
|
||||
|
||||
# Load the XML content of the .csproj file
|
||||
[xml]$csprojContent = Get-Content -Path $filePath
|
||||
|
||||
|
||||
# Check if the Import element with Project attribute containing 'Common.Dotnet.CsWinRT.props' exists
|
||||
return $csprojContent.Project.Import | Where-Object { $null -ne $_.Project -and $_.Project.EndsWith('Common.Dotnet.CsWinRT.props') }
|
||||
}
|
||||
|
||||
# Call the function with the provided source directory
|
||||
$csprojFilesArray = Get-CSharpProjects -path $sourceDir
|
||||
|
||||
$hasInvalidCsProj = $false
|
||||
|
||||
# Enumerate the array of file paths and call Validate-ImportSharedCsWinRTProps for each file
|
||||
foreach ($csprojFile in $csprojFilesArray) {
|
||||
# Skip if the file ends with 'TemplateCmdPalExtension.csproj'
|
||||
if ($csprojFile -like '*TemplateCmdPalExtension.csproj') {
|
||||
continue
|
||||
}
|
||||
|
||||
$importExists = Test-ImportSharedCsWinRTProps -filePath $csprojFile
|
||||
if (!$importExists) {
|
||||
Write-Output "$csprojFile need to import 'Common.Dotnet.CsWinRT.props'."
|
||||
$hasInvalidCsProj = $true
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasInvalidCsProj) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
exit 0
|
||||
140
PowerToys.sln
140
PowerToys.sln
@@ -626,18 +626,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Built-in Extensions", "Buil
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Apps", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Apps\Microsoft.CmdPal.Ext.Apps.csproj", "{6CE438DF-C245-4997-A360-0A0939E4BA34}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Bookmarks", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Bookmark\Microsoft.CmdPal.Ext.Bookmarks.csproj", "{E09AA983-C755-474F-83D6-A5CDF528C070}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Calc", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Calc\Microsoft.CmdPal.Ext.Calc.csproj", "{6D56B64D-FF1F-488F-AFED-9B9854A5D399}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Registry", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Registry\Microsoft.CmdPal.Ext.Registry.csproj", "{92EC89E4-9972-453A-8A1A-3A9E230C146A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsServices", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WindowsServices\Microsoft.CmdPal.Ext.WindowsServices.csproj", "{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsSettings", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WindowsSettings\Microsoft.CmdPal.Ext.WindowsSettings.csproj", "{D1160404-D3D1-497A-883A-4059C07C2273}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowsTerminal", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WindowsTerminal\Microsoft.CmdPal.Ext.WindowsTerminal.csproj", "{40F6D69D-E321-400F-A767-5628C7AE453D}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extension SDK", "Extension SDK", "{F3D09629-59A2-4924-A4B9-D6BFAA2C1B49}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.CommandPalette.Extensions", "src\modules\cmdpal\extensionsdk\Microsoft.CommandPalette.Extensions\Microsoft.CommandPalette.Extensions.vcxproj", "{305DD37E-C85D-4B08-AAFE-7381FA890463}"
|
||||
@@ -660,8 +648,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.UI", "src\
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.UI.ViewModels", "src\modules\cmdpal\Microsoft.CmdPal.UI.ViewModels\Microsoft.CmdPal.UI.ViewModels.csproj", "{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.ClipboardHistory", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.ClipboardHistory\Microsoft.CmdPal.Ext.ClipboardHistory.csproj", "{79775343-7A3D-445D-9104-3DD5B2893DF9}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdPalModuleInterface", "src\modules\cmdpal\CmdPalModuleInterface\CmdPalModuleInterface.vcxproj", "{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspacesCsharpLibrary", "src\modules\Workspaces\WorkspacesCsharpLibrary\WorkspacesCsharpLibrary.csproj", "{89D0E199-B17A-418C-B2F8-7375B6708357}"
|
||||
@@ -672,12 +658,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Indexe
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.Shell", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.Shell\Microsoft.CmdPal.Ext.Shell.csproj", "{C0CE3B5E-16D3-495D-B335-CA791B660162}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CmdPal.Ext.WindowWalker", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WindowWalker\Microsoft.CmdPal.Ext.WindowWalker.csproj", "{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WebSearch", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WebSearch\Microsoft.CmdPal.Ext.WebSearch.csproj", "{605E914B-7232-4789-AF46-BF5D3DDFC14E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.WinGet", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.WinGet\Microsoft.CmdPal.Ext.WinGet.csproj", "{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.UnitTests", "src\modules\AdvancedPaste\AdvancedPaste.UnitTests\AdvancedPaste.UnitTests.csproj", "{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.FuzzTests", "src\modules\AdvancedPaste\AdvancedPaste.FuzzTests\AdvancedPaste.FuzzTests.csproj", "{7F5B9557-5878-4438-A721-3E28296BA193}"
|
||||
@@ -690,8 +670,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZoomItModuleInterface", "sr
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZoomItSettingsInterop", "src\modules\ZoomIt\ZoomItSettingsInterop\ZoomItSettingsInterop.vcxproj", "{CA7D8106-30B9-4AEC-9D05-B69B31B8C461}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.TimeDate", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.TimeDate\Microsoft.CmdPal.Ext.TimeDate.csproj", "{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UITestAutomation", "src\common\UITestAutomation\UITestAutomation.csproj", "{A558C25D-2007-498E-8B6F-43405AFAE9E2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeyboardManagerEditorUI", "src\modules\keyboardmanager\KeyboardManagerEditorUI\KeyboardManagerEditorUI.csproj", "{08F9155D-B6DC-46E5-9C83-AF60B655898B}"
|
||||
@@ -704,8 +682,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hosts.UITests", "src\module
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegistryPreview.FuzzTests", "src\modules\registrypreview\RegistryPreview.FuzzTests\RegistryPreview.FuzzTests.csproj", "{5702B3CC-8575-48D5-83D8-15BB42269CD3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.System", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj", "{64B88F02-CD88-4ED8-9624-989A800230F9}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdPalKeyboardService", "src\modules\cmdpal\CmdPalKeyboardService\CmdPalKeyboardService.vcxproj", "{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRename.FuzzingTest", "src\modules\powerrename\PowerRename.FuzzingTest\PowerRename.FuzzingTest.vcxproj", "{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}"
|
||||
@@ -2270,54 +2246,6 @@ Global
|
||||
{6CE438DF-C245-4997-A360-0A0939E4BA34}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{6CE438DF-C245-4997-A360-0A0939E4BA34}.Release|x64.ActiveCfg = Release|x64
|
||||
{6CE438DF-C245-4997-A360-0A0939E4BA34}.Release|x64.Build.0 = Release|x64
|
||||
{E09AA983-C755-474F-83D6-A5CDF528C070}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{E09AA983-C755-474F-83D6-A5CDF528C070}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{E09AA983-C755-474F-83D6-A5CDF528C070}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E09AA983-C755-474F-83D6-A5CDF528C070}.Debug|x64.Build.0 = Debug|x64
|
||||
{E09AA983-C755-474F-83D6-A5CDF528C070}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{E09AA983-C755-474F-83D6-A5CDF528C070}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{E09AA983-C755-474F-83D6-A5CDF528C070}.Release|x64.ActiveCfg = Release|x64
|
||||
{E09AA983-C755-474F-83D6-A5CDF528C070}.Release|x64.Build.0 = Release|x64
|
||||
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Debug|x64.Build.0 = Debug|x64
|
||||
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Release|x64.ActiveCfg = Release|x64
|
||||
{6D56B64D-FF1F-488F-AFED-9B9854A5D399}.Release|x64.Build.0 = Release|x64
|
||||
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Debug|x64.Build.0 = Debug|x64
|
||||
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Release|x64.ActiveCfg = Release|x64
|
||||
{92EC89E4-9972-453A-8A1A-3A9E230C146A}.Release|x64.Build.0 = Release|x64
|
||||
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Debug|x64.Build.0 = Debug|x64
|
||||
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Release|x64.ActiveCfg = Release|x64
|
||||
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95}.Release|x64.Build.0 = Release|x64
|
||||
{D1160404-D3D1-497A-883A-4059C07C2273}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{D1160404-D3D1-497A-883A-4059C07C2273}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{D1160404-D3D1-497A-883A-4059C07C2273}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D1160404-D3D1-497A-883A-4059C07C2273}.Debug|x64.Build.0 = Debug|x64
|
||||
{D1160404-D3D1-497A-883A-4059C07C2273}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{D1160404-D3D1-497A-883A-4059C07C2273}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{D1160404-D3D1-497A-883A-4059C07C2273}.Release|x64.ActiveCfg = Release|x64
|
||||
{D1160404-D3D1-497A-883A-4059C07C2273}.Release|x64.Build.0 = Release|x64
|
||||
{40F6D69D-E321-400F-A767-5628C7AE453D}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{40F6D69D-E321-400F-A767-5628C7AE453D}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{40F6D69D-E321-400F-A767-5628C7AE453D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{40F6D69D-E321-400F-A767-5628C7AE453D}.Debug|x64.Build.0 = Debug|x64
|
||||
{40F6D69D-E321-400F-A767-5628C7AE453D}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{40F6D69D-E321-400F-A767-5628C7AE453D}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{40F6D69D-E321-400F-A767-5628C7AE453D}.Release|x64.ActiveCfg = Release|x64
|
||||
{40F6D69D-E321-400F-A767-5628C7AE453D}.Release|x64.Build.0 = Release|x64
|
||||
{305DD37E-C85D-4B08-AAFE-7381FA890463}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{305DD37E-C85D-4B08-AAFE-7381FA890463}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{305DD37E-C85D-4B08-AAFE-7381FA890463}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2394,14 +2322,6 @@ Global
|
||||
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}.Release|x64.ActiveCfg = Release|x64
|
||||
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2}.Release|x64.Build.0 = Release|x64
|
||||
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Debug|x64.Build.0 = Debug|x64
|
||||
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Release|x64.ActiveCfg = Release|x64
|
||||
{79775343-7A3D-445D-9104-3DD5B2893DF9}.Release|x64.Build.0 = Release|x64
|
||||
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2446,34 +2366,6 @@ Global
|
||||
{C0CE3B5E-16D3-495D-B335-CA791B660162}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{C0CE3B5E-16D3-495D-B335-CA791B660162}.Release|x64.ActiveCfg = Release|x64
|
||||
{C0CE3B5E-16D3-495D-B335-CA791B660162}.Release|x64.Build.0 = Release|x64
|
||||
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Debug|x64.Build.0 = Debug|x64
|
||||
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Release|x64.ActiveCfg = Release|x64
|
||||
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C}.Release|x64.Build.0 = Release|x64
|
||||
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Debug|x64.Build.0 = Debug|x64
|
||||
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Release|x64.ActiveCfg = Release|x64
|
||||
{605E914B-7232-4789-AF46-BF5D3DDFC14E}.Release|x64.Build.0 = Release|x64
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Debug|x64.Build.0 = Debug|x64
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|ARM64.Deploy.0 = Release|ARM64
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|x64.ActiveCfg = Release|x64
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|x64.Build.0 = Release|x64
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9}.Release|x64.Deploy.0 = Release|x64
|
||||
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2514,18 +2406,6 @@ Global
|
||||
{CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA7D8106-30B9-4AEC-9D05-B69B31B8C461}.Release|x64.Build.0 = Release|x64
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Debug|x64.Build.0 = Debug|x64
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Release|ARM64.Deploy.0 = Release|ARM64
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Release|x64.ActiveCfg = Release|x64
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Release|x64.Build.0 = Release|x64
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449}.Release|x64.Deploy.0 = Release|x64
|
||||
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{A558C25D-2007-498E-8B6F-43405AFAE9E2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2574,14 +2454,6 @@ Global
|
||||
{5702B3CC-8575-48D5-83D8-15BB42269CD3}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{5702B3CC-8575-48D5-83D8-15BB42269CD3}.Release|x64.ActiveCfg = Release|x64
|
||||
{5702B3CC-8575-48D5-83D8-15BB42269CD3}.Release|x64.Build.0 = Release|x64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Debug|x64.Build.0 = Debug|x64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x64.ActiveCfg = Release|x64
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9}.Release|x64.Build.0 = Release|x64
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2826,12 +2698,6 @@ Global
|
||||
{3846508C-77EB-4034-A702-F8BB263C4F79} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2} = {3846508C-77EB-4034-A702-F8BB263C4F79}
|
||||
{6CE438DF-C245-4997-A360-0A0939E4BA34} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{E09AA983-C755-474F-83D6-A5CDF528C070} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{6D56B64D-FF1F-488F-AFED-9B9854A5D399} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{92EC89E4-9972-453A-8A1A-3A9E230C146A} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{51939B4F-1F62-4BFF-A6A2-C08646E5BE95} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{D1160404-D3D1-497A-883A-4059C07C2273} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{40F6D69D-E321-400F-A767-5628C7AE453D} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{F3D09629-59A2-4924-A4B9-D6BFAA2C1B49} = {3846508C-77EB-4034-A702-F8BB263C4F79}
|
||||
{305DD37E-C85D-4B08-AAFE-7381FA890463} = {F3D09629-59A2-4924-A4B9-D6BFAA2C1B49}
|
||||
{CA4D810F-C8F4-4B61-9DA9-71807E0B9F24} = {F3D09629-59A2-4924-A4B9-D6BFAA2C1B49}
|
||||
@@ -2843,29 +2709,23 @@ Global
|
||||
{7520A2FE-00A2-49B8-83ED-DB216E874C04} = {3846508C-77EB-4034-A702-F8BB263C4F79}
|
||||
{8FBDABA4-40EE-4C0E-9BC8-2F6444A6EF90} = {7520A2FE-00A2-49B8-83ED-DB216E874C04}
|
||||
{C66020D1-CB10-4CF7-8715-84C97FD5E5E2} = {7520A2FE-00A2-49B8-83ED-DB216E874C04}
|
||||
{79775343-7A3D-445D-9104-3DD5B2893DF9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{0ADEB797-C8C7-4FFA-ACD5-2AF6CAD7ECD8} = {3846508C-77EB-4034-A702-F8BB263C4F79}
|
||||
{89D0E199-B17A-418C-B2F8-7375B6708357} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
|
||||
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E} = {CA716AE6-FE5C-40AC-BB8F-2C87912687AC}
|
||||
{453CBB73-A3CB-4D0B-8D24-6940B86FE21D} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{C0CE3B5E-16D3-495D-B335-CA791B660162} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{3A9A7297-92C4-4F16-B6F9-8D4AB652C86C} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{605E914B-7232-4789-AF46-BF5D3DDFC14E} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{E81A7D20-9862-ABDB-0AAE-9BC5B517A9F9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE} = {9873BA05-4C41-4819-9283-CF45D795431B}
|
||||
{7F5B9557-5878-4438-A721-3E28296BA193} = {9873BA05-4C41-4819-9283-CF45D795431B}
|
||||
{DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{0A84F764-3A88-44CD-AA96-41BDBD48627B} = {DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C}
|
||||
{E4585179-2AC1-4D5F-A3FF-CFC5392F694C} = {DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C}
|
||||
{CA7D8106-30B9-4AEC-9D05-B69B31B8C461} = {DD6E12FE-5509-4ABC-ACC2-3D6DC98A238C}
|
||||
{DCC6BD67-17BB-47AA-B507-FB0FE43A7449} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{A558C25D-2007-498E-8B6F-43405AFAE9E2} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{08F9155D-B6DC-46E5-9C83-AF60B655898B} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||
{4382A954-179A-4078-92AF-715187DFFF50} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||
{EBED240C-8702-452D-B764-6DB9DA9179AF} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
|
||||
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
|
||||
{5702B3CC-8575-48D5-83D8-15BB42269CD3} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2} = {3846508C-77EB-4034-A702-F8BB263C4F79}
|
||||
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
EndGlobalSection
|
||||
|
||||
10
src/Common.Dotnet.FuzzTest.props
Normal file
10
src/Common.Dotnet.FuzzTest.props
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Some items may be set in Directory.Build.props in root -->
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<!-- OneFuzz does not currently support testing with .NET 9.
|
||||
As a temporary workaround, create a .NET 8 project and use file links
|
||||
to include the code that needs testing. -->
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,6 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.Dotnet.FuzzTest.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.Dotnet.FuzzTest.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Project DefaultTargets="Build"
|
||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<Import Project="..\Microsoft.CmdPal.UI\CmdPal.pre.props" Condition="Exists('..\Microsoft.CmdPal.UI\CmdPal.pre.prop')" />
|
||||
<Import Project="..\Microsoft.CmdPal.UI\CmdPal.pre.props" Condition="Exists('..\Microsoft.CmdPal.UI\CmdPal.pre.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
@@ -53,7 +53,6 @@
|
||||
<PreprocessorDefinitions>
|
||||
EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;
|
||||
%(PreprocessorDefinitions);
|
||||
$(CommandPaletteBranding)
|
||||
</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="'$(CommandPaletteBranding)'=='' or '$(CommandPaletteBranding)'=='Dev'">
|
||||
IS_DEV_BRANDING;%(PreprocessorDefinitions)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
@@ -10,10 +11,11 @@
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/utils/package.h>
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/interop/shared_constants.h>
|
||||
#include <Psapi.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <thread>
|
||||
|
||||
HINSTANCE g_hInst_cmdPal = 0;
|
||||
|
||||
@@ -37,8 +39,6 @@ BOOL APIENTRY DllMain(HMODULE hInstance,
|
||||
class CmdPal : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
bool m_enabled = false;
|
||||
|
||||
std::wstring app_name;
|
||||
|
||||
//contains the non localized key of the powertoy
|
||||
@@ -46,7 +46,10 @@ private:
|
||||
|
||||
HANDLE m_hTerminateEvent;
|
||||
|
||||
void LaunchApp(const std::wstring& appPath, const std::wstring& commandLineArgs, bool elevated)
|
||||
// Track if this is the first call to enable
|
||||
bool firstEnableCall = true;
|
||||
|
||||
static bool LaunchApp(const std::wstring& appPath, const std::wstring& commandLineArgs, bool elevated, bool silentFail)
|
||||
{
|
||||
std::wstring dir = std::filesystem::path(appPath).parent_path();
|
||||
|
||||
@@ -54,6 +57,10 @@ private:
|
||||
sei.cbSize = sizeof(SHELLEXECUTEINFO);
|
||||
sei.hwnd = nullptr;
|
||||
sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE;
|
||||
if (silentFail)
|
||||
{
|
||||
sei.fMask = sei.fMask | SEE_MASK_FLAG_NO_UI;
|
||||
}
|
||||
sei.lpVerb = elevated ? L"runas" : L"open";
|
||||
sei.lpFile = appPath.c_str();
|
||||
sei.lpParameters = commandLineArgs.c_str();
|
||||
@@ -64,7 +71,11 @@ private:
|
||||
{
|
||||
std::wstring error = get_last_error_or_default(GetLastError());
|
||||
Logger::error(L"Failed to launch process. {}", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_launched.store(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<DWORD> GetProcessesIdByName(const std::wstring& processName)
|
||||
@@ -122,6 +133,9 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
static std::atomic<bool> m_enabled;
|
||||
static std::atomic<bool> m_launched;
|
||||
|
||||
CmdPal()
|
||||
{
|
||||
app_name = L"CmdPal";
|
||||
@@ -133,10 +147,7 @@ public:
|
||||
|
||||
~CmdPal()
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
}
|
||||
m_enabled = false;
|
||||
CmdPal::m_enabled.store(false);
|
||||
}
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
@@ -203,15 +214,18 @@ public:
|
||||
{
|
||||
Logger::trace("CmdPal::enable()");
|
||||
|
||||
m_enabled = true;
|
||||
CmdPal::m_enabled.store(true);
|
||||
|
||||
try
|
||||
{
|
||||
std::wstring packageName = L"Microsoft.CommandPalette";
|
||||
std::wstring packageName = L"Microsoft.CommandPalette";
|
||||
std::wstring launchPath = L"shell:AppsFolder\\Microsoft.CommandPalette_8wekyb3d8bbwe!App";
|
||||
#ifdef IS_DEV_BRANDING
|
||||
packageName = L"Microsoft.CommandPalette.Dev";
|
||||
packageName = L"Microsoft.CommandPalette.Dev";
|
||||
launchPath = L"shell:AppsFolder\\Microsoft.CommandPalette.Dev_8wekyb3d8bbwe!App";
|
||||
#endif
|
||||
if (!package::GetRegisteredPackage(packageName, false).has_value())
|
||||
|
||||
if (!package::GetRegisteredPackage(packageName, false).has_value())
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger::info(L"CmdPal not installed. Installing...");
|
||||
|
||||
@@ -238,28 +252,34 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::string errorMessage{ "Exception thrown while trying to install CmdPal package: " };
|
||||
errorMessage += e.what();
|
||||
Logger::error(errorMessage);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
|
||||
if (!package::GetRegisteredPackage(packageName, false).has_value())
|
||||
{
|
||||
std::string errorMessage{ "Exception thrown while trying to install CmdPal package: " };
|
||||
errorMessage += e.what();
|
||||
Logger::error(errorMessage);
|
||||
Logger::error("Cmdpal is not registered, quit..");
|
||||
return;
|
||||
}
|
||||
try
|
||||
|
||||
if (!firstEnableCall)
|
||||
{
|
||||
#ifdef IS_DEV_BRANDING
|
||||
LaunchApp(std::wstring{ L"shell:AppsFolder\\" } + L"Microsoft.CommandPalette.Dev_8wekyb3d8bbwe!App", L"RunFromPT", false);
|
||||
#else
|
||||
LaunchApp(std::wstring{ L"shell:AppsFolder\\" } + L"Microsoft.CommandPalette_8wekyb3d8bbwe!App", L"RunFromPT", false);
|
||||
#endif
|
||||
Logger::trace("Not first attempt, try to launch");
|
||||
LaunchApp(launchPath, L"RunFromPT", false /*no elevated*/, false /*error pop up*/);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
else
|
||||
{
|
||||
std::string errorMessage{ "Exception thrown while trying to launch CmdPal: " };
|
||||
errorMessage += e.what();
|
||||
Logger::error(errorMessage);
|
||||
throw;
|
||||
// If first time enable, do retry launch.
|
||||
Logger::trace("First attempt, try to launch");
|
||||
std::thread launchThread(&CmdPal::RetryLaunch, launchPath);
|
||||
launchThread.detach();
|
||||
}
|
||||
|
||||
firstEnableCall = false;
|
||||
}
|
||||
|
||||
virtual void disable()
|
||||
@@ -267,7 +287,44 @@ public:
|
||||
Logger::trace("CmdPal::disable()");
|
||||
TerminateCmdPal();
|
||||
|
||||
m_enabled = false;
|
||||
CmdPal::m_enabled.store(false);
|
||||
}
|
||||
|
||||
static void RetryLaunch(std::wstring path)
|
||||
{
|
||||
const int base_delay_milliseconds = 1000;
|
||||
int max_retry = 9; // 2**9 - 1 seconds. Control total wait time within 10 min.
|
||||
int retry = 0;
|
||||
do
|
||||
{
|
||||
auto launch_result = LaunchApp(path, L"RunFromPT", false, retry < max_retry);
|
||||
if (launch_result)
|
||||
{
|
||||
Logger::info(L"CmdPal launched successfully after {} retries.", retry);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Retry {} launch CmdPal launch failed.", retry);
|
||||
}
|
||||
|
||||
// When we got max retry, we don't need to wait for the next retry.
|
||||
if (retry < max_retry)
|
||||
{
|
||||
int delay = base_delay_milliseconds * (1 << (retry));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
|
||||
}
|
||||
++retry;
|
||||
} while (retry <= max_retry && m_enabled.load() && !m_launched.load());
|
||||
|
||||
if (!m_enabled.load() || m_launched.load())
|
||||
{
|
||||
Logger::error(L"Retry cancelled. CmdPal is disabled or already launched.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"CmdPal launch failed after {} attempts.", retry);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool on_hotkey(size_t) override
|
||||
@@ -282,11 +339,14 @@ public:
|
||||
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
return CmdPal::m_enabled.load();
|
||||
}
|
||||
};
|
||||
|
||||
std::atomic<bool> CmdPal::m_enabled{ false };
|
||||
std::atomic<bool> CmdPal::m_launched{ false };
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new CmdPal();
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,12 @@ namespace TemplateCmdPalExtension;
|
||||
public class Program
|
||||
{
|
||||
[MTAThread]
|
||||
public static async Task Main(string[] args)
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
if (args.Length > 0 && args[0] == "-RegisterProcessAsComServer")
|
||||
{
|
||||
await using global::Shmuelie.WinRTServer.ComServer server = new();
|
||||
global::Shmuelie.WinRTServer.ComServer server = new();
|
||||
|
||||
ManualResetEvent extensionDisposedEvent = new(false);
|
||||
|
||||
// We are instantiating an extension instance once above, and returning it every time the callback in RegisterExtension below is called.
|
||||
@@ -31,6 +32,8 @@ public class Program
|
||||
// This will make the main thread wait until the event is signalled by the extension class.
|
||||
// Since we have single instance of the extension object, we exit as soon as it is disposed.
|
||||
extensionDisposedEvent.WaitOne();
|
||||
server.Stop();
|
||||
server.UnsafeDispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,14 +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.
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Contracts;
|
||||
|
||||
public interface IFileService
|
||||
{
|
||||
T Read<T>(string folderPath, string fileName);
|
||||
|
||||
void Save<T>(string folderPath, string fileName, T content);
|
||||
|
||||
void Delete(string folderPath, string fileName);
|
||||
}
|
||||
@@ -1,16 +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.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Contracts;
|
||||
|
||||
public interface ILocalSettingsService
|
||||
{
|
||||
Task<bool> HasSettingAsync(string key);
|
||||
|
||||
Task<T?> ReadSettingAsync<T>(string key);
|
||||
|
||||
Task SaveSettingAsync<T>(string key, T value);
|
||||
}
|
||||
@@ -1,40 +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 Microsoft.CmdPal.Common.Services;
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension class implementing extension methods for <see cref="Application"/>.
|
||||
/// </summary>
|
||||
public static class ApplicationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get registered services at the application level from anywhere in the
|
||||
/// application.
|
||||
///
|
||||
/// Note:
|
||||
/// https://learn.microsoft.com/uwp/api/windows.ui.xaml.application.current?view=winrt-22621#windows-ui-xaml-application-current
|
||||
/// "Application is a singleton that implements the static Current property
|
||||
/// to provide shared access to the Application instance for the current
|
||||
/// application. The singleton pattern ensures that state managed by
|
||||
/// Application, including shared resources and properties, is available
|
||||
/// from a single, shared location."
|
||||
///
|
||||
/// Example of usage:
|
||||
/// <code>
|
||||
/// Application.Current.GetService<T>()
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Service type.</typeparam>
|
||||
/// <param name="application">Current application.</param>
|
||||
/// <returns>Service reference.</returns>
|
||||
public static T GetService<T>(this Application application)
|
||||
where T : class
|
||||
{
|
||||
return (application as IApp)!.GetService<T>();
|
||||
}
|
||||
}
|
||||
@@ -1,40 +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;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Extensions;
|
||||
|
||||
public static class IHostExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="ActivatorUtilities.CreateInstance(IServiceProvider, Type, object[])"/>
|
||||
/// </summary>
|
||||
public static T CreateInstance<T>(this IHost host, params object[] parameters)
|
||||
{
|
||||
return ActivatorUtilities.CreateInstance<T>(host.Services, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the service object for the specified type, or throws an exception
|
||||
/// if type was not registered.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Service type</typeparam>
|
||||
/// <param name="host">Host object</param>
|
||||
/// <returns>Service object</returns>
|
||||
/// <exception cref="ArgumentException">Throw an exception if the specified
|
||||
/// type is not registered</exception>
|
||||
public static T GetService<T>(this IHost host)
|
||||
where T : class
|
||||
{
|
||||
if (host.Services.GetService(typeof(T)) is not T service)
|
||||
{
|
||||
throw new ArgumentException($"{typeof(T)} needs to be registered in ConfigureServices.");
|
||||
}
|
||||
|
||||
return service;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +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.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Helpers;
|
||||
|
||||
public static class Json
|
||||
{
|
||||
public static async Task<T> ToObjectAsync<T>(string value)
|
||||
{
|
||||
if (typeof(T) == typeof(bool))
|
||||
{
|
||||
return (T)(object)bool.Parse(value);
|
||||
}
|
||||
|
||||
await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(value));
|
||||
return (await JsonSerializer.DeserializeAsync<T>(stream))!;
|
||||
}
|
||||
|
||||
public static async Task<string> StringifyAsync<T>(T value)
|
||||
{
|
||||
if (typeof(T) == typeof(bool))
|
||||
{
|
||||
return value!.ToString()!.ToLowerInvariant();
|
||||
}
|
||||
|
||||
await using var stream = new MemoryStream();
|
||||
await JsonSerializer.SerializeAsync(stream, value);
|
||||
return Encoding.UTF8.GetString(stream.ToArray());
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Dispatching;
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Helpers;
|
||||
|
||||
public static class NativeEventWaiter
|
||||
public static partial class NativeEventWaiter
|
||||
{
|
||||
public static void WaitForEventLoop(string eventName, Action callback)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ using Windows.Win32.Foundation;
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Helpers;
|
||||
|
||||
public static class RuntimeHelper
|
||||
public static partial class RuntimeHelper
|
||||
{
|
||||
public static bool IsMSIX
|
||||
{
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Messages;
|
||||
|
||||
public record HideWindowMessage()
|
||||
public partial record HideWindowMessage()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.CmdPal.Common</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@@ -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.
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Models;
|
||||
|
||||
public class LocalSettingsOptions
|
||||
{
|
||||
public string? ApplicationDataFolder
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string? LocalSettingsFile
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,7 @@
|
||||
EnableWindow
|
||||
CoCreateInstance
|
||||
FileOpenDialog
|
||||
FileSaveDialog
|
||||
IFileOpenDialog
|
||||
IFileSaveDialog
|
||||
SHCreateItemFromParsingName
|
||||
GetCurrentPackageFullName
|
||||
SetWindowLong
|
||||
GetWindowLong
|
||||
WINDOW_EX_STYLE
|
||||
SHLoadIndirectString
|
||||
StrFormatByteSizeEx
|
||||
SFBS_FLAGS
|
||||
MAX_PATH
|
||||
GetDpiForWindow
|
||||
|
||||
@@ -1,48 +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.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.CmdPal.Common.Contracts;
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Services;
|
||||
|
||||
public class FileService : IFileService
|
||||
{
|
||||
private static readonly Encoding _encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
|
||||
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
public T Read<T>(string folderPath, string fileName)
|
||||
{
|
||||
var path = Path.Combine(folderPath, fileName);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
using var fileStream = File.OpenText(path);
|
||||
return JsonSerializer.Deserialize<T>(fileStream.BaseStream);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
#pragma warning restore CS8603 // Possible null reference return.
|
||||
|
||||
public void Save<T>(string folderPath, string fileName, T content)
|
||||
{
|
||||
if (!Directory.Exists(folderPath))
|
||||
{
|
||||
Directory.CreateDirectory(folderPath);
|
||||
}
|
||||
|
||||
var fileContent = JsonSerializer.Serialize(content);
|
||||
File.WriteAllText(Path.Combine(folderPath, fileName), fileContent, _encoding);
|
||||
}
|
||||
|
||||
public void Delete(string folderPath, string fileName)
|
||||
{
|
||||
if (fileName != null && File.Exists(Path.Combine(folderPath, fileName)))
|
||||
{
|
||||
File.Delete(Path.Combine(folderPath, fileName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for the current application singleton object exposing the API
|
||||
/// that can be accessed from anywhere in the application.
|
||||
/// </summary>
|
||||
public interface IApp
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets services registered at the application level.
|
||||
/// </summary>
|
||||
public T GetService<T>()
|
||||
where T : class;
|
||||
}
|
||||
@@ -1,120 +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;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CmdPal.Common.Contracts;
|
||||
using Microsoft.CmdPal.Common.Helpers;
|
||||
using Microsoft.CmdPal.Common.Models;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace Microsoft.CmdPal.Common.Services;
|
||||
|
||||
public class LocalSettingsService : ILocalSettingsService
|
||||
{
|
||||
// TODO! for now, we're hardcoding the path as effectively:
|
||||
// %localappdata%\CmdPal\LocalSettings.json
|
||||
private const string DefaultApplicationDataFolder = "CmdPal";
|
||||
private const string DefaultLocalSettingsFile = "LocalSettings.json";
|
||||
|
||||
private readonly IFileService _fileService;
|
||||
private readonly LocalSettingsOptions _options;
|
||||
|
||||
private readonly string _localApplicationData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
private readonly string _applicationDataFolder;
|
||||
private readonly string _localSettingsFile;
|
||||
|
||||
private readonly bool _isMsix;
|
||||
|
||||
private Dictionary<string, object> _settings;
|
||||
private bool _isInitialized;
|
||||
|
||||
public LocalSettingsService(IFileService fileService, IOptions<LocalSettingsOptions> options)
|
||||
{
|
||||
_isMsix = false; // RuntimeHelper.IsMSIX;
|
||||
|
||||
_fileService = fileService;
|
||||
_options = options.Value;
|
||||
|
||||
_applicationDataFolder = Path.Combine(_localApplicationData, _options.ApplicationDataFolder ?? DefaultApplicationDataFolder);
|
||||
_localSettingsFile = _options.LocalSettingsFile ?? DefaultLocalSettingsFile;
|
||||
|
||||
_settings = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
private async Task InitializeAsync()
|
||||
{
|
||||
if (!_isInitialized)
|
||||
{
|
||||
_settings = await Task.Run(() => _fileService.Read<Dictionary<string, object>>(_applicationDataFolder, _localSettingsFile)) ?? new Dictionary<string, object>();
|
||||
|
||||
_isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> HasSettingAsync(string key)
|
||||
{
|
||||
if (_isMsix)
|
||||
{
|
||||
return ApplicationData.Current.LocalSettings.Values.ContainsKey(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
await InitializeAsync();
|
||||
|
||||
if (_settings != null)
|
||||
{
|
||||
return _settings.ContainsKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<T?> ReadSettingAsync<T>(string key)
|
||||
{
|
||||
if (_isMsix)
|
||||
{
|
||||
if (ApplicationData.Current.LocalSettings.Values.TryGetValue(key, out var obj))
|
||||
{
|
||||
return await Json.ToObjectAsync<T>((string)obj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await InitializeAsync();
|
||||
|
||||
if (_settings != null && _settings.TryGetValue(key, out var obj))
|
||||
{
|
||||
var s = obj.ToString();
|
||||
|
||||
if (s != null)
|
||||
{
|
||||
return await Json.ToObjectAsync<T>(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public async Task SaveSettingAsync<T>(string key, T value)
|
||||
{
|
||||
if (_isMsix)
|
||||
{
|
||||
ApplicationData.Current.LocalSettings.Values[key] = await Json.StringifyAsync(value!);
|
||||
}
|
||||
else
|
||||
{
|
||||
await InitializeAsync();
|
||||
|
||||
_settings[key] = await Json.StringifyAsync(value!);
|
||||
|
||||
await Task.Run(() => _fileService.Save(_applicationDataFolder, _localSettingsFile, _settings));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ public partial class AppStateModel : ObservableObject
|
||||
// Read the JSON content from the file
|
||||
var jsonContent = File.ReadAllText(FilePath);
|
||||
|
||||
var loaded = JsonSerializer.Deserialize<AppStateModel>(jsonContent, _deserializerOptions);
|
||||
var loaded = JsonSerializer.Deserialize<AppStateModel>(jsonContent, JsonSerializationContext.Default.AppStateModel);
|
||||
|
||||
Debug.WriteLine(loaded != null ? "Loaded settings file" : "Failed to parse");
|
||||
|
||||
@@ -73,7 +73,7 @@ public partial class AppStateModel : ObservableObject
|
||||
try
|
||||
{
|
||||
// Serialize the main dictionary to JSON and save it to the file
|
||||
var settingsJson = JsonSerializer.Serialize(model, _serializerOptions);
|
||||
var settingsJson = JsonSerializer.Serialize(model, JsonSerializationContext.Default.AppStateModel);
|
||||
|
||||
// Is it valid JSON?
|
||||
if (JsonNode.Parse(settingsJson) is JsonObject newSettings)
|
||||
@@ -89,7 +89,7 @@ public partial class AppStateModel : ObservableObject
|
||||
savedSettings[item.Key] = item.Value != null ? item.Value.DeepClone() : null;
|
||||
}
|
||||
|
||||
var serialized = savedSettings.ToJsonString(_serializerOptions);
|
||||
var serialized = savedSettings.ToJsonString(JsonSerializationContext.Default.AppStateModel.Options);
|
||||
File.WriteAllText(FilePath, serialized);
|
||||
|
||||
// TODO: Instead of just raising the event here, we should
|
||||
@@ -122,18 +122,19 @@ public partial class AppStateModel : ObservableObject
|
||||
return Path.Combine(directory, "state.json");
|
||||
}
|
||||
|
||||
private static readonly JsonSerializerOptions _serializerOptions = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
Converters = { new JsonStringEnumConverter() },
|
||||
};
|
||||
// [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
|
||||
// private static readonly JsonSerializerOptions _serializerOptions = new()
|
||||
// {
|
||||
// WriteIndented = true,
|
||||
// Converters = { new JsonStringEnumConverter() },
|
||||
// };
|
||||
|
||||
private static readonly JsonSerializerOptions _deserializerOptions = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
IncludeFields = true,
|
||||
AllowTrailingCommas = true,
|
||||
PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||
};
|
||||
// private static readonly JsonSerializerOptions _deserializerOptions = new()
|
||||
// {
|
||||
// PropertyNameCaseInsensitive = true,
|
||||
// IncludeFields = true,
|
||||
// AllowTrailingCommas = true,
|
||||
// PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate,
|
||||
// ReadCommentHandling = JsonCommentHandling.Skip,
|
||||
// };
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -190,7 +190,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
contextItem.SlowInitializeProperties();
|
||||
});
|
||||
|
||||
if (!string.IsNullOrEmpty(model.Command.Name))
|
||||
if (!string.IsNullOrEmpty(model.Command?.Name))
|
||||
{
|
||||
_defaultCommandContextItem = new(new CommandContextItem(model.Command!), PageContext)
|
||||
{
|
||||
|
||||
@@ -13,12 +13,13 @@ internal sealed partial class CreatedExtensionForm : NewExtensionFormBase
|
||||
{
|
||||
public CreatedExtensionForm(string name, string displayName, string path)
|
||||
{
|
||||
var serializeString = (string? s) => JsonSerializer.Serialize(s, JsonSerializationContext.Default.String);
|
||||
TemplateJson = CardTemplate;
|
||||
DataJson = $$"""
|
||||
{
|
||||
"name": {{JsonSerializer.Serialize(name)}},
|
||||
"directory": {{JsonSerializer.Serialize(path)}},
|
||||
"displayName": {{JsonSerializer.Serialize(displayName)}}
|
||||
"name": {{serializeString(name)}},
|
||||
"directory": {{serializeString(path)}},
|
||||
"displayName": {{serializeString(displayName)}}
|
||||
}
|
||||
""";
|
||||
_name = name;
|
||||
@@ -28,13 +29,13 @@ internal sealed partial class CreatedExtensionForm : NewExtensionFormBase
|
||||
|
||||
public override ICommandResult SubmitForm(string inputs, string data)
|
||||
{
|
||||
JsonObject? dataInput = JsonNode.Parse(data)?.AsObject();
|
||||
var dataInput = JsonNode.Parse(data)?.AsObject();
|
||||
if (dataInput == null)
|
||||
{
|
||||
return CommandResult.KeepOpen();
|
||||
}
|
||||
|
||||
string verb = dataInput["x"]?.AsValue()?.ToString() ?? string.Empty;
|
||||
var verb = dataInput["x"]?.AsValue()?.ToString() ?? string.Empty;
|
||||
return verb switch
|
||||
{
|
||||
"sln" => OpenSolution(),
|
||||
@@ -47,7 +48,7 @@ internal sealed partial class CreatedExtensionForm : NewExtensionFormBase
|
||||
private ICommandResult OpenSolution()
|
||||
{
|
||||
string[] parts = [_path, _name, $"{_name}.sln"];
|
||||
string pathToSolution = Path.Combine(parts);
|
||||
var pathToSolution = Path.Combine(parts);
|
||||
ShellHelpers.OpenInShell(pathToSolution);
|
||||
return CommandResult.Hide();
|
||||
}
|
||||
@@ -55,7 +56,7 @@ internal sealed partial class CreatedExtensionForm : NewExtensionFormBase
|
||||
private ICommandResult OpenDirectory()
|
||||
{
|
||||
string[] parts = [_path, _name];
|
||||
string pathToDir = Path.Combine(parts);
|
||||
var pathToDir = Path.Combine(parts);
|
||||
ShellHelpers.OpenInShell(pathToDir);
|
||||
return CommandResult.Hide();
|
||||
}
|
||||
|
||||
@@ -194,9 +194,8 @@ internal sealed partial class NewExtensionForm : NewExtensionFormBase
|
||||
Directory.Delete(tempDir, true);
|
||||
}
|
||||
|
||||
private string FormatJsonString(string str)
|
||||
{
|
||||
private string FormatJsonString(string str) =>
|
||||
|
||||
// Escape the string for JSON
|
||||
return JsonSerializer.Serialize(str);
|
||||
}
|
||||
JsonSerializer.Serialize(str, JsonSerializationContext.Default.String);
|
||||
}
|
||||
|
||||
@@ -51,15 +51,16 @@ public partial class ContentFormViewModel(IFormContent _form, WeakReference<IPag
|
||||
// If we fail to parse the card JSON, then display _our own card_
|
||||
// with the exception
|
||||
AdaptiveCardTemplate template = new(ErrorCardJson);
|
||||
var serializeString = (string? s) => JsonSerializer.Serialize(s, JsonSerializationContext.Default.String);
|
||||
|
||||
// todo: we could probably stick Card.Errors in there too
|
||||
var dataJson = $$"""
|
||||
{
|
||||
"error_message": {{JsonSerializer.Serialize(e.Message)}},
|
||||
"error_stack": {{JsonSerializer.Serialize(e.StackTrace)}},
|
||||
"inner_exception": {{JsonSerializer.Serialize(e.InnerException?.Message)}},
|
||||
"template_json": {{JsonSerializer.Serialize(TemplateJson)}},
|
||||
"data_json": {{JsonSerializer.Serialize(DataJson)}}
|
||||
"error_message": {{serializeString(e.Message)}},
|
||||
"error_stack": {{serializeString(e.StackTrace)}},
|
||||
"inner_exception": {{serializeString(e.InnerException?.Message)}},
|
||||
"template_json": {{serializeString(TemplateJson)}},
|
||||
"data_json": {{serializeString(DataJson)}}
|
||||
}
|
||||
""";
|
||||
var cardJson = template.Expand(dataJson);
|
||||
|
||||
@@ -328,7 +328,19 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void UpdateSelectedItem(ListItemViewModel item)
|
||||
private void UpdateSelectedItem(ListItemViewModel? item)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
SetSelectedItem(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearSelectedItem();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSelectedItem(ListItemViewModel item)
|
||||
{
|
||||
if (!item.SafeSlowInit())
|
||||
{
|
||||
@@ -357,6 +369,23 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
});
|
||||
}
|
||||
|
||||
private void ClearSelectedItem()
|
||||
{
|
||||
// GH #322:
|
||||
// For inexplicable reasons, if you try updating the command bar and
|
||||
// the details on the same UI thread tick as updating the list, we'll
|
||||
// explode
|
||||
DoOnUiThread(
|
||||
() =>
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<UpdateCommandBarMessage>(new(null));
|
||||
|
||||
WeakReferenceMessenger.Default.Send<HideDetailsMessage>();
|
||||
|
||||
TextToSuggest = string.Empty;
|
||||
});
|
||||
}
|
||||
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
base.InitializeProperties();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
@@ -67,4 +69,15 @@
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Just mark it as AOT compatible. Do not publish with AOT now. We need fully test before we really publish it as AOT enabled-->
|
||||
<!--<PropertyGroup>
|
||||
<SelfContained>true</SelfContained>
|
||||
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
--><!-- <DisableRuntimeMarshalling>true</DisableRuntimeMarshalling> --><!--
|
||||
<PublishAot>true</PublishAot>
|
||||
<EnableMsixTooling>true</EnableMsixTooling>
|
||||
</PropertyGroup>-->
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -11,7 +11,7 @@ using Windows.Foundation.Collections;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.ViewModels.Models;
|
||||
|
||||
public class ExtensionService : IExtensionService, IDisposable
|
||||
public partial class ExtensionService : IExtensionService, IDisposable
|
||||
{
|
||||
public event TypedEventHandler<IExtensionService, IEnumerable<IExtensionWrapper>>? OnExtensionAdded;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ using Windows.Win32;
|
||||
using Windows.Win32.System.Com;
|
||||
using WinRT;
|
||||
|
||||
// [assembly: System.Runtime.CompilerServices.DisableRuntimeMarshalling]
|
||||
namespace Microsoft.CmdPal.UI.ViewModels.Models;
|
||||
|
||||
public class ExtensionWrapper : IExtensionWrapper
|
||||
@@ -113,25 +114,36 @@ public class ExtensionWrapper : IExtensionWrapper
|
||||
// -2147467262: E_NOINTERFACE
|
||||
// -2147024893: E_PATH_NOT_FOUND
|
||||
var guid = typeof(IExtension).GUID;
|
||||
var hr = PInvoke.CoCreateInstance(Guid.Parse(ExtensionClassId), null, CLSCTX.CLSCTX_LOCAL_SERVER, guid, out var extensionObj);
|
||||
|
||||
if (hr.Value == -2147024893)
|
||||
unsafe
|
||||
{
|
||||
Logger.LogDebug($"Failed to find {ExtensionDisplayName}: {hr}. It may have been uninstalled or deleted.");
|
||||
var hr = PInvoke.CoCreateInstance(Guid.Parse(ExtensionClassId), null, CLSCTX.CLSCTX_LOCAL_SERVER, guid, out var extensionObj);
|
||||
|
||||
// We don't really need to throw this exception.
|
||||
// We'll just return out nothing.
|
||||
return;
|
||||
if (hr.Value == -2147024893)
|
||||
{
|
||||
Logger.LogDebug($"Failed to find {ExtensionDisplayName}: {hr}. It may have been uninstalled or deleted.");
|
||||
|
||||
// We don't really need to throw this exception.
|
||||
// We'll just return out nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
extensionPtr = Marshal.GetIUnknownForObject((nint)extensionObj);
|
||||
if (hr < 0)
|
||||
{
|
||||
Logger.LogDebug($"Failed to instantiate {ExtensionDisplayName}: {hr}");
|
||||
Marshal.ThrowExceptionForHR(hr);
|
||||
}
|
||||
|
||||
// extensionPtr = Marshal.GetIUnknownForObject(extensionObj);
|
||||
extensionPtr = (nint)extensionObj;
|
||||
if (hr < 0)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(hr);
|
||||
}
|
||||
|
||||
_extensionObject = MarshalInterface<IExtension>.FromAbi(extensionPtr);
|
||||
}
|
||||
|
||||
extensionPtr = Marshal.GetIUnknownForObject(extensionObj);
|
||||
if (hr < 0)
|
||||
{
|
||||
Logger.LogDebug($"Failed to instantiate {ExtensionDisplayName}: {hr}");
|
||||
Marshal.ThrowExceptionForHR(hr);
|
||||
}
|
||||
|
||||
_extensionObject = MarshalInterface<IExtension>.FromAbi(extensionPtr);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "https://aka.ms/CsWin32.schema.json",
|
||||
"allowMarshaling": false
|
||||
}
|
||||
@@ -99,7 +99,7 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
|
||||
//// Run on background thread from ListPage.xaml.cs
|
||||
[RelayCommand]
|
||||
private Task<bool> InitializeAsync()
|
||||
internal Task<bool> InitializeAsync()
|
||||
{
|
||||
// TODO: We may want a SemaphoreSlim lock here.
|
||||
|
||||
@@ -182,6 +182,7 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
return; // throw?
|
||||
}
|
||||
|
||||
var updateProperty = true;
|
||||
switch (propertyName)
|
||||
{
|
||||
case nameof(Name):
|
||||
@@ -198,9 +199,21 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
case nameof(Icon):
|
||||
this.Icon = new(model.Icon);
|
||||
break;
|
||||
default:
|
||||
updateProperty = false;
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateProperty(propertyName);
|
||||
// GH #38829: If we always UpdateProperty here, then there's a possible
|
||||
// race condition, where we raise the PropertyChanged(SearchText)
|
||||
// before the subclass actually retrieves the new SearchText from the
|
||||
// model. In that race situation, if the UI thread handles the
|
||||
// PropertyChanged before ListViewModel fetches the SearchText, it'll
|
||||
// think that the old search text is the _new_ value.
|
||||
if (updateProperty)
|
||||
{
|
||||
UpdateProperty(propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
public new void ShowException(Exception ex, string? extensionHint = null)
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Microsoft.CmdPal.UI.ViewModels;
|
||||
public partial class RecentCommandsManager : ObservableObject
|
||||
{
|
||||
[JsonInclude]
|
||||
private List<HistoryItem> History { get; set; } = [];
|
||||
internal List<HistoryItem> History { get; set; } = [];
|
||||
|
||||
public RecentCommandsManager()
|
||||
{
|
||||
|
||||
@@ -93,7 +93,7 @@ public partial class SettingsModel : ObservableObject
|
||||
// Read the JSON content from the file
|
||||
var jsonContent = File.ReadAllText(FilePath);
|
||||
|
||||
var loaded = JsonSerializer.Deserialize<SettingsModel>(jsonContent, _deserializerOptions);
|
||||
var loaded = JsonSerializer.Deserialize<SettingsModel>(jsonContent, JsonSerializationContext.Default.SettingsModel);
|
||||
|
||||
Debug.WriteLine(loaded != null ? "Loaded settings file" : "Failed to parse");
|
||||
|
||||
@@ -117,7 +117,7 @@ public partial class SettingsModel : ObservableObject
|
||||
try
|
||||
{
|
||||
// Serialize the main dictionary to JSON and save it to the file
|
||||
var settingsJson = JsonSerializer.Serialize(model, _serializerOptions);
|
||||
var settingsJson = JsonSerializer.Serialize(model, JsonSerializationContext.Default.SettingsModel);
|
||||
|
||||
// Is it valid JSON?
|
||||
if (JsonNode.Parse(settingsJson) is JsonObject newSettings)
|
||||
@@ -133,7 +133,7 @@ public partial class SettingsModel : ObservableObject
|
||||
savedSettings[item.Key] = item.Value != null ? item.Value.DeepClone() : null;
|
||||
}
|
||||
|
||||
var serialized = savedSettings.ToJsonString(_serializerOptions);
|
||||
var serialized = savedSettings.ToJsonString(JsonSerializationContext.Default.Options);
|
||||
File.WriteAllText(FilePath, serialized);
|
||||
|
||||
// TODO: Instead of just raising the event here, we should
|
||||
@@ -166,19 +166,34 @@ public partial class SettingsModel : ObservableObject
|
||||
return Path.Combine(directory, "settings.json");
|
||||
}
|
||||
|
||||
private static readonly JsonSerializerOptions _serializerOptions = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
Converters = { new JsonStringEnumConverter() },
|
||||
};
|
||||
// [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
|
||||
// private static readonly JsonSerializerOptions _serializerOptions = new()
|
||||
// {
|
||||
// WriteIndented = true,
|
||||
// Converters = { new JsonStringEnumConverter() },
|
||||
// };
|
||||
// private static readonly JsonSerializerOptions _deserializerOptions = new()
|
||||
// {
|
||||
// PropertyNameCaseInsensitive = true,
|
||||
// IncludeFields = true,
|
||||
// Converters = { new JsonStringEnumConverter() },
|
||||
// AllowTrailingCommas = true,
|
||||
// };
|
||||
}
|
||||
|
||||
private static readonly JsonSerializerOptions _deserializerOptions = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
IncludeFields = true,
|
||||
Converters = { new JsonStringEnumConverter() },
|
||||
AllowTrailingCommas = true,
|
||||
};
|
||||
[JsonSerializable(typeof(float))]
|
||||
[JsonSerializable(typeof(int))]
|
||||
[JsonSerializable(typeof(string))]
|
||||
[JsonSerializable(typeof(bool))]
|
||||
[JsonSerializable(typeof(HistoryItem))]
|
||||
[JsonSerializable(typeof(SettingsModel))]
|
||||
[JsonSerializable(typeof(AppStateModel))]
|
||||
[JsonSerializable(typeof(List<HistoryItem>), TypeInfoPropertyName = "HistoryList")]
|
||||
[JsonSerializable(typeof(Dictionary<string, object>), TypeInfoPropertyName = "Dictionary")]
|
||||
[JsonSourceGenerationOptions(UseStringEnumConverter = true, WriteIndented = true, IncludeFields = true, PropertyNameCaseInsensitive = true, AllowTrailingCommas = true)]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Just used here")]
|
||||
internal sealed partial class JsonSerializationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public enum MonitorBehavior
|
||||
|
||||
@@ -109,9 +109,12 @@ public partial class ShellViewModel(IServiceProvider _serviceProvider, TaskSched
|
||||
// TODO GH #239 switch back when using the new MD text block
|
||||
// _ = _queue.EnqueueAsync(() =>
|
||||
_ = Task.Factory.StartNew(
|
||||
() =>
|
||||
async () =>
|
||||
{
|
||||
var result = (bool)viewModel.InitializeCommand.ExecutionTask.GetResultOrDefault()!;
|
||||
// bool f = await viewModel.InitializeCommand.ExecutionTask.;
|
||||
// var result = viewModel.InitializeCommand.ExecutionTask.GetResultOrDefault()!;
|
||||
// var result = viewModel.InitializeCommand.ExecutionTask.GetResultOrDefault<bool?>()!;
|
||||
var result = await viewModel.InitializeAsync();
|
||||
|
||||
CurrentPage = viewModel; // result ? viewModel : null;
|
||||
////LoadedState = result ? ViewModelLoadedState.Loaded : ViewModelLoadedState.Error;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
@@ -53,53 +54,44 @@ public partial class TopLevelCommandManager : ObservableObject,
|
||||
{
|
||||
CommandProviderWrapper wrapper = new(provider, _taskScheduler);
|
||||
_builtInCommands.Add(wrapper);
|
||||
await LoadTopLevelCommandsFromProvider(wrapper);
|
||||
var commands = await LoadTopLevelCommandsFromProvider(wrapper);
|
||||
lock (TopLevelCommands)
|
||||
{
|
||||
foreach (var c in commands)
|
||||
{
|
||||
TopLevelCommands.Add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// May be called from a background thread
|
||||
private async Task LoadTopLevelCommandsFromProvider(CommandProviderWrapper commandProvider)
|
||||
private async Task<IEnumerable<TopLevelViewModel>> LoadTopLevelCommandsFromProvider(CommandProviderWrapper commandProvider)
|
||||
{
|
||||
WeakReference<IPageContext> weakSelf = new(this);
|
||||
|
||||
await commandProvider.LoadTopLevelCommands(_serviceProvider, weakSelf);
|
||||
|
||||
var settings = _serviceProvider.GetService<SettingsModel>()!;
|
||||
var makeAndAdd = (ICommandItem? i, bool fallback) =>
|
||||
|
||||
List<TopLevelViewModel> commands = [];
|
||||
|
||||
foreach (var item in commandProvider.TopLevelItems)
|
||||
{
|
||||
var commandItemViewModel = new CommandItemViewModel(new(i), weakSelf);
|
||||
var topLevelViewModel = new TopLevelViewModel(commandItemViewModel, fallback, commandProvider.ExtensionHost, commandProvider.ProviderId, settings, _serviceProvider);
|
||||
commands.Add(item);
|
||||
}
|
||||
|
||||
lock (TopLevelCommands)
|
||||
{
|
||||
TopLevelCommands.Add(topLevelViewModel);
|
||||
}
|
||||
};
|
||||
|
||||
await Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
lock (TopLevelCommands)
|
||||
{
|
||||
foreach (var item in commandProvider.TopLevelItems)
|
||||
{
|
||||
TopLevelCommands.Add(item);
|
||||
}
|
||||
|
||||
foreach (var item in commandProvider.FallbackItems)
|
||||
{
|
||||
TopLevelCommands.Add(item);
|
||||
}
|
||||
}
|
||||
},
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.None,
|
||||
_taskScheduler);
|
||||
foreach (var item in commandProvider.FallbackItems)
|
||||
{
|
||||
commands.Add(item);
|
||||
}
|
||||
|
||||
commandProvider.CommandsChanged -= CommandProvider_CommandsChanged;
|
||||
commandProvider.CommandsChanged += CommandProvider_CommandsChanged;
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
// By all accounts, we're already on a background thread (the COM call
|
||||
@@ -239,25 +231,71 @@ public partial class TopLevelCommandManager : ObservableObject,
|
||||
|
||||
private async Task StartExtensionsAndGetCommands(IEnumerable<IExtensionWrapper> extensions)
|
||||
{
|
||||
// TODO This most definitely needs a lock
|
||||
foreach (var extension in extensions)
|
||||
{
|
||||
Logger.LogDebug($"Starting {extension.PackageFullName}");
|
||||
try
|
||||
{
|
||||
// start it ...
|
||||
await extension.StartExtensionAsync();
|
||||
var timer = new Stopwatch();
|
||||
timer.Start();
|
||||
|
||||
// ... and fetch the command provider from it.
|
||||
CommandProviderWrapper wrapper = new(extension, _taskScheduler);
|
||||
_extensionCommandProviders.Add(wrapper);
|
||||
await LoadTopLevelCommandsFromProvider(wrapper);
|
||||
}
|
||||
catch (Exception ex)
|
||||
// Start all extensions in parallel
|
||||
var startTasks = extensions.Select(StartExtensionWithTimeoutAsync);
|
||||
|
||||
// Wait for all extensions to start
|
||||
var wrappers = (await Task.WhenAll(startTasks)).Where(wrapper => wrapper != null).Select(w => w!).ToList();
|
||||
|
||||
foreach (var wrapper in wrappers)
|
||||
{
|
||||
_extensionCommandProviders.Add(wrapper!);
|
||||
}
|
||||
|
||||
// Load the commands from the providers in parallel
|
||||
var loadTasks = wrappers.Select(LoadCommandsWithTimeoutAsync);
|
||||
|
||||
var commandSets = (await Task.WhenAll(loadTasks)).Where(results => results != null).Select(r => r!).ToList();
|
||||
|
||||
lock (TopLevelCommands)
|
||||
{
|
||||
foreach (var commands in commandSets)
|
||||
{
|
||||
Logger.LogError(ex.ToString());
|
||||
foreach (var c in commands)
|
||||
{
|
||||
TopLevelCommands.Add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timer.Stop();
|
||||
Logger.LogDebug($"Loading extensions took {timer.ElapsedMilliseconds} ms");
|
||||
}
|
||||
|
||||
private async Task<CommandProviderWrapper?> StartExtensionWithTimeoutAsync(IExtensionWrapper extension)
|
||||
{
|
||||
Logger.LogDebug($"Starting {extension.PackageFullName}");
|
||||
try
|
||||
{
|
||||
await extension.StartExtensionAsync().WaitAsync(TimeSpan.FromSeconds(10));
|
||||
return new CommandProviderWrapper(extension, _taskScheduler);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Failed to start extension {extension.PackageFullName}: {ex}");
|
||||
return null; // Return null for failed extensions
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<TopLevelViewModel>?> LoadCommandsWithTimeoutAsync(CommandProviderWrapper wrapper)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await LoadTopLevelCommandsFromProvider(wrapper!).WaitAsync(TimeSpan.FromSeconds(10));
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
Logger.LogError($"Loading commands from {wrapper!.ExtensionHost?.Extension?.PackageFullName} timed out");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Failed to load commands for extension {wrapper!.ExtensionHost?.Extension?.PackageFullName}: {ex}");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ExtensionService_OnExtensionRemoved(IExtensionService sender, IEnumerable<IExtensionWrapper> extensions)
|
||||
|
||||
@@ -6,19 +6,8 @@ using ManagedCommon;
|
||||
using Microsoft.CmdPal.Common.Helpers;
|
||||
using Microsoft.CmdPal.Common.Services;
|
||||
using Microsoft.CmdPal.Ext.Apps;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks;
|
||||
using Microsoft.CmdPal.Ext.Calc;
|
||||
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.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.BuiltinCommands;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Models;
|
||||
@@ -110,40 +99,17 @@ public partial class App : Application
|
||||
var allApps = new AllAppsCommandProvider();
|
||||
services.AddSingleton<ICommandProvider>(allApps);
|
||||
services.AddSingleton<ICommandProvider, ShellCommandsProvider>();
|
||||
services.AddSingleton<ICommandProvider, CalculatorCommandProvider>();
|
||||
services.AddSingleton<ICommandProvider, IndexerCommandsProvider>();
|
||||
services.AddSingleton<ICommandProvider, BookmarksCommandProvider>();
|
||||
|
||||
// TODO GH #527 re-enable the clipboard commands
|
||||
// services.AddSingleton<ICommandProvider, ClipboardHistoryCommandsProvider>();
|
||||
services.AddSingleton<ICommandProvider, WindowWalkerCommandsProvider>();
|
||||
services.AddSingleton<ICommandProvider, WebSearchCommandsProvider>();
|
||||
|
||||
// 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>();
|
||||
|
||||
@@ -124,14 +124,12 @@ public sealed partial class ListPage : Page,
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS is too aggressive at pruning methods bound in XAML")]
|
||||
private void ItemsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ItemsList.SelectedItem is ListItemViewModel item)
|
||||
var vm = ViewModel;
|
||||
var li = ItemsList.SelectedItem as ListItemViewModel;
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
var vm = ViewModel;
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
vm?.UpdateSelectedItemCommand.Execute(item);
|
||||
});
|
||||
}
|
||||
vm?.UpdateSelectedItemCommand.Execute(li);
|
||||
});
|
||||
|
||||
// There's mysterious behavior here, where the selection seemingly
|
||||
// changes to _nothing_ when we're backspacing to a single character.
|
||||
|
||||
@@ -2,13 +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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks;
|
||||
using Microsoft.UI.Xaml.Documents;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Helpers;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Window
|
||||
<winuiex:WindowEx
|
||||
x:Class="Microsoft.CmdPal.UI.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -6,8 +6,13 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:pages="using:Microsoft.CmdPal.UI.Pages"
|
||||
xmlns:viewmodels="using:Microsoft.CmdPal.UI.ViewModels"
|
||||
xmlns:winuiex="using:WinUIEx"
|
||||
Width="800"
|
||||
Height="480"
|
||||
MinWidth="320"
|
||||
MinHeight="240"
|
||||
Activated="MainWindow_Activated"
|
||||
Closed="MainWindow_Closed"
|
||||
mc:Ignorable="d">
|
||||
<pages:ShellPage x:Name="RootShellPage" />
|
||||
</Window>
|
||||
</winuiex:WindowEx>
|
||||
|
||||
@@ -25,15 +25,17 @@ using Windows.UI;
|
||||
using Windows.UI.WindowManagement;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Graphics.Dwm;
|
||||
using Windows.Win32.UI.Input.KeyboardAndMouse;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using WinRT;
|
||||
using WinUIEx;
|
||||
using RS_ = Microsoft.CmdPal.UI.Helpers.ResourceLoaderInstance;
|
||||
|
||||
namespace Microsoft.CmdPal.UI;
|
||||
|
||||
public sealed partial class MainWindow : Window,
|
||||
public sealed partial class MainWindow : WindowEx,
|
||||
IRecipient<DismissMessage>,
|
||||
IRecipient<ShowWindowMessage>,
|
||||
IRecipient<HideWindowMessage>,
|
||||
@@ -82,7 +84,6 @@ public sealed partial class MainWindow : Window,
|
||||
|
||||
this.SetIcon();
|
||||
AppWindow.Title = RS_.GetString("AppName");
|
||||
AppWindow.Resize(new SizeInt32 { Width = 1000, Height = 620 });
|
||||
PositionCentered();
|
||||
SetAcrylic();
|
||||
|
||||
@@ -232,6 +233,16 @@ public sealed partial class MainWindow : Window,
|
||||
PositionCentered(display);
|
||||
|
||||
PInvoke.ShowWindow(hwnd, SHOW_WINDOW_CMD.SW_SHOW);
|
||||
|
||||
// instead of showing the window, uncloak it from DWM
|
||||
// This will make it visible to the user, without the animation or frames for
|
||||
// loading XAML with composition
|
||||
unsafe
|
||||
{
|
||||
BOOL value = false;
|
||||
PInvoke.DwmSetWindowAttribute(_hwnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAK, (void*)&value, (uint)sizeof(BOOL));
|
||||
}
|
||||
|
||||
PInvoke.SetForegroundWindow(hwnd);
|
||||
PInvoke.SetActiveWindow(hwnd);
|
||||
}
|
||||
@@ -289,7 +300,7 @@ public sealed partial class MainWindow : Window,
|
||||
ShowHwnd(message.Hwnd, settings.SummonOn);
|
||||
}
|
||||
|
||||
public void Receive(HideWindowMessage message) => PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
public void Receive(HideWindowMessage message) => HideWindow();
|
||||
|
||||
public void Receive(QuitMessage message) =>
|
||||
|
||||
@@ -297,7 +308,21 @@ public sealed partial class MainWindow : Window,
|
||||
DispatcherQueue.TryEnqueue(() => Close());
|
||||
|
||||
public void Receive(DismissMessage message) =>
|
||||
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
HideWindow();
|
||||
|
||||
private void HideWindow()
|
||||
{
|
||||
// Hide our window
|
||||
|
||||
// Instead of hiding the window, cloak it from DWM
|
||||
// This will make it invisible to the user, such that we can show it again
|
||||
// by uncloaking it, which avoids an unnecessary "flicker in" that XAML does
|
||||
unsafe
|
||||
{
|
||||
BOOL value = true;
|
||||
PInvoke.DwmSetWindowAttribute(_hwnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAK, (void*)&value, (uint)sizeof(BOOL));
|
||||
}
|
||||
}
|
||||
|
||||
internal void MainWindow_Closed(object sender, WindowEventArgs args)
|
||||
{
|
||||
@@ -386,7 +411,9 @@ public sealed partial class MainWindow : Window,
|
||||
return;
|
||||
}
|
||||
|
||||
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
// This will DWM cloak our window:
|
||||
HideWindow();
|
||||
|
||||
PowerToysTelemetry.Log.WriteEvent(new CmdPalDismissedOnLostFocus());
|
||||
}
|
||||
|
||||
@@ -404,11 +431,6 @@ public sealed partial class MainWindow : Window,
|
||||
// know till the message is being handled.
|
||||
WeakReferenceMessenger.Default.Send<HotkeySummonMessage>(new(commandId, _hwnd));
|
||||
|
||||
#pragma warning disable SA1310 // Field names should not contain underscore
|
||||
private const uint DOT_KEY = 0xBE;
|
||||
private const uint WM_HOTKEY = 0x0312;
|
||||
#pragma warning restore SA1310 // Field names should not contain underscore
|
||||
|
||||
private void UnregisterHotkeys()
|
||||
{
|
||||
_keyboardListener.ClearHotkeys();
|
||||
@@ -479,10 +501,24 @@ public sealed partial class MainWindow : Window,
|
||||
var isRootHotkey = string.IsNullOrEmpty(commandId);
|
||||
PowerToysTelemetry.Log.WriteEvent(new CmdPalHotkeySummoned(isRootHotkey));
|
||||
|
||||
var isVisible = this.Visible;
|
||||
unsafe
|
||||
{
|
||||
// We need to check if our window is cloaked or not. A cloaked window is still
|
||||
// technically visible, because SHOW/HIDE != iconic (minimized) != cloaked
|
||||
// (these are all separate states)
|
||||
long attr = 0;
|
||||
PInvoke.DwmGetWindowAttribute(_hwnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAKED, &attr, sizeof(long));
|
||||
if (attr == 1 /* DWM_CLOAKED_APP */)
|
||||
{
|
||||
isVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Note to future us: the wParam will have the index of the hotkey we registered.
|
||||
// We can use that in the future to differentiate the hotkeys we've pressed
|
||||
// so that we can bind hotkeys to individual commands
|
||||
if (!this.Visible || !isRootHotkey)
|
||||
if (!isVisible || !isRootHotkey)
|
||||
{
|
||||
Activate();
|
||||
|
||||
@@ -490,7 +526,16 @@ public sealed partial class MainWindow : Window,
|
||||
}
|
||||
else if (isRootHotkey)
|
||||
{
|
||||
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
// If there's a debugger attached...
|
||||
if (System.Diagnostics.Debugger.IsAttached)
|
||||
{
|
||||
// ... then manually hide our window. When debugged, we won't get the cool cloaking,
|
||||
// but that's the price to pay for having the HWND not light-dismiss while we're debugging.
|
||||
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
return;
|
||||
}
|
||||
|
||||
HideWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,7 +547,10 @@ public sealed partial class MainWindow : Window,
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_HOTKEY:
|
||||
// Prevent the window from maximizing when double-clicking the title bar area
|
||||
case PInvoke.WM_NCLBUTTONDBLCLK:
|
||||
return (LRESULT)IntPtr.Zero;
|
||||
case PInvoke.WM_HOTKEY:
|
||||
{
|
||||
var hotkeyIndex = (int)wParam.Value;
|
||||
if (hotkeyIndex < _hotkeys.Count)
|
||||
@@ -518,22 +566,6 @@ public sealed partial class MainWindow : Window,
|
||||
|
||||
var hotkey = _hotkeys[hotkeyIndex];
|
||||
HandleSummon(hotkey.CommandId);
|
||||
|
||||
// var isRootHotkey = string.IsNullOrEmpty(hotkey.CommandId);
|
||||
|
||||
// // Note to future us: the wParam will have the index of the hotkey we registered.
|
||||
// // We can use that in the future to differentiate the hotkeys we've pressed
|
||||
// // so that we can bind hotkeys to individual commands
|
||||
// if (!this.Visible || !isRootHotkey)
|
||||
// {
|
||||
// Activate();
|
||||
|
||||
// Summon(hotkey.CommandId);
|
||||
// }
|
||||
// else if (isRootHotkey)
|
||||
// {
|
||||
// PInvoke.ShowWindow(hwnd, SHOW_WINDOW_CMD.SW_HIDE);
|
||||
// }
|
||||
}
|
||||
|
||||
return (LRESULT)IntPtr.Zero;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\CmdPalVersion.props" />
|
||||
<Import Project="CmdPal.pre.props" />
|
||||
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
|
||||
<Import Project="CmdPal.pre.props" />
|
||||
<Import Project="CmdPal.Branding.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
@@ -66,7 +68,7 @@
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" />
|
||||
|
||||
<PackageReference Include="WinUIEx" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
@@ -97,8 +99,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.WebSearch\Microsoft.CmdPal.Ext.WebSearch.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Indexer\Microsoft.CmdPal.Ext.Indexer.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.CmdPal.Common\Microsoft.CmdPal.Common.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.CmdPal.UI.ViewModels\Microsoft.CmdPal.UI.ViewModels.csproj" />
|
||||
@@ -106,17 +106,7 @@
|
||||
<ProjectReference Include="..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
||||
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Apps\Microsoft.CmdPal.Ext.Apps.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Bookmark\Microsoft.CmdPal.Ext.Bookmarks.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Calc\Microsoft.CmdPal.Ext.Calc.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.ClipboardHistory\Microsoft.CmdPal.Ext.ClipboardHistory.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Registry\Microsoft.CmdPal.Ext.Registry.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.Shell\Microsoft.CmdPal.Ext.Shell.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.TimeDate\Microsoft.CmdPal.Ext.TimeDate.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.WindowsServices\Microsoft.CmdPal.Ext.WindowsServices.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.WindowsSettings\Microsoft.CmdPal.Ext.WindowsSettings.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.WindowsTerminal\Microsoft.CmdPal.Ext.WindowsTerminal.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.WindowWalker\Microsoft.CmdPal.Ext.WindowWalker.csproj" />
|
||||
<ProjectReference Include="..\ext\Microsoft.CmdPal.Ext.WinGet\Microsoft.CmdPal.Ext.WinGet.csproj" />
|
||||
|
||||
<ProjectReference Include="..\Microsoft.Terminal.UI\Microsoft.Terminal.UI.vcxproj">
|
||||
<ReferenceOutputAssembly>True</ReferenceOutputAssembly>
|
||||
|
||||
@@ -25,6 +25,8 @@ SHCreateStreamOnFileEx
|
||||
CoAllowSetForegroundWindow
|
||||
SHCreateStreamOnFileEx
|
||||
SHLoadIndirectString
|
||||
WM_HOTKEY
|
||||
WM_NCLBUTTONDBLCLK
|
||||
|
||||
Shell_NotifyIcon
|
||||
LoadIcon
|
||||
@@ -36,3 +38,7 @@ ExtractIconEx
|
||||
WM_RBUTTONUP
|
||||
WM_LBUTTONUP
|
||||
WM_LBUTTONDBLCLK
|
||||
|
||||
DwmGetWindowAttribute
|
||||
DwmSetWindowAttribute
|
||||
DWM_CLOAKED_APP
|
||||
@@ -418,9 +418,6 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
||||
{
|
||||
_ = DispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
// Also hide our details pane about here, if we had one
|
||||
HideDetails();
|
||||
|
||||
if (_settingsWindow == null)
|
||||
{
|
||||
_settingsWindow = new SettingsWindow();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Window
|
||||
<winuiex:WindowEx
|
||||
x:Class="Microsoft.CmdPal.UI.Settings.SettingsWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -7,13 +7,18 @@
|
||||
xmlns:local="using:Microsoft.CmdPal.UI.Settings"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
xmlns:winuiex="using:WinUIEx"
|
||||
Title="SettingsWindow"
|
||||
Width="1280"
|
||||
Height="720"
|
||||
MinWidth="480"
|
||||
MinHeight="480"
|
||||
Activated="Window_Activated"
|
||||
Closed="Window_Closed"
|
||||
mc:Ignorable="d">
|
||||
<Window.SystemBackdrop>
|
||||
<winuiex:WindowEx.SystemBackdrop>
|
||||
<MicaBackdrop />
|
||||
</Window.SystemBackdrop>
|
||||
</winuiex:WindowEx.SystemBackdrop>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -37,10 +42,10 @@
|
||||
Height="16"
|
||||
Source="ms-appx:///Assets/icon.svg" />
|
||||
<TextBlock
|
||||
x:Uid="CmdPalSettingsHeader"
|
||||
Margin="12,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="Command Palette Settings" />
|
||||
Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
</StackPanel>
|
||||
<NavigationView
|
||||
x:Name="NavView"
|
||||
@@ -100,4 +105,4 @@
|
||||
</Grid>
|
||||
</NavigationView>
|
||||
</Grid>
|
||||
</Window>
|
||||
</winuiex:WindowEx>
|
||||
|
||||
@@ -11,11 +11,12 @@ using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Windows.Graphics;
|
||||
using WinUIEx;
|
||||
using RS_ = Microsoft.CmdPal.UI.Helpers.ResourceLoaderInstance;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Settings;
|
||||
|
||||
public sealed partial class SettingsWindow : Window,
|
||||
public sealed partial class SettingsWindow : WindowEx,
|
||||
IRecipient<NavigateToExtensionSettingsMessage>,
|
||||
IRecipient<QuitMessage>
|
||||
{
|
||||
@@ -70,7 +71,6 @@ public sealed partial class SettingsWindow : Window,
|
||||
|
||||
private void PositionCentered()
|
||||
{
|
||||
AppWindow.Resize(new SizeInt32 { Width = 1280, Height = 720 });
|
||||
var displayArea = DisplayArea.GetFromWindowId(AppWindow.Id, DisplayAreaFallback.Nearest);
|
||||
if (displayArea is not null)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Window
|
||||
<winuiex:WindowEx
|
||||
x:Class="Microsoft.CmdPal.UI.ToastWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -7,17 +7,18 @@
|
||||
xmlns:local="using:Microsoft.CmdPal.UI"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
xmlns:winuiex="using:WinUIEx"
|
||||
Title="Command Palette Toast"
|
||||
mc:Ignorable="d">
|
||||
<Window.SystemBackdrop>
|
||||
<winuiex:WindowEx.SystemBackdrop>
|
||||
<DesktopAcrylicBackdrop />
|
||||
</Window.SystemBackdrop>
|
||||
</winuiex:WindowEx.SystemBackdrop>
|
||||
<Grid x:Name="ToastGrid">
|
||||
<!-- This padding is used to calculate the dimensions of the ToastWindow -->
|
||||
<TextBlock
|
||||
x:Name="ToastText"
|
||||
Padding="16,16,36,24"
|
||||
Padding="12,12,24,20"
|
||||
Text="{x:Bind ViewModel.ToastMessage, Mode=OneWay}"
|
||||
TextAlignment="Center" />
|
||||
</Grid>
|
||||
</Window>
|
||||
</winuiex:WindowEx>
|
||||
@@ -17,11 +17,12 @@ using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Graphics.Gdi;
|
||||
using Windows.Win32.UI.HiDpi;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using WinUIEx;
|
||||
using RS_ = Microsoft.CmdPal.UI.Helpers.ResourceLoaderInstance;
|
||||
|
||||
namespace Microsoft.CmdPal.UI;
|
||||
|
||||
public sealed partial class ToastWindow : Window,
|
||||
public sealed partial class ToastWindow : WindowEx,
|
||||
IRecipient<QuitMessage>
|
||||
{
|
||||
private readonly HWND _hwnd;
|
||||
@@ -64,19 +65,7 @@ public sealed partial class ToastWindow : Window,
|
||||
|
||||
private void PositionCentered()
|
||||
{
|
||||
var intSize = new SizeInt32
|
||||
{
|
||||
Width = Convert.ToInt32(ToastText.ActualWidth),
|
||||
Height = Convert.ToInt32(ToastText.ActualHeight),
|
||||
};
|
||||
|
||||
var scaleAdjustment = GetScaleFactor(_hwnd);
|
||||
var scaled = new SizeInt32
|
||||
{
|
||||
Width = (int)Math.Round(intSize.Width * scaleAdjustment),
|
||||
Height = (int)Math.Round(intSize.Height * scaleAdjustment),
|
||||
};
|
||||
AppWindow.Resize(scaled);
|
||||
this.SetWindowSize(ToastText.ActualWidth, ToastText.ActualHeight);
|
||||
|
||||
var displayArea = DisplayArea.GetFromWindowId(AppWindow.Id, DisplayAreaFallback.Nearest);
|
||||
if (displayArea is not null)
|
||||
@@ -86,7 +75,7 @@ public sealed partial class ToastWindow : Window,
|
||||
|
||||
var monitorHeight = displayArea.WorkArea.Height;
|
||||
var windowHeight = AppWindow.Size.Height;
|
||||
centeredPosition.Y = monitorHeight - (windowHeight * 2);
|
||||
centeredPosition.Y = monitorHeight - (windowHeight + 8); // Align with other shell toasts, like the volume indicator.
|
||||
AppWindow.Move(centeredPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ By default, CmdPal is bound to <kbd>Win+Alt+Space</kbd>.
|
||||
|
||||
The fastest way to get started is just to run the "Create extension" command in the palette itself. That'll prompt you for a project name and a Display Name, and where you want to place your project. Then just open the `sln` it produces. You should be ready to go 🙂.
|
||||
|
||||
The official API documentation can be found [on this docs site](TODO! Add docs link when we have one)
|
||||
The official API documentation can be found [on this docs site](https://learn.microsoft.com/windows/powertoys/command-palette/extensibility-overview).
|
||||
|
||||
We've also got samples, so that you can see how the APIs in-action.
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ using Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps;
|
||||
|
||||
public sealed class AppCache : IDisposable
|
||||
public sealed partial class AppCache : IDisposable
|
||||
{
|
||||
private Win32ProgramFileSystemWatchers _win32ProgramRepositoryHelper;
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<PropertyGroup>
|
||||
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.CmdPal.Ext.Apps</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutputPath>
|
||||
|
||||
@@ -319,7 +319,7 @@ public static class ReparsePoint
|
||||
|
||||
public static AppExecutionAliasMetadata FromPersistedRepresentationIntPtr(IntPtr reparseDataBufferPtr, AppExecutionAliasReparseTagBufferLayoutVersion version)
|
||||
{
|
||||
var dataOffset = Marshal.SizeOf(typeof(AppExecutionAliasReparseTagHeader));
|
||||
var dataOffset = Marshal.SizeOf<AppExecutionAliasReparseTagHeader>();
|
||||
var dataBufferPtr = reparseDataBufferPtr + dataOffset;
|
||||
|
||||
string? packageFullName = null;
|
||||
|
||||
@@ -8,7 +8,7 @@ using System.IO;
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Storage;
|
||||
|
||||
// File System Watcher Wrapper class which implements the IFileSystemWatcherWrapper interface
|
||||
public sealed class FileSystemWatcherWrapper : FileSystemWatcher, IFileSystemWatcherWrapper
|
||||
public sealed partial class FileSystemWatcherWrapper : FileSystemWatcher, IFileSystemWatcherWrapper
|
||||
{
|
||||
public FileSystemWatcherWrapper()
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Microsoft.CmdPal.Ext.Apps.Storage;
|
||||
/// A repository for storing packaged applications such as UWP apps or appx packaged desktop apps.
|
||||
/// This repository will also monitor for changes to the PackageCatalog and update the repository accordingly
|
||||
/// </summary>
|
||||
internal sealed class PackageRepository : ListRepository<UWPApplication>, IProgramRepository
|
||||
internal sealed partial class PackageRepository : ListRepository<UWPApplication>, IProgramRepository
|
||||
{
|
||||
private readonly IPackageCatalog _packageCatalog;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ using System.Linq;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Storage;
|
||||
|
||||
internal sealed class Win32ProgramFileSystemWatchers : IDisposable
|
||||
internal sealed partial class Win32ProgramFileSystemWatchers : IDisposable
|
||||
{
|
||||
public string[] PathsToWatch { get; set; }
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ using Win32Program = Microsoft.CmdPal.Ext.Apps.Programs.Win32Program;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Storage;
|
||||
|
||||
internal sealed class Win32ProgramRepository : ListRepository<Programs.Win32Program>, IProgramRepository
|
||||
internal sealed partial class Win32ProgramRepository : ListRepository<Programs.Win32Program>, IProgramRepository
|
||||
{
|
||||
private static readonly IFileSystem FileSystem = new FileSystem();
|
||||
private static readonly IPath Path = FileSystem.Path;
|
||||
|
||||
@@ -34,7 +34,7 @@ internal sealed partial class AddBookmarkForm : FormContent
|
||||
"style": "text",
|
||||
"id": "name",
|
||||
"label": "{{Resources.bookmarks_form_name_label}}",
|
||||
"value": {{JsonSerializer.Serialize(name)}},
|
||||
"value": {{JsonSerializer.Serialize(name, BookmarkSerializationContext.Default.String)}},
|
||||
"isRequired": true,
|
||||
"errorMessage": "{{Resources.bookmarks_form_name_required}}"
|
||||
},
|
||||
@@ -42,7 +42,7 @@ internal sealed partial class AddBookmarkForm : FormContent
|
||||
"type": "Input.Text",
|
||||
"style": "text",
|
||||
"id": "bookmark",
|
||||
"value": {{JsonSerializer.Serialize(url)}},
|
||||
"value": {{JsonSerializer.Serialize(url, BookmarkSerializationContext.Default.String)}},
|
||||
"label": "{{Resources.bookmarks_form_bookmark_label}}",
|
||||
"isRequired": true,
|
||||
"errorMessage": "{{Resources.bookmarks_form_bookmark_required}}"
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks;
|
||||
|
||||
[JsonSerializable(typeof(float))]
|
||||
[JsonSerializable(typeof(int))]
|
||||
[JsonSerializable(typeof(string))]
|
||||
[JsonSerializable(typeof(bool))]
|
||||
[JsonSerializable(typeof(BookmarkData))]
|
||||
[JsonSerializable(typeof(Bookmarks))]
|
||||
[JsonSerializable(typeof(List<BookmarkData>), TypeInfoPropertyName = "BookmarkList")]
|
||||
[JsonSourceGenerationOptions(UseStringEnumConverter = true, WriteIndented = true, IncludeFields = true, PropertyNameCaseInsensitive = true, AllowTrailingCommas = true)]
|
||||
internal sealed partial class BookmarkSerializationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
@@ -28,7 +28,7 @@ public sealed class Bookmarks
|
||||
|
||||
if (!string.IsNullOrEmpty(jsonStringReading))
|
||||
{
|
||||
data = JsonSerializer.Deserialize<Bookmarks>(jsonStringReading, _jsonOptions) ?? new Bookmarks();
|
||||
data = JsonSerializer.Deserialize<Bookmarks>(jsonStringReading, BookmarkSerializationContext.Default.Bookmarks) ?? new Bookmarks();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public sealed class Bookmarks
|
||||
|
||||
public static void WriteToFile(string path, Bookmarks data)
|
||||
{
|
||||
var jsonString = JsonSerializer.Serialize(data, _jsonOptions);
|
||||
var jsonString = JsonSerializer.Serialize(data, BookmarkSerializationContext.Default.Bookmarks);
|
||||
|
||||
File.WriteAllText(BookmarksCommandProvider.StateJsonPath(), jsonString);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.CmdPal.Ext.Bookmarks</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
@@ -16,7 +17,7 @@
|
||||
<ProjectReference Include="..\..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
||||
<ProjectReference Include="..\..\ext\Microsoft.CmdPal.Ext.Indexer\Microsoft.CmdPal.Ext.Indexer.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
@@ -24,7 +25,7 @@
|
||||
<AutoGen>True</AutoGen>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\Bookmark.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
@@ -39,5 +40,5 @@
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -17,7 +17,7 @@ internal static class NativeMethods
|
||||
internal INPUTTYPE type;
|
||||
internal InputUnion data;
|
||||
|
||||
internal static int Size => Marshal.SizeOf(typeof(INPUT));
|
||||
internal static int Size => Marshal.SizeOf<INPUT>();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.CmdPal.Ext.ClipboardHistory</RootNamespace>
|
||||
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutputPath>
|
||||
|
||||
@@ -2,7 +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 System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Data;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
@@ -10,8 +13,14 @@ using Windows.Storage.Streams;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer;
|
||||
|
||||
internal sealed partial class FallbackOpenFileItem : FallbackCommandItem
|
||||
internal sealed partial class FallbackOpenFileItem : FallbackCommandItem, System.IDisposable
|
||||
{
|
||||
private readonly CompositeFormat fallbackItemSearchPageTitleCompositeFormat = CompositeFormat.Parse(Resources.Indexer_fallback_searchPage_title);
|
||||
|
||||
private readonly SearchEngine _searchEngine = new();
|
||||
|
||||
private uint _queryCookie = 10;
|
||||
|
||||
public FallbackOpenFileItem()
|
||||
: base(new NoOpCommand(), Resources.Indexer_Find_Path_fallback_display_title)
|
||||
{
|
||||
@@ -21,8 +30,20 @@ internal sealed partial class FallbackOpenFileItem : FallbackCommandItem
|
||||
|
||||
public override void UpdateQuery(string query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
Command = new NoOpCommand();
|
||||
Title = string.Empty;
|
||||
Subtitle = string.Empty;
|
||||
Icon = null;
|
||||
MoreCommands = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Path.Exists(query))
|
||||
{
|
||||
// Exit 1: The query is a direct path to a file. Great! Return it.
|
||||
var item = new IndexerItem() { FullPath = query, FileName = Path.GetFileName(query) };
|
||||
var listItemForUs = new IndexerListItem(item, IncludeBrowseCommand.AsDefault);
|
||||
Command = listItemForUs.Command;
|
||||
@@ -43,12 +64,65 @@ internal sealed partial class FallbackOpenFileItem : FallbackCommandItem
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Title = string.Empty;
|
||||
Subtitle = string.Empty;
|
||||
Command = new NoOpCommand();
|
||||
_queryCookie++;
|
||||
|
||||
try
|
||||
{
|
||||
_searchEngine.Query(query, _queryCookie);
|
||||
var results = _searchEngine.FetchItems(0, 20, _queryCookie, out var _);
|
||||
|
||||
if (results.Count == 0 || ((results[0] as IndexerListItem) == null))
|
||||
{
|
||||
// Exit 2: We searched for the file, and found nothing. Oh well.
|
||||
// Hide ourselves.
|
||||
Title = string.Empty;
|
||||
Subtitle = string.Empty;
|
||||
Command = new NoOpCommand();
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.Count == 1)
|
||||
{
|
||||
// Exit 3: We searched for the file, and found exactly one thing. Awesome!
|
||||
// Return it.
|
||||
Title = results[0].Title;
|
||||
Subtitle = results[0].Subtitle;
|
||||
Icon = results[0].Icon;
|
||||
Command = results[0].Command;
|
||||
MoreCommands = results[0].MoreCommands;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Exit 4: We found more than one result. Make our command take
|
||||
// us to the file search page, prepopulated with this search.
|
||||
var indexerPage = new IndexerPage(query, _searchEngine, _queryCookie, results);
|
||||
Title = string.Format(CultureInfo.CurrentCulture, fallbackItemSearchPageTitleCompositeFormat, query);
|
||||
Icon = Icons.FileExplorer;
|
||||
Subtitle = Resources.Indexer_Subtitle;
|
||||
Command = indexerPage;
|
||||
|
||||
return;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Title = string.Empty;
|
||||
Subtitle = string.Empty;
|
||||
Icon = null;
|
||||
Command = new NoOpCommand();
|
||||
MoreCommands = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_searchEngine.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<PropertyGroup>
|
||||
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.CmdPal.Ext.Indexer</RootNamespace>
|
||||
|
||||
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutputPath>
|
||||
|
||||
@@ -4,25 +4,22 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Data;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Indexer;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Properties;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer;
|
||||
|
||||
internal sealed partial class IndexerPage : DynamicListPage, IDisposable
|
||||
{
|
||||
private readonly List<IListItem> _indexerListItems = [];
|
||||
private readonly SearchEngine _searchEngine;
|
||||
private readonly bool disposeSearchEngine = true;
|
||||
|
||||
private SearchQuery _searchQuery = new();
|
||||
private uint _queryCookie;
|
||||
|
||||
private uint _queryCookie = 10;
|
||||
private string initialQuery = string.Empty;
|
||||
|
||||
public IndexerPage()
|
||||
{
|
||||
@@ -30,16 +27,31 @@ internal sealed partial class IndexerPage : DynamicListPage, IDisposable
|
||||
Icon = Icons.FileExplorer;
|
||||
Name = Resources.Indexer_Title;
|
||||
PlaceholderText = Resources.Indexer_PlaceholderText;
|
||||
_searchEngine = new();
|
||||
_queryCookie = 10;
|
||||
}
|
||||
|
||||
public IndexerPage(string query, SearchEngine searchEngine, uint queryCookie, IList<IListItem> firstPageData)
|
||||
{
|
||||
Icon = Icons.FileExplorer;
|
||||
Name = Resources.Indexer_Title;
|
||||
_searchEngine = searchEngine;
|
||||
_queryCookie = queryCookie;
|
||||
_indexerListItems.AddRange(firstPageData);
|
||||
initialQuery = query;
|
||||
SearchText = query;
|
||||
disposeSearchEngine = false;
|
||||
}
|
||||
|
||||
public override void UpdateSearchText(string oldSearch, string newSearch)
|
||||
{
|
||||
if (oldSearch != newSearch)
|
||||
if (oldSearch != newSearch && newSearch != initialQuery)
|
||||
{
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
Query(newSearch);
|
||||
LoadMore();
|
||||
initialQuery = string.Empty;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -49,7 +61,9 @@ internal sealed partial class IndexerPage : DynamicListPage, IDisposable
|
||||
public override void LoadMore()
|
||||
{
|
||||
IsLoading = true;
|
||||
FetchItems(20);
|
||||
var results = _searchEngine.FetchItems(_indexerListItems.Count, 20, _queryCookie, out var hasMore);
|
||||
_indexerListItems.AddRange(results);
|
||||
HasMoreItems = hasMore;
|
||||
IsLoading = false;
|
||||
RaiseItemsChanged(_indexerListItems.Count);
|
||||
}
|
||||
@@ -58,70 +72,16 @@ internal sealed partial class IndexerPage : DynamicListPage, IDisposable
|
||||
{
|
||||
++_queryCookie;
|
||||
_indexerListItems.Clear();
|
||||
_searchQuery.SearchResults.Clear();
|
||||
_searchQuery.CancelOutstandingQueries();
|
||||
|
||||
if (query == string.Empty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Stopwatch stopwatch = new();
|
||||
stopwatch.Start();
|
||||
|
||||
_searchQuery.Execute(query, _queryCookie);
|
||||
|
||||
stopwatch.Stop();
|
||||
Logger.LogDebug($"Query time: {stopwatch.ElapsedMilliseconds} ms, query: \"{query}\"");
|
||||
}
|
||||
|
||||
private void FetchItems(int limit)
|
||||
{
|
||||
if (_searchQuery != null)
|
||||
{
|
||||
var cookie = _searchQuery.Cookie;
|
||||
if (cookie == _queryCookie)
|
||||
{
|
||||
var index = 0;
|
||||
SearchResult result;
|
||||
|
||||
var hasMoreItems = _searchQuery.FetchRows(_indexerListItems.Count, limit);
|
||||
|
||||
while (!_searchQuery.SearchResults.IsEmpty && _searchQuery.SearchResults.TryDequeue(out result) && ++index <= limit)
|
||||
{
|
||||
IconInfo icon = null;
|
||||
try
|
||||
{
|
||||
var stream = ThumbnailHelper.GetThumbnail(result.LaunchUri).Result;
|
||||
if (stream != null)
|
||||
{
|
||||
var data = new IconData(RandomAccessStreamReference.CreateFromStream(stream));
|
||||
icon = new IconInfo(data, data);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to get the icon.", ex);
|
||||
}
|
||||
|
||||
_indexerListItems.Add(new IndexerListItem(new IndexerItem
|
||||
{
|
||||
FileName = result.ItemDisplayName,
|
||||
FullPath = result.LaunchUri,
|
||||
})
|
||||
{
|
||||
Icon = icon,
|
||||
});
|
||||
}
|
||||
|
||||
HasMoreItems = hasMoreItems;
|
||||
}
|
||||
}
|
||||
_searchEngine.Query(query, _queryCookie);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_searchQuery = null;
|
||||
GC.SuppressFinalize(this);
|
||||
if (disposeSearchEngine)
|
||||
{
|
||||
_searchEngine.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +123,15 @@ namespace Microsoft.CmdPal.Ext.Indexer.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Search for "{0}" in files.
|
||||
/// </summary>
|
||||
internal static string Indexer_fallback_searchPage_title {
|
||||
get {
|
||||
return ResourceManager.GetString("Indexer_fallback_searchPage_title", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to This file doesn't exist.
|
||||
/// </summary>
|
||||
@@ -168,6 +177,42 @@ namespace Microsoft.CmdPal.Ext.Indexer.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Always on.
|
||||
/// </summary>
|
||||
internal static string Indexer_Settings_FallbackCommand_AlwaysOn {
|
||||
get {
|
||||
return ResourceManager.GetString("Indexer_Settings_FallbackCommand_AlwaysOn", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Only when file path exist.
|
||||
/// </summary>
|
||||
internal static string Indexer_Settings_FallbackCommand_FilePathExist {
|
||||
get {
|
||||
return ResourceManager.GetString("Indexer_Settings_FallbackCommand_FilePathExist", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Shows file search results on the top-level search results.
|
||||
/// </summary>
|
||||
internal static string Indexer_Settings_FallbackCommand_Mode {
|
||||
get {
|
||||
return ResourceManager.GetString("Indexer_Settings_FallbackCommand_Mode", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Always off.
|
||||
/// </summary>
|
||||
internal static string Indexer_Settings_FallbackCommand_Off {
|
||||
get {
|
||||
return ResourceManager.GetString("Indexer_Settings_FallbackCommand_Off", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Search files on this device.
|
||||
/// </summary>
|
||||
|
||||
@@ -156,10 +156,25 @@
|
||||
<data name="Indexer_PlaceholderText" xml:space="preserve">
|
||||
<value>Search for files and folders...</value>
|
||||
</data>
|
||||
<data name="Indexer_Settings_FallbackCommand_AlwaysOn" xml:space="preserve">
|
||||
<value>Always on</value>
|
||||
</data>
|
||||
<data name="Indexer_Settings_FallbackCommand_Mode" xml:space="preserve">
|
||||
<value>Shows file search results on the top-level search results</value>
|
||||
</data>
|
||||
<data name="Indexer_Settings_FallbackCommand_Off" xml:space="preserve">
|
||||
<value>Always off</value>
|
||||
</data>
|
||||
<data name="Indexer_Settings_FallbackCommand_FilePathExist" xml:space="preserve">
|
||||
<value>Only when file path exist</value>
|
||||
</data>
|
||||
<data name="Indexer_Subtitle" xml:space="preserve">
|
||||
<value>Search files on this device</value>
|
||||
</data>
|
||||
<data name="Indexer_Title" xml:space="preserve">
|
||||
<value>Search files</value>
|
||||
</data>
|
||||
<data name="Indexer_fallback_searchPage_title" xml:space="preserve">
|
||||
<value>Search for "{0}" in files</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,95 @@
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Data;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Indexer;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer;
|
||||
|
||||
public sealed partial class SearchEngine : IDisposable
|
||||
{
|
||||
private SearchQuery _searchQuery = new();
|
||||
|
||||
public void Query(string query, uint queryCookie)
|
||||
{
|
||||
// _indexerListItems.Clear();
|
||||
_searchQuery.SearchResults.Clear();
|
||||
_searchQuery.CancelOutstandingQueries();
|
||||
|
||||
if (query == string.Empty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Stopwatch stopwatch = new();
|
||||
stopwatch.Start();
|
||||
|
||||
_searchQuery.Execute(query, queryCookie);
|
||||
|
||||
stopwatch.Stop();
|
||||
Logger.LogDebug($"Query time: {stopwatch.ElapsedMilliseconds} ms, query: \"{query}\"");
|
||||
}
|
||||
|
||||
public IList<IListItem> FetchItems(int offset, int limit, uint queryCookie, out bool hasMore)
|
||||
{
|
||||
hasMore = false;
|
||||
var results = new List<IListItem>();
|
||||
if (_searchQuery != null)
|
||||
{
|
||||
var cookie = _searchQuery.Cookie;
|
||||
if (cookie == queryCookie)
|
||||
{
|
||||
var index = 0;
|
||||
SearchResult result;
|
||||
|
||||
// var hasMoreItems = _searchQuery.FetchRows(_indexerListItems.Count, limit);
|
||||
var hasMoreItems = _searchQuery.FetchRows(offset, limit);
|
||||
|
||||
while (!_searchQuery.SearchResults.IsEmpty && _searchQuery.SearchResults.TryDequeue(out result) && ++index <= limit)
|
||||
{
|
||||
IconInfo icon = null;
|
||||
try
|
||||
{
|
||||
var stream = ThumbnailHelper.GetThumbnail(result.LaunchUri).Result;
|
||||
if (stream != null)
|
||||
{
|
||||
var data = new IconData(RandomAccessStreamReference.CreateFromStream(stream));
|
||||
icon = new IconInfo(data, data);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Failed to get the icon.", ex);
|
||||
}
|
||||
|
||||
results.Add(new IndexerListItem(new IndexerItem
|
||||
{
|
||||
FileName = result.ItemDisplayName,
|
||||
FullPath = result.LaunchUri,
|
||||
})
|
||||
{
|
||||
Icon = icon,
|
||||
});
|
||||
}
|
||||
|
||||
hasMore = hasMoreItems;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_searchQuery = null;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ internal sealed partial class FallbackSystemCommandItem : FallbackCommandItem
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
Command = null;
|
||||
Title = string.Empty;
|
||||
Subtitle = string.Empty;
|
||||
return;
|
||||
@@ -58,6 +59,7 @@ internal sealed partial class FallbackSystemCommandItem : FallbackCommandItem
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
Command = null;
|
||||
Title = string.Empty;
|
||||
Subtitle = string.Empty;
|
||||
|
||||
|
||||
@@ -311,14 +311,14 @@ internal sealed class NetworkConnectionProperties
|
||||
{
|
||||
switch (property)
|
||||
{
|
||||
case string:
|
||||
return string.IsNullOrWhiteSpace(property) ? string.Empty : $"\n\n{title}{property}";
|
||||
case string str:
|
||||
return string.IsNullOrWhiteSpace(str) ? string.Empty : $"\n\n{title}{str}";
|
||||
case List<string> listString:
|
||||
return listString.Count == 0 ? string.Empty : $"\n\n{title}{string.Join("\n\n* ", property)}";
|
||||
return listString.Count == 0 ? string.Empty : $"\n\n{title}{string.Join("\n\n* ", listString)}";
|
||||
case List<IPAddress> listIP:
|
||||
return listIP.Count == 0 ? string.Empty : $"\n\n{title}{string.Join("\n\n* ", property)}";
|
||||
return listIP.Count == 0 ? string.Empty : $"\n\n{title}{string.Join("\n\n* ", listIP)}";
|
||||
case IPAddressCollection collectionIP:
|
||||
return collectionIP.Count == 0 ? string.Empty : $"\n\n{title}{string.Join("\n\n* ", property)}";
|
||||
return collectionIP.Count == 0 ? string.Empty : $"\n\n{title}{string.Join("\n\n* ", collectionIP)}";
|
||||
case null:
|
||||
return string.Empty;
|
||||
default:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
<PropertyGroup>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Microsoft.CmdPal.Ext.System</RootNamespace>
|
||||
|
||||
@@ -10,12 +10,12 @@ namespace Microsoft.CmdPal.Ext.System.Pages;
|
||||
|
||||
public sealed partial class SystemCommandPage : ListPage
|
||||
{
|
||||
private SettingsManager _settingsManager;
|
||||
private readonly SettingsManager _settingsManager;
|
||||
|
||||
public SystemCommandPage(SettingsManager settingsManager)
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_ext_system_page_name;
|
||||
Name = Resources.Microsoft_plugin_ext_system_page_name;
|
||||
Title = Resources.Microsoft_plugin_ext_system_page_title;
|
||||
Name = Resources.Microsoft_plugin_command_name_open;
|
||||
Icon = IconHelpers.FromRelativePath("Assets\\SystemCommand.svg");
|
||||
_settingsManager = settingsManager;
|
||||
ShowDetails = true;
|
||||
|
||||
@@ -205,7 +205,7 @@ namespace Microsoft.CmdPal.Ext.System {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Windows System Command.
|
||||
/// Looks up a localized string similar to System Commands.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_ext_system_page_name {
|
||||
get {
|
||||
@@ -213,6 +213,15 @@ namespace Microsoft.CmdPal.Ext.System {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Windows System Commands.
|
||||
/// </summary>
|
||||
public static string Microsoft_plugin_ext_system_page_title {
|
||||
get {
|
||||
return ResourceManager.GetString("Microsoft_plugin_ext_system_page_title", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Adapter name.
|
||||
/// </summary>
|
||||
|
||||
@@ -160,8 +160,11 @@
|
||||
<data name="Microsoft_plugin_ext_settings_hideDisconnectedNetworkInfo" xml:space="preserve">
|
||||
<value>Hide disconnected network info</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_ext_system_page_title" xml:space="preserve">
|
||||
<value>Windows System Commands</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_ext_system_page_name" xml:space="preserve">
|
||||
<value>Windows System Command</value>
|
||||
<value>System Commands</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_sys_AdapterName" xml:space="preserve">
|
||||
<value>Adapter name</value>
|
||||
|
||||
@@ -14,7 +14,7 @@ public partial class SystemCommandExtensionProvider : CommandProvider
|
||||
private readonly ICommandItem[] _commands;
|
||||
private static readonly SettingsManager _settingsManager = new();
|
||||
public static readonly SystemCommandPage Page = new(_settingsManager);
|
||||
private readonly FallbackSystemCommandItem _fallbackFileItem = new(_settingsManager);
|
||||
private readonly FallbackSystemCommandItem _fallbackSystemItem = new(_settingsManager);
|
||||
|
||||
public SystemCommandExtensionProvider()
|
||||
{
|
||||
@@ -23,7 +23,7 @@ public partial class SystemCommandExtensionProvider : CommandProvider
|
||||
_commands = [
|
||||
new CommandItem(Page)
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_ext_system_page_name,
|
||||
Title = Resources.Microsoft_plugin_ext_system_page_title,
|
||||
Icon = Page.Icon,
|
||||
MoreCommands = [new CommandContextItem(_settingsManager.Settings.SettingsPage)],
|
||||
},
|
||||
@@ -38,5 +38,5 @@ public partial class SystemCommandExtensionProvider : CommandProvider
|
||||
return _commands;
|
||||
}
|
||||
|
||||
public override IFallbackCommandItem[] FallbackCommands() => [_fallbackFileItem];
|
||||
public override IFallbackCommandItem[] FallbackCommands() => [_fallbackSystemItem];
|
||||
}
|
||||
|
||||
@@ -13,5 +13,5 @@ public class HistoryItem(string searchString, DateTime timestamp)
|
||||
|
||||
public DateTime Timestamp { get; private set; } = timestamp;
|
||||
|
||||
public string ToJson() => JsonSerializer.Serialize(this);
|
||||
public string ToJson() => JsonSerializer.Serialize(this, WebSearchJsonSerializationContext.Default.HistoryItem);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class SettingsManager : JsonSettingsManager
|
||||
if (File.Exists(_historyPath))
|
||||
{
|
||||
var existingContent = File.ReadAllText(_historyPath);
|
||||
historyItems = JsonSerializer.Deserialize<List<HistoryItem>>(existingContent) ?? [];
|
||||
historyItems = JsonSerializer.Deserialize<List<HistoryItem>>(existingContent, WebSearchJsonSerializationContext.Default.ListHistoryItem) ?? [];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -101,7 +101,7 @@ public class SettingsManager : JsonSettingsManager
|
||||
}
|
||||
|
||||
// Serialize the updated list back to JSON and save it
|
||||
var historyJson = JsonSerializer.Serialize(historyItems);
|
||||
var historyJson = JsonSerializer.Serialize(historyItems, WebSearchJsonSerializationContext.Default.ListHistoryItem);
|
||||
File.WriteAllText(_historyPath, historyJson);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -121,7 +121,7 @@ public class SettingsManager : JsonSettingsManager
|
||||
|
||||
// Read and deserialize JSON into a list of HistoryItem objects
|
||||
var fileContent = File.ReadAllText(_historyPath);
|
||||
var historyItems = JsonSerializer.Deserialize<List<HistoryItem>>(fileContent) ?? [];
|
||||
var historyItems = JsonSerializer.Deserialize<List<HistoryItem>>(fileContent, WebSearchJsonSerializationContext.Default.ListHistoryItem) ?? [];
|
||||
|
||||
// Convert each HistoryItem to a ListItem
|
||||
var listItems = new List<ListItem>();
|
||||
@@ -198,7 +198,7 @@ public class SettingsManager : JsonSettingsManager
|
||||
if (File.Exists(_historyPath))
|
||||
{
|
||||
var existingContent = File.ReadAllText(_historyPath);
|
||||
var historyItems = JsonSerializer.Deserialize<List<HistoryItem>>(existingContent) ?? [];
|
||||
var historyItems = JsonSerializer.Deserialize<List<HistoryItem>>(existingContent, WebSearchJsonSerializationContext.Default.ListHistoryItem) ?? [];
|
||||
|
||||
// Check if trimming is needed
|
||||
if (historyItems.Count > maxHistoryItems)
|
||||
@@ -207,7 +207,7 @@ public class SettingsManager : JsonSettingsManager
|
||||
historyItems = historyItems.Skip(historyItems.Count - maxHistoryItems).ToList();
|
||||
|
||||
// Save the trimmed history back to the file
|
||||
var trimmedHistoryJson = JsonSerializer.Serialize(historyItems);
|
||||
var trimmedHistoryJson = JsonSerializer.Serialize(historyItems, WebSearchJsonSerializationContext.Default.ListHistoryItem);
|
||||
File.WriteAllText(_historyPath, trimmedHistoryJson);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.CmdPal.Ext.WebSearch.Helpers;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WebSearch;
|
||||
|
||||
[JsonSerializable(typeof(float))]
|
||||
[JsonSerializable(typeof(int))]
|
||||
[JsonSerializable(typeof(string))]
|
||||
[JsonSerializable(typeof(bool))]
|
||||
[JsonSerializable(typeof(HistoryItem))]
|
||||
[JsonSerializable(typeof(List<HistoryItem>))]
|
||||
[JsonSourceGenerationOptions(UseStringEnumConverter = true, WriteIndented = true, IncludeFields = true, PropertyNameCaseInsensitive = true, AllowTrailingCommas = true)]
|
||||
internal sealed partial class WebSearchJsonSerializationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.CmdPal.Ext.WebSearch</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WindowsSettings.Helpers;
|
||||
|
||||
@@ -21,6 +19,8 @@ internal static class JsonSettingsListHelper
|
||||
/// </summary>
|
||||
private const string _settingsFile = "WindowsSettings.json";
|
||||
|
||||
private const string _extTypeNamespace = "Microsoft.CmdPal.Ext.WindowsSettings";
|
||||
|
||||
private static readonly JsonSerializerOptions _serializerOptions = new()
|
||||
{
|
||||
};
|
||||
@@ -32,7 +32,6 @@ internal static class JsonSettingsListHelper
|
||||
internal static Classes.WindowsSettings ReadAllPossibleSettings()
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var type = assembly.GetTypes().FirstOrDefault(x => x.Name == nameof(WindowsSettingsCommandsProvider));
|
||||
|
||||
#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
Classes.WindowsSettings? settings = null;
|
||||
@@ -40,7 +39,7 @@ internal static class JsonSettingsListHelper
|
||||
|
||||
try
|
||||
{
|
||||
var resourceName = $"{type?.Namespace}.{_settingsFile}";
|
||||
var resourceName = $"{_extTypeNamespace}.{_settingsFile}";
|
||||
using var stream = assembly.GetManifestResourceStream(resourceName);
|
||||
if (stream is null)
|
||||
{
|
||||
@@ -48,12 +47,13 @@ internal static class JsonSettingsListHelper
|
||||
}
|
||||
|
||||
var options = _serializerOptions;
|
||||
options.Converters.Add(new JsonStringEnumConverter());
|
||||
|
||||
// Why we need it? I don't see any enum usage in WindowsSettings
|
||||
// options.Converters.Add(new JsonStringEnumConverter());
|
||||
using var reader = new StreamReader(stream);
|
||||
var text = reader.ReadToEnd();
|
||||
|
||||
settings = JsonSerializer.Deserialize<Classes.WindowsSettings>(text, options);
|
||||
settings = JsonSerializer.Deserialize(text, WindowsSettingsJsonSerializationContext.Default.WindowsSettings);
|
||||
}
|
||||
#pragma warning disable CS0168
|
||||
catch (Exception exception)
|
||||
|
||||
@@ -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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WindowsSettings;
|
||||
|
||||
[JsonSerializable(typeof(float))]
|
||||
[JsonSerializable(typeof(int))]
|
||||
[JsonSerializable(typeof(string))]
|
||||
[JsonSerializable(typeof(bool))]
|
||||
[JsonSerializable(typeof(Classes.WindowsSettings))]
|
||||
[JsonSourceGenerationOptions(UseStringEnumConverter = true, WriteIndented = true, IncludeFields = true, PropertyNameCaseInsensitive = true, AllowTrailingCommas = true)]
|
||||
internal sealed partial class WindowsSettingsJsonSerializationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.CmdPal.Ext.WindowsSettings</RootNamespace>
|
||||
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutputPath>
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
[JsonSerializable(typeof(List<ChoiceSetSetting>))]
|
||||
[JsonSerializable(typeof(Dictionary<string, object>), TypeInfoPropertyName = "Dictionary")]
|
||||
[JsonSourceGenerationOptions(UseStringEnumConverter = true, WriteIndented = true)]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Just used here")]
|
||||
internal partial class JsonSerializationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
@@ -282,11 +282,11 @@ namespace PowerLauncher.ViewModel
|
||||
|
||||
if (options.SearchQueryTuningEnabled)
|
||||
{
|
||||
sorted = Results.OrderByDescending(x => (x.Result.Metadata.WeightBoost + x.Result.Score + (x.Result.SelectedCount * options.SearchClickedItemWeight))).ToList();
|
||||
sorted = Results.OrderByDescending(x => x.Result.GetSortOrderScore(options.SearchClickedItemWeight)).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
sorted = Results.OrderByDescending(x => (x.Result.Metadata.WeightBoost + x.Result.Score + (x.Result.SelectedCount * 5))).ToList();
|
||||
sorted = Results.OrderByDescending(x => x.Result.GetSortOrderScore(5)).ToList();
|
||||
}
|
||||
|
||||
// remove history items in they are in the list as non-history items
|
||||
|
||||
@@ -187,5 +187,20 @@ namespace Wox.Plugin
|
||||
/// Gets plugin ID that generated this result
|
||||
/// </summary>
|
||||
public string PluginID { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether usage based sorting should be applied to this result.
|
||||
/// </summary>
|
||||
public bool DisableUsageBasedScoring { get; set; }
|
||||
|
||||
public int GetSortOrderScore(int selectedItemMultiplier)
|
||||
{
|
||||
if (DisableUsageBasedScoring)
|
||||
{
|
||||
return Metadata.WeightBoost + Score;
|
||||
}
|
||||
|
||||
return Metadata.WeightBoost + Score + (SelectedCount * selectedItemMultiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.Dotnet.FuzzTest.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
|
||||
<Platforms>x64;ARM64</Platforms>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Platforms>x64;ARM64</Platforms>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -152,8 +152,4 @@ function Export-CertificateFiles {
|
||||
if (-not $CerPath -and -not $PfxPath) {
|
||||
Write-Warning "No output path specified. Nothing was exported."
|
||||
}
|
||||
}
|
||||
|
||||
$cert = EnsureCertificate
|
||||
$pswd = ConvertTo-SecureString -String "MySecurePassword123!" -AsPlainText -Force
|
||||
Export-CertificateFiles -Certificate $cert -CerPath "$env:TEMP\cert.cer" -PfxPath "$env:TEMP\cert.pfx" -PfxPassword $pswd
|
||||
}
|
||||
Reference in New Issue
Block a user