mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 02:36:19 +02:00
Add the Command Palette module (#37908)
Windows Command Palette ("CmdPal") is the next iteration of PowerToys Run. With extensibility at its core, the Command Palette is your one-stop launcher to start _anything_.
By default, CmdPal is bound to <kbd>Win+Alt+Space</kbd>.


----
This brings the current preview version of CmdPal into the upstream PowerToys repo. There are still lots of bugs to work out, but it's reached the state we're ready to start sharing it with the world. From here, we can further collaborate with the community on the features that are important, and ensuring that we've got a most robust API to enable developers to build whatever extensions they want.
Most of the built-in PT Run modules have already been ported to CmdPal's extension API. Those include:
* Installed apps
* Shell commands
* File search (powered by the indexer)
* Windows Registry search
* Web search
* Windows Terminal Profiles
* Windows Services
* Windows settings
There are a couple new extensions built-in
* You can now search for packages on `winget` and install them right from the palette. This also powers searching for extensions for the palette
* The calculator has an entirely new implementation. This is currently less feature complete than the original PT Run one - we're looking forward to updating it to be more complete for future ingestion in Windows
* "Bookmarks" allow you to save shortcuts to files, folders, and webpages as top-level commands in the palette.
We've got a bunch of other samples too, in this repo and elsewhere
### PowerToys specific notes
CmdPal will eventually graduate out of PowerToys to live as its own application, which is why it's implemented just a little differently than most other modules. Enabling CmdPal will install its `msix` package.
The CI was minorly changed to support CmdPal version numbers independent of PowerToys itself. It doesn't make sense for us to start CmdPal at v0.90, and in the future, we want to be able to rev CmdPal independently of PT itself.
Closes #3200, closes #3600, closes #7770, closes #34273, closes #36471, closes #20976, closes #14495
-----
TODOs et al
**Blocking:**
- [ ] Images and descriptions in Settings and OOBE need to be properly defined, as mentioned before
- [ ] Niels is on it
- [x] Doesn't start properly from PowerToys unless the fix PR is merged.
- https://github.com/zadjii-msft/PowerToys/pull/556 merged
- [x] I seem to lose focus a lot when I press on some limits, like between the search bar and the results.
- This is https://github.com/zadjii-msft/PowerToys/issues/427
- [x] Turned off an extension like Calculator and it was still working.
- Need to get rid of that toggle, it doesn't do anything currently
- [x] `ListViewModel.<FetchItems>` crash
- Pretty confident that was fixed in https://github.com/zadjii-msft/PowerToys/pull/553
**Not blocking / improvements:**
- Show the shortcut through settings, as mentioned before, or create a button that would open CmdPalette settings.
- When PowerToys starts, CmdPalette is always shown if enabled. That's weird when just starting PowerToys/ logging in to the computer with PowerToys auto-start activated. I think this should at least be a setting.
- Needing to double press a result for it to do the default action seems quirky. If one is already selected, I think just pressing should be enough for it to do the action.
- This is currently a setting, though we're thinking of changing the setting even more: https://github.com/zadjii-msft/PowerToys/issues/392
- There's no URI extension. Was surprised when typing a URL that it only proposed a web search.
- [x] There's no System commands extension. Was expecting to be able to quickly restart the computer by typing restart but it wasn't there.
- This is in PR https://github.com/zadjii-msft/PowerToys/pull/452
---------
Co-authored-by: joadoumie <98557455+joadoumie@users.noreply.github.com>
Co-authored-by: Jordi Adoumie <jordiadoumie@microsoft.com>
Co-authored-by: Mike Griese <zadjii@gmail.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Michael Hawker <24302614+michael-hawker@users.noreply.github.com>
Co-authored-by: Stefan Markovic <57057282+stefansjfw@users.noreply.github.com>
Co-authored-by: Seraphima <zykovas91@gmail.com>
Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
Co-authored-by: Kristen Schau <47155823+krschau@users.noreply.github.com>
Co-authored-by: Eric Johnson <ericjohnson327@gmail.com>
Co-authored-by: Ethan Fang <ethanfang@microsoft.com>
Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
This commit is contained in:
108
src/modules/cmdpal/Microsoft.Terminal.UI/Converters.cpp
Normal file
108
src/modules/cmdpal/Microsoft.Terminal.UI/Converters.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
#include "pch.h"
|
||||
#include "Converters.h"
|
||||
#include "Converters.g.cpp"
|
||||
|
||||
#pragma warning(disable : 26497) // We will make these functions constexpr, as they are part of an ABI boundary.
|
||||
#pragma warning(disable : 26440) // The function ... can be declared as noexcept.
|
||||
|
||||
namespace winrt::Microsoft::Terminal::UI::implementation
|
||||
{
|
||||
// Booleans
|
||||
bool Converters::InvertBoolean(bool value)
|
||||
{
|
||||
return !value;
|
||||
}
|
||||
|
||||
// winrt::Windows::UI::Xaml::Visibility Converters::InvertedBooleanToVisibility(bool value)
|
||||
// {
|
||||
// return value ? winrt::Windows::UI::Xaml::Visibility::Collapsed : winrt::Windows::UI::Xaml::Visibility::Visible;
|
||||
// }
|
||||
|
||||
// Numbers
|
||||
double Converters::PercentageToPercentageValue(double value)
|
||||
{
|
||||
return value * 100.0;
|
||||
}
|
||||
|
||||
double Converters::PercentageValueToPercentage(double value)
|
||||
{
|
||||
return value / 100.0;
|
||||
}
|
||||
|
||||
//winrt::hstring Converters::PercentageToPercentageString(double value)
|
||||
//{
|
||||
// return winrt::hstring{ fmt::format(FMT_COMPILE(L"{:.0f}%"), value * 100.0) };
|
||||
//}
|
||||
|
||||
// Strings
|
||||
bool Converters::StringsAreNotEqual(const winrt::hstring& expected, const winrt::hstring& actual)
|
||||
{
|
||||
return expected != actual;
|
||||
}
|
||||
|
||||
bool Converters::StringNotEmpty(const winrt::hstring& value)
|
||||
{
|
||||
return !value.empty();
|
||||
}
|
||||
|
||||
// winrt::Windows::UI::Xaml::Visibility Converters::StringNotEmptyToVisibility(const winrt::hstring& value)
|
||||
// {
|
||||
// return value.empty() ? winrt::Windows::UI::Xaml::Visibility::Collapsed : winrt::Windows::UI::Xaml::Visibility::Visible;
|
||||
// }
|
||||
|
||||
winrt::hstring Converters::StringOrEmptyIfPlaceholder(const winrt::hstring& placeholder, const winrt::hstring& value)
|
||||
{
|
||||
return placeholder == value ? L"" : value;
|
||||
}
|
||||
|
||||
// Misc
|
||||
// winrt::Windows::UI::Text::FontWeight Converters::DoubleToFontWeight(double value)
|
||||
// {
|
||||
// return winrt::Windows::UI::Text::FontWeight{ base::ClampedNumeric<uint16_t>(value) };
|
||||
// }
|
||||
|
||||
//winrt::Windows::UI::Xaml::Media::SolidColorBrush Converters::ColorToBrush(const winrt::Windows::UI::Color color)
|
||||
//{
|
||||
// return Windows::UI::Xaml::Media::SolidColorBrush(color);
|
||||
//}
|
||||
|
||||
// double Converters::FontWeightToDouble(const winrt::Windows::UI::Text::FontWeight fontWeight)
|
||||
// {
|
||||
// return fontWeight.Weight;
|
||||
// }
|
||||
|
||||
// double Converters::MaxValueFromPaddingString(const winrt::hstring& paddingString)
|
||||
// {
|
||||
// std::wstring_view remaining{ paddingString };
|
||||
// double maxVal = 0;
|
||||
|
||||
// // Get padding values till we run out of delimiter separated values in the stream
|
||||
// // Non-numeral values detected will default to 0
|
||||
// // std::stod will throw invalid_argument exception if the input is an invalid double value
|
||||
// // std::stod will throw out_of_range exception if the input value is more than DBL_MAX
|
||||
// try
|
||||
// {
|
||||
// while (!remaining.empty())
|
||||
// {
|
||||
// const std::wstring token{ til::prefix_split(remaining, L',') };
|
||||
// // std::stod internally calls wcstod which handles whitespace prefix (which is ignored)
|
||||
// // & stops the scan when first char outside the range of radix is encountered
|
||||
// // We'll be permissive till the extent that stod function allows us to be by default
|
||||
// // Ex. a value like 100.3#535w2 will be read as 100.3, but ;df25 will fail
|
||||
// const auto curVal = std::stod(token);
|
||||
// if (curVal > maxVal)
|
||||
// {
|
||||
// maxVal = curVal;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// // If something goes wrong, even if due to a single bad padding value, we'll return default 0 padding
|
||||
// maxVal = 0;
|
||||
// LOG_CAUGHT_EXCEPTION();
|
||||
// }
|
||||
|
||||
// return maxVal;
|
||||
// }
|
||||
}
|
||||
40
src/modules/cmdpal/Microsoft.Terminal.UI/Converters.h
Normal file
40
src/modules/cmdpal/Microsoft.Terminal.UI/Converters.h
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Converters.g.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::UI::implementation
|
||||
{
|
||||
struct Converters
|
||||
{
|
||||
// Booleans
|
||||
static bool InvertBoolean(bool value);
|
||||
// static winrt::Windows::UI::Xaml::Visibility InvertedBooleanToVisibility(bool value);
|
||||
|
||||
// Numbers
|
||||
static double PercentageToPercentageValue(double value);
|
||||
static double PercentageValueToPercentage(double value);
|
||||
// static winrt::hstring PercentageToPercentageString(double value);
|
||||
|
||||
// Strings
|
||||
static bool StringsAreNotEqual(const winrt::hstring& expected, const winrt::hstring& actual);
|
||||
static bool StringNotEmpty(const winrt::hstring& value);
|
||||
// static winrt::Windows::UI::Xaml::Visibility StringNotEmptyToVisibility(const winrt::hstring& value);
|
||||
static winrt::hstring StringOrEmptyIfPlaceholder(const winrt::hstring& placeholder, const winrt::hstring& value);
|
||||
|
||||
// Misc
|
||||
// static winrt::Windows::UI::Text::FontWeight DoubleToFontWeight(double value);
|
||||
// static winrt::Windows::UI::Xaml::Media::SolidColorBrush ColorToBrush(winrt::Windows::UI::Color color);
|
||||
// static double FontWeightToDouble(winrt::Windows::UI::Text::FontWeight fontWeight);
|
||||
// static double MaxValueFromPaddingString(const winrt::hstring& paddingString);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::UI::factory_implementation
|
||||
{
|
||||
struct Converters : ConvertersT<Converters, implementation::Converters>
|
||||
{
|
||||
};
|
||||
}
|
||||
31
src/modules/cmdpal/Microsoft.Terminal.UI/Converters.idl
Normal file
31
src/modules/cmdpal/Microsoft.Terminal.UI/Converters.idl
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Microsoft.Terminal.UI
|
||||
{
|
||||
|
||||
[bindable]
|
||||
static runtimeclass Converters
|
||||
{
|
||||
// Booleans
|
||||
static Boolean InvertBoolean(Boolean value);
|
||||
// static Windows.UI.Xaml.Visibility InvertedBooleanToVisibility(Boolean value);
|
||||
|
||||
// Numbers
|
||||
static Double PercentageToPercentageValue(Double value);
|
||||
static Double PercentageValueToPercentage(Double value);
|
||||
// static String PercentageToPercentageString(Double value);
|
||||
|
||||
// Strings
|
||||
static Boolean StringsAreNotEqual(String expected, String actual);
|
||||
static Boolean StringNotEmpty(String value);
|
||||
// static Windows.UI.Xaml.Visibility StringNotEmptyToVisibility(String value);
|
||||
static String StringOrEmptyIfPlaceholder(String placeholder, String value);
|
||||
|
||||
// Misc
|
||||
// static Windows.UI.Text.FontWeight DoubleToFontWeight(Double value);
|
||||
// static Windows.UI.Xaml.Media.SolidColorBrush ColorToBrush(Windows.UI.Color color);
|
||||
// static Double FontWeightToDouble(Windows.UI.Text.FontWeight fontWeight);
|
||||
// static Double MaxValueFromPaddingString(String paddingString);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Microsoft.Terminal.UI
|
||||
{
|
||||
[uuid("0ddf4edc-3fda-4dee-97ca-a417ee3dd510")]
|
||||
interface IDirectKeyListener {
|
||||
Boolean OnDirectKeyEvent(UInt32 vkey, UInt8 scanCode, Boolean down);
|
||||
}
|
||||
}
|
||||
386
src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.cpp
Normal file
386
src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.cpp
Normal file
@@ -0,0 +1,386 @@
|
||||
#include "pch.h"
|
||||
#include "IconPathConverter.h"
|
||||
#include "IconPathConverter.g.cpp"
|
||||
|
||||
// #include "Utils.h"
|
||||
|
||||
#include <Shlobj.h>
|
||||
#include <Shlobj_core.h>
|
||||
#include <wincodec.h>
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
namespace MUX = Microsoft::UI::Xaml;
|
||||
}
|
||||
|
||||
using namespace winrt::Windows;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
|
||||
using namespace winrt::Windows::Graphics::Imaging;
|
||||
using namespace winrt::Windows::Storage::Streams;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::UI::implementation
|
||||
{
|
||||
// These are templates that help us figure out which BitmapIconSource/FontIconSource to use for a given IconSource.
|
||||
// We have to do this because some of our code still wants to use WUX/MUX IconSources.
|
||||
#pragma region BitmapIconSource
|
||||
template<typename TIconSource>
|
||||
struct BitmapIconSource
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct BitmapIconSource<winrt::Microsoft::UI::Xaml::Controls::IconSource>
|
||||
{
|
||||
using type = winrt::Microsoft::UI::Xaml::Controls::BitmapIconSource;
|
||||
};
|
||||
|
||||
/*template<>
|
||||
struct BitmapIconSource<winrt::Windows::UI::Xaml::Controls::IconSource>
|
||||
{
|
||||
using type = winrt::Windows::UI::Xaml::Controls::BitmapIconSource;
|
||||
};*/
|
||||
#pragma endregion
|
||||
|
||||
#pragma region FontIconSource
|
||||
template<typename TIconSource>
|
||||
struct FontIconSource
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct FontIconSource<winrt::Microsoft::UI::Xaml::Controls::IconSource>
|
||||
{
|
||||
using type = winrt::Microsoft::UI::Xaml::Controls::FontIconSource;
|
||||
};
|
||||
|
||||
/*template<>
|
||||
struct FontIconSource<winrt::Windows::UI::Xaml::Controls::IconSource>
|
||||
{
|
||||
using type = winrt::Windows::UI::Xaml::Controls::FontIconSource;
|
||||
};*/
|
||||
#pragma endregion
|
||||
|
||||
#pragma region PathIconSource
|
||||
template<typename TIconSource>
|
||||
struct PathIconSource
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct PathIconSource<winrt::Microsoft::UI::Xaml::Controls::IconSource>
|
||||
{
|
||||
using type = winrt::Microsoft::UI::Xaml::Controls::PathIconSource;
|
||||
};
|
||||
#pragma endregion
|
||||
#pragma region ImageIconSource
|
||||
template<typename TIconSource>
|
||||
struct ImageIconSource
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ImageIconSource<winrt::Microsoft::UI::Xaml::Controls::IconSource>
|
||||
{
|
||||
using type = winrt::Microsoft::UI::Xaml::Controls::ImageIconSource;
|
||||
};
|
||||
#pragma endregion
|
||||
|
||||
// Method Description:
|
||||
// - Creates an IconSource for the given path. The icon returned is a colored
|
||||
// icon. If we couldn't create the icon for any reason, we return an empty
|
||||
// IconElement.
|
||||
// Template Types:
|
||||
// - <TIconSource>: The type of IconSource (MUX, WUX) to generate.
|
||||
// Arguments:
|
||||
// - path: the full, expanded path to the icon.
|
||||
// Return Value:
|
||||
// - An IconElement with its IconSource set, if possible.
|
||||
template<typename TIconSource>
|
||||
TIconSource _getColoredBitmapIcon(const winrt::hstring& path, bool monochrome)
|
||||
{
|
||||
// FontIcon uses glyphs in the private use area, whereas valid URIs only contain ASCII characters.
|
||||
// To skip throwing on Uri construction, we can quickly check if the first character is ASCII.
|
||||
if (!path.empty() && path.front() < 128)
|
||||
{
|
||||
try
|
||||
{
|
||||
winrt::Windows::Foundation::Uri iconUri{ path };
|
||||
|
||||
if (til::equals_insensitive_ascii(iconUri.Extension(), L".svg"))
|
||||
{
|
||||
typename ImageIconSource<TIconSource>::type iconSource;
|
||||
winrt::Microsoft::UI::Xaml::Media::Imaging::SvgImageSource source{ iconUri };
|
||||
iconSource.ImageSource(source);
|
||||
return iconSource;
|
||||
}
|
||||
else
|
||||
{
|
||||
typename BitmapIconSource<TIconSource>::type iconSource;
|
||||
// Make sure to set this to false, so we keep the RGB data of the
|
||||
// image. Otherwise, the icon will be white for all the
|
||||
// non-transparent pixels in the image.
|
||||
iconSource.ShowAsMonochrome(monochrome);
|
||||
iconSource.UriSource(iconUri);
|
||||
return iconSource;
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static winrt::hstring _expandIconPath(const hstring& iconPath)
|
||||
{
|
||||
if (iconPath.empty())
|
||||
{
|
||||
return iconPath;
|
||||
}
|
||||
// winrt::hstring envExpandedPath{ wil::ExpandEnvironmentStringsW<std::wstring>(iconPath.c_str()) };
|
||||
winrt::hstring envExpandedPath{ iconPath };
|
||||
return envExpandedPath;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Creates an IconSource for the given path.
|
||||
// * If the icon is a path to an image, we'll use that.
|
||||
// * If it isn't, then we'll try and use the text as a FontIcon. If the
|
||||
// character is in the range of symbols reserved for the Segoe MDL2
|
||||
// Asserts, well treat it as such. Otherwise, we'll default to a Sego
|
||||
// UI icon, so things like emoji will work.
|
||||
// * If we couldn't create the icon for any reason, we return an empty
|
||||
// IconElement.
|
||||
// Template Types:
|
||||
// - <TIconSource>: The type of IconSource (MUX, WUX) to generate.
|
||||
// Arguments:
|
||||
// - path: the unprocessed path to the icon.
|
||||
// Return Value:
|
||||
// - An IconElement with its IconSource set, if possible.
|
||||
template<typename TIconSource>
|
||||
TIconSource _getIconSource(const winrt::hstring& iconPath, bool monochrome, const int targetSize)
|
||||
{
|
||||
TIconSource iconSource{ nullptr };
|
||||
|
||||
if (iconPath.size() != 0)
|
||||
{
|
||||
const auto expandedIconPath{ _expandIconPath(iconPath) };
|
||||
iconSource = _getColoredBitmapIcon<TIconSource>(expandedIconPath, monochrome);
|
||||
|
||||
// If we fail to set the icon source using the "icon" as a path,
|
||||
// let's try it as a symbol/emoji.
|
||||
//
|
||||
// Anything longer than 2 wchar_t's _isn't_ an emoji or symbol, so
|
||||
// don't do this if it's just an invalid path.
|
||||
if (!iconSource && iconPath.size() <= 2)
|
||||
{
|
||||
try
|
||||
{
|
||||
typename FontIconSource<TIconSource>::type icon;
|
||||
const auto ch = til::at(iconPath, 0);
|
||||
|
||||
// The range of MDL2 Icons isn't explicitly defined, but
|
||||
// we're using this based off the table on:
|
||||
// https://docs.microsoft.com/en-us/windows/uwp/design/style/segoe-ui-symbol-font
|
||||
const auto isMDL2Icon = ch >= L'\uE700' && ch <= L'\uF8FF';
|
||||
if (isMDL2Icon)
|
||||
{
|
||||
icon.FontFamily(winrt::Microsoft::UI::Xaml::Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note: you _do_ need to manually set the font here.
|
||||
icon.FontFamily(winrt::Microsoft::UI::Xaml::Media::FontFamily{ L"Segoe UI" });
|
||||
}
|
||||
icon.FontSize(targetSize);
|
||||
icon.Glyph(iconPath);
|
||||
iconSource = icon;
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
}
|
||||
if (!iconSource)
|
||||
{
|
||||
// Set the default IconSource to a BitmapIconSource with a null source
|
||||
// (instead of just nullptr) because there's a really weird crash when swapping
|
||||
// data bound IconSourceElements in a ListViewTemplate (i.e. CommandPalette).
|
||||
// Swapping between nullptr IconSources and non-null IconSources causes a crash
|
||||
// to occur, but swapping between IconSources with a null source and non-null IconSources
|
||||
// work perfectly fine :shrug:.
|
||||
typename BitmapIconSource<TIconSource>::type icon;
|
||||
icon.UriSource(nullptr);
|
||||
iconSource = icon;
|
||||
}
|
||||
|
||||
return iconSource;
|
||||
}
|
||||
|
||||
// Windows::UI::Xaml::Controls::IconSource IconPathConverter::IconSourceWUX(const hstring& path)
|
||||
// {
|
||||
// // * If the icon is a path to an image, we'll use that.
|
||||
// // * If it isn't, then we'll try and use the text as a FontIcon. If the
|
||||
// // character is in the range of symbols reserved for the Segoe MDL2
|
||||
// // Asserts, well treat it as such. Otherwise, we'll default to a Segoe
|
||||
// // UI icon, so things like emoji will work.
|
||||
// return _getIconSource<Windows::UI::Xaml::Controls::IconSource>(path, false);
|
||||
// }
|
||||
|
||||
static Microsoft::UI::Xaml::Controls::IconSource _IconSourceMUX(const hstring& path, bool monochrome, const int targetSize)
|
||||
{
|
||||
return _getIconSource<Microsoft::UI::Xaml::Controls::IconSource>(path, monochrome, targetSize);
|
||||
}
|
||||
|
||||
static SoftwareBitmap _convertToSoftwareBitmap(HICON hicon,
|
||||
BitmapPixelFormat pixelFormat,
|
||||
BitmapAlphaMode alphaMode,
|
||||
IWICImagingFactory* imagingFactory)
|
||||
{
|
||||
// Load the icon into an IWICBitmap
|
||||
wil::com_ptr<IWICBitmap> iconBitmap;
|
||||
THROW_IF_FAILED(imagingFactory->CreateBitmapFromHICON(hicon, iconBitmap.put()));
|
||||
|
||||
// Put the IWICBitmap into a SoftwareBitmap. This may fail if WICBitmap's format is not supported by
|
||||
// SoftwareBitmap. CreateBitmapFromHICON always creates RGBA8 so we're ok.
|
||||
auto softwareBitmap = winrt::capture<SoftwareBitmap>(
|
||||
winrt::create_instance<ISoftwareBitmapNativeFactory>(CLSID_SoftwareBitmapNativeFactory),
|
||||
&ISoftwareBitmapNativeFactory::CreateFromWICBitmap,
|
||||
iconBitmap.get(),
|
||||
false);
|
||||
|
||||
// Convert the pixel format and alpha mode if necessary
|
||||
if (softwareBitmap.BitmapPixelFormat() != pixelFormat || softwareBitmap.BitmapAlphaMode() != alphaMode)
|
||||
{
|
||||
softwareBitmap = SoftwareBitmap::Convert(softwareBitmap, pixelFormat, alphaMode);
|
||||
}
|
||||
|
||||
return softwareBitmap;
|
||||
}
|
||||
|
||||
static SoftwareBitmap _getBitmapFromIconFileAsync(const winrt::hstring& iconPath,
|
||||
int32_t iconIndex,
|
||||
uint32_t iconSize)
|
||||
{
|
||||
wil::unique_hicon hicon;
|
||||
LOG_IF_FAILED(SHDefExtractIcon(iconPath.c_str(), iconIndex, 0, &hicon, nullptr, iconSize));
|
||||
|
||||
if (!hicon)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
wil::com_ptr<IWICImagingFactory> wicImagingFactory;
|
||||
THROW_IF_FAILED(CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&wicImagingFactory)));
|
||||
|
||||
return _convertToSoftwareBitmap(hicon.get(),
|
||||
BitmapPixelFormat::Bgra8,
|
||||
BitmapAlphaMode::Premultiplied,
|
||||
wicImagingFactory.get());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempt to get the icon index from the icon path provided
|
||||
// Arguments:
|
||||
// - iconPath: the full icon path, including the index if present
|
||||
// - iconPathWithoutIndex: the place to store the icon path, sans the index if present
|
||||
// Return Value:
|
||||
// - nullopt if the iconPath is not an exe/dll/lnk file in the first place
|
||||
// - 0 if the iconPath is an exe/dll/lnk file but does not contain an index (i.e. we default
|
||||
// to the first icon in the file)
|
||||
// - the icon index if the iconPath is an exe/dll/lnk file and contains an index
|
||||
static std::optional<int> _getIconIndex(const winrt::hstring& iconPath, std::wstring_view& iconPathWithoutIndex)
|
||||
{
|
||||
const auto pathView = std::wstring_view{ iconPath };
|
||||
// Does iconPath have a comma in it? If so, split the string on the
|
||||
// comma and look for the index and extension.
|
||||
const auto commaIndex = pathView.find(L',');
|
||||
|
||||
// split the path on the comma
|
||||
iconPathWithoutIndex = pathView.substr(0, commaIndex);
|
||||
|
||||
// It's an exe, dll, or lnk, so we need to extract the icon from the file.
|
||||
if (!til::ends_with(iconPathWithoutIndex, L".exe") &&
|
||||
!til::ends_with(iconPathWithoutIndex, L".dll") &&
|
||||
!til::ends_with(iconPathWithoutIndex, L".lnk"))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (commaIndex != std::wstring::npos)
|
||||
{
|
||||
// Convert the string iconIndex to a signed int to support negative numbers which represent an Icon's ID.
|
||||
const auto index{ til::to_int(pathView.substr(commaIndex + 1)) };
|
||||
if (index == til::to_int_error)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
return static_cast<int>(index);
|
||||
}
|
||||
|
||||
// We had a binary path, but no index. Default to 0.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static winrt::Microsoft::UI::Xaml::Media::Imaging::SoftwareBitmapSource _getImageIconSourceForBinary(std::wstring_view iconPathWithoutIndex,
|
||||
int index,
|
||||
int targetSize)
|
||||
{
|
||||
// Try:
|
||||
// * c:\Windows\System32\SHELL32.dll, 210
|
||||
// * c:\Windows\System32\notepad.exe, 0
|
||||
// * C:\Program Files\PowerShell\6-preview\pwsh.exe, 0 (this doesn't exist for me)
|
||||
// * C:\Program Files\PowerShell\7\pwsh.exe, 0
|
||||
|
||||
const auto swBitmap{ _getBitmapFromIconFileAsync(winrt::hstring{ iconPathWithoutIndex }, index, targetSize) };
|
||||
if (swBitmap == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::Microsoft::UI::Xaml::Media::Imaging::SoftwareBitmapSource bitmapSource{};
|
||||
bitmapSource.SetBitmapAsync(swBitmap);
|
||||
return bitmapSource;
|
||||
}
|
||||
|
||||
MUX::Controls::IconSource IconPathConverter::IconSourceMUX(const winrt::hstring& iconPath,
|
||||
const bool monochrome,
|
||||
const int targetSize)
|
||||
{
|
||||
std::wstring_view iconPathWithoutIndex;
|
||||
const auto indexOpt = _getIconIndex(iconPath, iconPathWithoutIndex);
|
||||
if (!indexOpt.has_value())
|
||||
{
|
||||
return _IconSourceMUX(iconPath, monochrome, targetSize);
|
||||
}
|
||||
|
||||
const auto bitmapSource = _getImageIconSourceForBinary(iconPathWithoutIndex, indexOpt.value(), targetSize);
|
||||
|
||||
MUX::Controls::ImageIconSource imageIconSource{};
|
||||
imageIconSource.ImageSource(bitmapSource);
|
||||
|
||||
return imageIconSource;
|
||||
}
|
||||
|
||||
Microsoft::UI::Xaml::Controls::IconElement IconPathConverter::IconMUX(const winrt::hstring& iconPath) {
|
||||
return IconMUX(iconPath, 24);
|
||||
}
|
||||
Microsoft::UI::Xaml::Controls::IconElement IconPathConverter::IconMUX(const winrt::hstring& iconPath, const int targetSize)
|
||||
{
|
||||
std::wstring_view iconPathWithoutIndex;
|
||||
const auto indexOpt = _getIconIndex(iconPath, iconPathWithoutIndex);
|
||||
if (!indexOpt.has_value())
|
||||
{
|
||||
auto source = IconSourceMUX(iconPath, false, targetSize);
|
||||
Microsoft::UI::Xaml::Controls::IconSourceElement icon;
|
||||
icon.IconSource(source);
|
||||
return icon;
|
||||
}
|
||||
|
||||
const auto bitmapSource = _getImageIconSourceForBinary(iconPathWithoutIndex, indexOpt.value(), targetSize);
|
||||
|
||||
winrt::Microsoft::UI::Xaml::Controls::ImageIcon icon{};
|
||||
icon.Source(bitmapSource);
|
||||
icon.Width(targetSize);
|
||||
icon.Height(targetSize);
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
22
src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.h
Normal file
22
src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "IconPathConverter.g.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::UI::implementation
|
||||
{
|
||||
struct IconPathConverter
|
||||
{
|
||||
IconPathConverter() = default;
|
||||
|
||||
//static Windows::UI::Xaml::Controls::IconElement IconWUX(const winrt::hstring& iconPath);
|
||||
//static Windows::UI::Xaml::Controls::IconSource IconSourceWUX(const winrt::hstring& iconPath);
|
||||
static Microsoft::UI::Xaml::Controls::IconSource IconSourceMUX(const winrt::hstring& iconPath, bool convertToGrayscale, const int targetSize=24);
|
||||
static Microsoft::UI::Xaml::Controls::IconElement IconMUX(const winrt::hstring& iconPath);
|
||||
static Microsoft::UI::Xaml::Controls::IconElement IconMUX(const winrt::hstring& iconPath, const int targetSize);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::UI::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(IconPathConverter);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Microsoft.Terminal.UI
|
||||
{
|
||||
static runtimeclass IconPathConverter
|
||||
{
|
||||
// static Windows.UI.Xaml.Controls.IconElement IconWUX(String path);
|
||||
// static Windows.UI.Xaml.Controls.IconSource IconSourceWUX(String path);
|
||||
static Microsoft.UI.Xaml.Controls.IconSource IconSourceMUX(String path, Boolean convertToGrayscale);
|
||||
static Microsoft.UI.Xaml.Controls.IconElement IconMUX(String path);
|
||||
static Microsoft.UI.Xaml.Controls.IconElement IconMUX(String path, Int32 targetSize);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
EXPORTS
|
||||
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
|
||||
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
|
||||
@@ -0,0 +1,213 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" 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')" />
|
||||
<PropertyGroup>
|
||||
<PathToRoot>..\..\..\..\</PathToRoot>
|
||||
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.6.250205002</WasdkNuget>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<CppWinRTOptimized>true</CppWinRTOptimized>
|
||||
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
|
||||
<CppWinRTGenerateWindowsMetadata>true</CppWinRTGenerateWindowsMetadata>
|
||||
<MinimalCoreWin>true</MinimalCoreWin>
|
||||
<ProjectGuid>{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}</ProjectGuid>
|
||||
<ProjectName>Microsoft.Terminal.UI</ProjectName>
|
||||
<RootNamespace>Microsoft.Terminal.UI</RootNamespace>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
|
||||
<AppContainerApplication>false</AppContainerApplication>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
|
||||
<WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0.22621.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.19041.0</WindowsTargetPlatformMinVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="version.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ARM64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)' == '14.0'">v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
<DesktopCompatible>true</DesktopCompatible>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<ClCompile>
|
||||
<!-- We use MultiThreadedDebug, rather than MultiThreadedDebugDLL, to avoid DLL dependencies on VCRUNTIME140d.dll and MSVCP140d.dll. -->
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
|
||||
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
|
||||
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
|
||||
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrtd.lib</IgnoreSpecificDefaultLibraries>
|
||||
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrtd.lib /profile /opt:ref /opt:icf</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<ClCompile>
|
||||
<!-- We use MultiThreaded, rather than MultiThreadedDLL, to avoid DLL dependencies on VCRUNTIME140.dll and MSVCP140.dll. -->
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT
|
||||
lib and instead linking against the Universal CRT DLL import library. This "hybrid" linking mechanism is
|
||||
supported according to the CRT maintainer. Dynamic linking against the CRT makes the binaries a bit smaller
|
||||
than they would otherwise be if the CRT, runtime, and STL were all statically linked in. -->
|
||||
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries);libucrt.lib</IgnoreSpecificDefaultLibraries>
|
||||
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrt.lib /profile /opt:ref /opt:icf</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<AdditionalOptions>%(AdditionalOptions) /bigobj /Zi</AdditionalOptions>
|
||||
<PreprocessorDefinitions>_WINRT_DLL;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
|
||||
<ControlFlowGuard>Guard</ControlFlowGuard>
|
||||
<SpectreMitigation>Spectre</SpectreMitigation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
<ModuleDefinitionFile>Microsoft.Terminal.UI.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);user32.lib;shell32.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="Converters.h">
|
||||
<DependentUpon>Converters.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IconPathConverter.h">
|
||||
<DependentUpon>IconPathConverter.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="ResourceString.h">
|
||||
<DependentUpon>ResourceString.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="init.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Converters.cpp">
|
||||
<DependentUpon>Converters.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IconPathConverter.cpp">
|
||||
<DependentUpon>IconPathConverter.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ResourceString.cpp">
|
||||
<DependentUpon>ResourceString.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="Converters.idl" />
|
||||
<Midl Include="IconPathConverter.idl" />
|
||||
<Midl Include="IDirectKeyListener.idl" />
|
||||
<Midl Include="ResourceString.idl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Microsoft.Terminal.UI.def" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(MSBuildThisFileDirectory)..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props'))" />
|
||||
<Error Condition="!Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', 'Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\version\version.vcxproj">
|
||||
<Project>{cc6e41ac-8174-4e8a-8d22-85dd7f4851df}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
17
src/modules/cmdpal/Microsoft.Terminal.UI/ResourceString.cpp
Normal file
17
src/modules/cmdpal/Microsoft.Terminal.UI/ResourceString.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "pch.h"
|
||||
// #include "ResourceString.h"
|
||||
// #include "ResourceString.g.cpp"
|
||||
|
||||
// namespace winrt::Microsoft::Terminal::UI::implementation
|
||||
// {
|
||||
// winrt::Windows::Foundation::IInspectable ResourceString::ProvideValue()
|
||||
// {
|
||||
// if (tree_.empty())
|
||||
// {
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
// auto loader{ winrt::Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView(tree_ + L"/Resources") };
|
||||
// return winrt::box_value(loader.GetString(name_));
|
||||
// }
|
||||
// }
|
||||
43
src/modules/cmdpal/Microsoft.Terminal.UI/ResourceString.h
Normal file
43
src/modules/cmdpal/Microsoft.Terminal.UI/ResourceString.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// #pragma once
|
||||
|
||||
// #include "ResourceString.g.h"
|
||||
|
||||
// namespace winrt::Microsoft::Terminal::UI::implementation
|
||||
// {
|
||||
// struct ResourceString : ResourceStringT<ResourceString>
|
||||
// {
|
||||
// ResourceString() noexcept = default;
|
||||
|
||||
// hstring Tree()
|
||||
// {
|
||||
// return tree_;
|
||||
// }
|
||||
|
||||
// void Tree(hstring const& value)
|
||||
// {
|
||||
// tree_ = value;
|
||||
// }
|
||||
|
||||
// hstring Name()
|
||||
// {
|
||||
// return name_;
|
||||
// }
|
||||
|
||||
// void Name(hstring const& value)
|
||||
// {
|
||||
// name_ = value;
|
||||
// }
|
||||
|
||||
// winrt::Windows::Foundation::IInspectable ProvideValue();
|
||||
|
||||
// private:
|
||||
// winrt::hstring tree_;
|
||||
// winrt::hstring name_;
|
||||
// };
|
||||
// }
|
||||
// namespace winrt::Microsoft::Terminal::UI::factory_implementation
|
||||
// {
|
||||
// struct ResourceString : ResourceStringT<ResourceString, implementation::ResourceString>
|
||||
// {
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Microsoft.Terminal.UI {
|
||||
// runtimeclass ResourceString : Windows.UI.Xaml.Markup.MarkupExtension
|
||||
// {
|
||||
// ResourceString();
|
||||
// String Tree { get; set; };
|
||||
// String Name { get; set; };
|
||||
// Object ProvideValue();
|
||||
// };
|
||||
}
|
||||
21
src/modules/cmdpal/Microsoft.Terminal.UI/init.cpp
Normal file
21
src/modules/cmdpal/Microsoft.Terminal.UI/init.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#pragma warning(suppress : 26440) // Not interested in changing the specification of DllMain to make it noexcept given it's an interface to the OS.
|
||||
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID /*reserved*/)
|
||||
{
|
||||
switch (reason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hInstDll);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
7
src/modules/cmdpal/Microsoft.Terminal.UI/packages.config
Normal file
7
src/modules/cmdpal/Microsoft.Terminal.UI/packages.config
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- The packages.config acts as the global version for all of the NuGet packages contained within. -->
|
||||
<packages>
|
||||
<package id="Microsoft.Web.WebView2" version="1.0.2903.40" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
|
||||
</packages>
|
||||
4
src/modules/cmdpal/Microsoft.Terminal.UI/pch.cpp
Normal file
4
src/modules/cmdpal/Microsoft.Terminal.UI/pch.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
111
src/modules/cmdpal/Microsoft.Terminal.UI/pch.h
Normal file
111
src/modules/cmdpal/Microsoft.Terminal.UI/pch.h
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// pch.h
|
||||
// Header for platform projection include files
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#define NOMCX
|
||||
#define NOHELP
|
||||
#define NOCOMM
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#define BLOCK_TIL
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Below is the contents of Terminal's LibraryIncludes.h
|
||||
|
||||
// C
|
||||
#include <climits>
|
||||
#include <cwchar>
|
||||
#include <cwctype>
|
||||
|
||||
// STL
|
||||
|
||||
// Block minwindef.h min/max macros to prevent <algorithm> conflict
|
||||
#define NOMINMAX
|
||||
// Exclude rarely-used stuff from Windows headers
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <deque>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory_resource>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <shared_mutex>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// WIL
|
||||
#include <wil/com.h>
|
||||
#include <wil/stl.h>
|
||||
#include <wil/filesystem.h>
|
||||
// Due to the use of RESOURCE_SUPPRESS_STL in result.h, we need to include resource.h first, which happens
|
||||
// implicitly through the includes above. If RESOURCE_SUPPRESS_STL is gone, the order doesn't matter anymore.
|
||||
#include <wil/result.h>
|
||||
#include <wil/nt_result_macros.h>
|
||||
|
||||
#define BASIC_FACTORY(typeName) \
|
||||
struct typeName : typeName##T<typeName, implementation::typeName> \
|
||||
{ \
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This is inexplicable, but for whatever reason, cppwinrt conflicts with the
|
||||
// SDK definition of this function, so the only fix is to undef it.
|
||||
// from WinBase.h
|
||||
// Windows::UI::Xaml::Media::Animation::IStoryboard::GetCurrentTime
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
|
||||
#include <wil/cppwinrt.h>
|
||||
|
||||
#include <winrt/Windows.ApplicationModel.Resources.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
|
||||
#include <winrt/Windows.Graphics.Imaging.h>
|
||||
#include <Windows.Graphics.Imaging.Interop.h>
|
||||
|
||||
#include <winrt/Microsoft.UI.Text.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.Controls.h>
|
||||
// #include <winrt/Microsoft.UI.Xaml.Markup.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.Media.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.Media.Imaging.h>
|
||||
|
||||
// #include <winrt/Microsoft.UI.Xaml.Controls.h>
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
//#include "til.h"
|
||||
#define _TIL_INLINEPREFIX __declspec(noinline) inline
|
||||
#include "til_string.h"
|
||||
|
||||
// #include <cppwinrt_utils.h>
|
||||
#include <wil/cppwinrt_helpers.h> // must go after the CoreDispatcher type is defined
|
||||
13
src/modules/cmdpal/Microsoft.Terminal.UI/resource.h
Normal file
13
src/modules/cmdpal/Microsoft.Terminal.UI/resource.h
Normal file
@@ -0,0 +1,13 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by AlwaysOnTopModuleInterface.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys Command Palette Terminal UI"
|
||||
#define INTERNAL_NAME "Microsoft.Terminal.UI"
|
||||
#define ORIGINAL_FILENAME "Microsoft.Terminal.UI.dll"
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
||||
560
src/modules/cmdpal/Microsoft.Terminal.UI/til_string.h
Normal file
560
src/modules/cmdpal/Microsoft.Terminal.UI/til_string.h
Normal file
@@ -0,0 +1,560 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
{
|
||||
// The at function declares that you've already sufficiently checked that your array access
|
||||
// is in range before retrieving an item inside it at an offset.
|
||||
// This is to save double/triple/quadruple testing in circumstances where you are already
|
||||
// pivoting on the length of a set and now want to pull elements out of it by offset
|
||||
// without checking again.
|
||||
// gsl::at will do the check again. As will .at(). And using [] will have a warning in audit.
|
||||
// This template is explicitly disabled if T is of type std::span, as it would interfere with
|
||||
// the overload below.
|
||||
template<typename T, typename I>
|
||||
constexpr auto at(T&& cont, const I i) noexcept -> decltype(auto)
|
||||
{
|
||||
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||
#pragma warning(suppress : 26482) // Suppress bounds.2 check for indexing with constant expressions
|
||||
#pragma warning(suppress : 26446) // Suppress bounds.4 check for subscript operator.
|
||||
#pragma warning(suppress : 26445) // Suppress lifetime check for a reference to std::span or std::string_view
|
||||
return cont[i];
|
||||
}
|
||||
|
||||
_TIL_INLINEPREFIX std::wstring visualize_control_codes(std::wstring str) noexcept
|
||||
{
|
||||
for (auto& ch : str)
|
||||
{
|
||||
if (ch < 0x20)
|
||||
{
|
||||
ch += 0x2400;
|
||||
}
|
||||
else if (ch == 0x20)
|
||||
{
|
||||
ch = 0x2423; // replace space with ␣
|
||||
}
|
||||
else if (ch == 0x7f)
|
||||
{
|
||||
ch = 0x2421; // replace del with ␡
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
// The same as the above, but it doesn't visualize BS nor SPC.
|
||||
_TIL_INLINEPREFIX std::wstring visualize_nonspace_control_codes(std::wstring str) noexcept
|
||||
{
|
||||
for (auto& ch : str)
|
||||
{
|
||||
// NOT backspace!
|
||||
if (ch < 0x20 && ch != 0x08)
|
||||
{
|
||||
ch += 0x2400;
|
||||
}
|
||||
// NOT space
|
||||
else if (ch == 0x7f)
|
||||
{
|
||||
ch = 0x2421; // replace del with ␡
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
_TIL_INLINEPREFIX std::wstring visualize_control_codes(std::wstring_view str)
|
||||
{
|
||||
return visualize_control_codes(std::wstring{ str });
|
||||
}
|
||||
|
||||
namespace details
|
||||
{
|
||||
inline constexpr uint8_t __ = 0b00;
|
||||
inline constexpr uint8_t F_ = 0b10; // stripped in clean_filename
|
||||
inline constexpr uint8_t _P = 0b01; // stripped in clean_path
|
||||
inline constexpr uint8_t FP = 0b11; // stripped in clean_filename and clean_path
|
||||
inline constexpr std::array<uint8_t, 128> pathFilter{ {
|
||||
// clang-format off
|
||||
__ /* NUL */, __ /* SOH */, __ /* STX */, __ /* ETX */, __ /* EOT */, __ /* ENQ */, __ /* ACK */, __ /* BEL */, __ /* BS */, __ /* HT */, __ /* LF */, __ /* VT */, __ /* FF */, __ /* CR */, __ /* SO */, __ /* SI */,
|
||||
__ /* DLE */, __ /* DC1 */, __ /* DC2 */, __ /* DC3 */, __ /* DC4 */, __ /* NAK */, __ /* SYN */, __ /* ETB */, __ /* CAN */, __ /* EM */, __ /* SUB */, __ /* ESC */, __ /* FS */, __ /* GS */, __ /* RS */, __ /* US */,
|
||||
__ /* SP */, __ /* ! */, FP /* " */, __ /* # */, __ /* $ */, __ /* % */, __ /* & */, __ /* ' */, __ /* ( */, __ /* ) */, FP /* * */, __ /* + */, __ /* , */, __ /* - */, __ /* . */, F_ /* / */,
|
||||
__ /* 0 */, __ /* 1 */, __ /* 2 */, __ /* 3 */, __ /* 4 */, __ /* 5 */, __ /* 6 */, __ /* 7 */, __ /* 8 */, __ /* 9 */, F_ /* : */, __ /* ; */, FP /* < */, __ /* = */, FP /* > */, FP /* ? */,
|
||||
__ /* @ */, __ /* A */, __ /* B */, __ /* C */, __ /* D */, __ /* E */, __ /* F */, __ /* G */, __ /* H */, __ /* I */, __ /* J */, __ /* K */, __ /* L */, __ /* M */, __ /* N */, __ /* O */,
|
||||
__ /* P */, __ /* Q */, __ /* R */, __ /* S */, __ /* T */, __ /* U */, __ /* V */, __ /* W */, __ /* X */, __ /* Y */, __ /* Z */, __ /* [ */, F_ /* \ */, __ /* ] */, __ /* ^ */, __ /* _ */,
|
||||
__ /* ` */, __ /* a */, __ /* b */, __ /* c */, __ /* d */, __ /* e */, __ /* f */, __ /* g */, __ /* h */, __ /* i */, __ /* j */, __ /* k */, __ /* l */, __ /* m */, __ /* n */, __ /* o */,
|
||||
__ /* p */, __ /* q */, __ /* r */, __ /* s */, __ /* t */, __ /* u */, __ /* v */, __ /* w */, __ /* x */, __ /* y */, __ /* z */, __ /* { */, FP /* | */, __ /* } */, __ /* ~ */, __ /* DEL */,
|
||||
// clang-format on
|
||||
} };
|
||||
}
|
||||
|
||||
_TIL_INLINEPREFIX std::wstring clean_filename(std::wstring str) noexcept
|
||||
{
|
||||
using namespace til::details;
|
||||
std::erase_if(str, [](auto ch) {
|
||||
// This lookup is branchless: It always checks the filter, but throws
|
||||
// away the result if ch >= 128. This is faster than using `&&` (branchy).
|
||||
return ((til::at(details::pathFilter, ch & 127) & F_) != 0) & (ch < 128);
|
||||
});
|
||||
return str;
|
||||
}
|
||||
|
||||
_TIL_INLINEPREFIX std::wstring clean_path(std::wstring str) noexcept
|
||||
{
|
||||
using namespace til::details;
|
||||
std::erase_if(str, [](auto ch) {
|
||||
return ((til::at(details::pathFilter, ch & 127) & _P) != 0) & (ch < 128);
|
||||
});
|
||||
return str;
|
||||
}
|
||||
|
||||
// is_legal_path rules on whether a path contains any non-path characters.
|
||||
// it **DOES NOT** rule on whether a path exists.
|
||||
_TIL_INLINEPREFIX constexpr bool is_legal_path(const std::wstring_view str) noexcept
|
||||
{
|
||||
using namespace til::details;
|
||||
return !std::any_of(std::begin(str), std::end(str), [](auto&& ch) {
|
||||
return ((til::at(details::pathFilter, ch & 127) & _P) != 0) & (ch < 128);
|
||||
});
|
||||
}
|
||||
|
||||
// std::string_view::starts_with support for C++17.
|
||||
template<typename T, typename Traits>
|
||||
constexpr bool starts_with(const std::basic_string_view<T, Traits>& str, const std::basic_string_view<T, Traits>& prefix) noexcept
|
||||
{
|
||||
return str.size() >= prefix.size() && __builtin_memcmp(str.data(), prefix.data(), prefix.size() * sizeof(T)) == 0;
|
||||
}
|
||||
|
||||
constexpr bool starts_with(const std::string_view& str, const std::string_view& prefix) noexcept
|
||||
{
|
||||
return starts_with<>(str, prefix);
|
||||
}
|
||||
|
||||
constexpr bool starts_with(const std::wstring_view& str, const std::wstring_view& prefix) noexcept
|
||||
{
|
||||
return starts_with<>(str, prefix);
|
||||
}
|
||||
|
||||
// std::string_view::ends_with support for C++17.
|
||||
template<typename T, typename Traits>
|
||||
constexpr bool ends_with(const std::basic_string_view<T, Traits>& str, const std::basic_string_view<T, Traits>& suffix) noexcept
|
||||
{
|
||||
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||
return str.size() >= suffix.size() && __builtin_memcmp(str.data() + (str.size() - suffix.size()), suffix.data(), suffix.size() * sizeof(T)) == 0;
|
||||
}
|
||||
|
||||
constexpr bool ends_with(const std::string_view& str, const std::string_view& prefix) noexcept
|
||||
{
|
||||
return ends_with<>(str, prefix);
|
||||
}
|
||||
|
||||
constexpr bool ends_with(const std::wstring_view& str, const std::wstring_view& prefix) noexcept
|
||||
{
|
||||
return ends_with<>(str, prefix);
|
||||
}
|
||||
|
||||
inline constexpr unsigned long to_ulong_error = ULONG_MAX;
|
||||
inline constexpr int to_int_error = INT_MAX;
|
||||
|
||||
// Just like std::wcstoul, but without annoying locales and null-terminating strings.
|
||||
// It has been fuzz-tested against clang's strtoul implementation.
|
||||
template<typename T, typename Traits>
|
||||
_TIL_INLINEPREFIX constexpr unsigned long to_ulong(const std::basic_string_view<T, Traits>& str, unsigned long base = 0) noexcept
|
||||
{
|
||||
static constexpr unsigned long maximumValue = ULONG_MAX / 16;
|
||||
|
||||
// We don't have to test ptr for null value, as we only access it under either condition:
|
||||
// * str.length() > 0, for determining the base
|
||||
// * ptr != end, when parsing the characters; if ptr is null, length will be 0 and thus end == ptr
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26429) // Symbol 'ptr' is never tested for null value, it can be marked as not_null
|
||||
#pragma warning(disable : 26481) // Don't use pointer arithmetic. Use span instead
|
||||
auto ptr = str.data();
|
||||
const auto end = ptr + str.length();
|
||||
unsigned long accumulator = 0;
|
||||
unsigned long value = ULONG_MAX;
|
||||
|
||||
if (!base)
|
||||
{
|
||||
base = 10;
|
||||
|
||||
if (str.length() > 1 && *ptr == '0')
|
||||
{
|
||||
base = 8;
|
||||
++ptr;
|
||||
|
||||
if (str.length() > 2 && (*ptr == 'x' || *ptr == 'X'))
|
||||
{
|
||||
base = 16;
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr == end)
|
||||
{
|
||||
return to_ulong_error;
|
||||
}
|
||||
|
||||
for (;; accumulator *= base)
|
||||
{
|
||||
value = ULONG_MAX;
|
||||
if (*ptr >= '0' && *ptr <= '9')
|
||||
{
|
||||
value = *ptr - '0';
|
||||
}
|
||||
else if (*ptr >= 'A' && *ptr <= 'F')
|
||||
{
|
||||
value = *ptr - 'A' + 10;
|
||||
}
|
||||
else if (*ptr >= 'a' && *ptr <= 'f')
|
||||
{
|
||||
value = *ptr - 'a' + 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
return to_ulong_error;
|
||||
}
|
||||
|
||||
accumulator += value;
|
||||
if (accumulator >= maximumValue)
|
||||
{
|
||||
return to_ulong_error;
|
||||
}
|
||||
|
||||
if (++ptr == end)
|
||||
{
|
||||
return accumulator;
|
||||
}
|
||||
}
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
constexpr unsigned long to_ulong(const std::string_view& str, unsigned long base = 0) noexcept
|
||||
{
|
||||
return to_ulong<>(str, base);
|
||||
}
|
||||
|
||||
constexpr unsigned long to_ulong(const std::wstring_view& str, unsigned long base = 0) noexcept
|
||||
{
|
||||
return to_ulong<>(str, base);
|
||||
}
|
||||
|
||||
// Implement to_int in terms of to_ulong by negating its result. to_ulong does not expect
|
||||
// to be passed signed numbers and will return an error accordingly. That error when
|
||||
// compared against -1 evaluates to true. We account for that by returning to_int_error if to_ulong
|
||||
// returns an error.
|
||||
constexpr int to_int(const std::wstring_view& str, unsigned long base = 0) noexcept
|
||||
{
|
||||
auto result = to_ulong_error;
|
||||
const auto signPosition = str.find(L"-");
|
||||
const bool hasSign = signPosition != std::wstring_view::npos;
|
||||
result = hasSign ? to_ulong(str.substr(signPosition + 1), base) : to_ulong(str, base);
|
||||
|
||||
// Check that result is valid and will fit in an int.
|
||||
if (result == to_ulong_error || (result > INT_MAX))
|
||||
{
|
||||
return to_int_error;
|
||||
}
|
||||
|
||||
return hasSign ? result * -1 : result;
|
||||
}
|
||||
|
||||
// Just like std::tolower, but without annoying locales.
|
||||
template<typename T>
|
||||
constexpr T tolower_ascii(T c)
|
||||
{
|
||||
if ((c >= 'A') && (c <= 'Z'))
|
||||
{
|
||||
c |= 0x20;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
// Just like std::toupper, but without annoying locales.
|
||||
template<typename T>
|
||||
constexpr T toupper_ascii(T c)
|
||||
{
|
||||
if ((c >= 'a') && (c <= 'z'))
|
||||
{
|
||||
c &= ~0x20;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
// Just like std::wstring_view::operator==().
|
||||
//
|
||||
// At the time of writing wmemcmp() is not an intrinsic for MSVC,
|
||||
// but the STL uses it to implement wide string comparisons.
|
||||
// This produces 3x the assembly _per_ comparison and increases
|
||||
// runtime by 2-3x for strings of medium length (16 characters)
|
||||
// and 5x or more for long strings (128 characters or more).
|
||||
// See: https://github.com/microsoft/STL/issues/2289
|
||||
template<typename T, typename Traits>
|
||||
bool equals(const std::basic_string_view<T, Traits>& lhs, const std::basic_string_view<T, Traits>& rhs) noexcept
|
||||
{
|
||||
return lhs.size() == rhs.size() && __builtin_memcmp(lhs.data(), rhs.data(), lhs.size() * sizeof(T)) == 0;
|
||||
}
|
||||
|
||||
// Just like _memicmp, but without annoying locales.
|
||||
template<typename T, typename Traits>
|
||||
bool equals_insensitive_ascii(const std::basic_string_view<T, Traits>& str1, const std::basic_string_view<T, Traits>& str2) noexcept
|
||||
{
|
||||
if (str1.size() != str2.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26429) // Symbol 'data1' is never tested for null, it can be marked as not_null
|
||||
#pragma warning(disable : 26481) // Don't use pointer arithmetic. Use span instead
|
||||
auto remaining = str1.size();
|
||||
auto data1 = str1.data();
|
||||
auto data2 = str2.data();
|
||||
for (; remaining; --remaining, ++data1, ++data2)
|
||||
{
|
||||
if (*data1 != *data2 && tolower_ascii(*data1) != tolower_ascii(*data2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool equals_insensitive_ascii(const std::string_view& str1, const std::string_view& str2) noexcept
|
||||
{
|
||||
return equals_insensitive_ascii<>(str1, str2);
|
||||
}
|
||||
|
||||
inline bool equals_insensitive_ascii(const std::wstring_view& str1, const std::wstring_view& str2) noexcept
|
||||
{
|
||||
return equals_insensitive_ascii<>(str1, str2);
|
||||
}
|
||||
|
||||
template<typename T, typename Traits>
|
||||
constexpr bool starts_with_insensitive_ascii(const std::basic_string_view<T, Traits>& str, const std::basic_string_view<T, Traits>& prefix) noexcept
|
||||
{
|
||||
return str.size() >= prefix.size() && equals_insensitive_ascii<>({ str.data(), prefix.size() }, prefix);
|
||||
}
|
||||
|
||||
constexpr bool starts_with_insensitive_ascii(const std::string_view& str, const std::string_view& prefix) noexcept
|
||||
{
|
||||
return starts_with_insensitive_ascii<>(str, prefix);
|
||||
}
|
||||
|
||||
constexpr bool starts_with_insensitive_ascii(const std::wstring_view& str, const std::wstring_view& prefix) noexcept
|
||||
{
|
||||
return starts_with_insensitive_ascii<>(str, prefix);
|
||||
}
|
||||
|
||||
template<typename T, typename Traits>
|
||||
constexpr bool ends_with_insensitive_ascii(const std::basic_string_view<T, Traits>& str, const std::basic_string_view<T, Traits>& suffix) noexcept
|
||||
{
|
||||
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||
return str.size() >= suffix.size() && equals_insensitive_ascii<>({ str.data() - suffix.size(), suffix.size() }, suffix);
|
||||
}
|
||||
|
||||
constexpr bool ends_with_insensitive_ascii(const std::string_view& str, const std::string_view& prefix) noexcept
|
||||
{
|
||||
return ends_with_insensitive_ascii<>(str, prefix);
|
||||
}
|
||||
|
||||
constexpr bool ends_with_insensitive_ascii(const std::wstring_view& str, const std::wstring_view& prefix) noexcept
|
||||
{
|
||||
return ends_with<>(str, prefix);
|
||||
}
|
||||
|
||||
// Give the arguments ("foo bar baz", " "), this method will
|
||||
// * modify the first argument to "bar baz"
|
||||
// * return "foo"
|
||||
// If the needle cannot be found the "str" argument is returned as is.
|
||||
template<typename T, typename Traits>
|
||||
constexpr std::basic_string_view<T, Traits> prefix_split(std::basic_string_view<T, Traits>& str, const std::basic_string_view<T, Traits>& needle) noexcept
|
||||
{
|
||||
using view_type = std::basic_string_view<T, Traits>;
|
||||
|
||||
const auto needleLen = needle.size();
|
||||
const auto idx = needleLen == 0 ? str.size() : str.find(needle);
|
||||
const auto prefixIdx = std::min(str.size(), idx);
|
||||
const auto suffixIdx = std::min(str.size(), prefixIdx + needle.size());
|
||||
|
||||
const view_type result{ str.data(), prefixIdx };
|
||||
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead
|
||||
str = { str.data() + suffixIdx, str.size() - suffixIdx };
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr std::string_view prefix_split(std::string_view& str, const std::string_view& needle) noexcept
|
||||
{
|
||||
return prefix_split<>(str, needle);
|
||||
}
|
||||
|
||||
constexpr std::wstring_view prefix_split(std::wstring_view& str, const std::wstring_view& needle) noexcept
|
||||
{
|
||||
return prefix_split<>(str, needle);
|
||||
}
|
||||
|
||||
// Give the arguments ("foo bar baz", " "), this method will
|
||||
// * modify the first argument to "bar baz"
|
||||
// * return "foo"
|
||||
// If the needle cannot be found the "str" argument is returned as is.
|
||||
template<typename T, typename Traits>
|
||||
constexpr std::basic_string_view<T, Traits> prefix_split(std::basic_string_view<T, Traits>& str, T ch) noexcept
|
||||
{
|
||||
using view_type = std::basic_string_view<T, Traits>;
|
||||
|
||||
const auto idx = str.find(ch);
|
||||
const auto prefixIdx = std::min(str.size(), idx);
|
||||
const auto suffixIdx = std::min(str.size(), prefixIdx + 1);
|
||||
|
||||
const view_type result{ str.data(), prefixIdx };
|
||||
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead
|
||||
str = { str.data() + suffixIdx, str.size() - suffixIdx };
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, typename Traits>
|
||||
constexpr std::basic_string_view<T, Traits> trim(const std::basic_string_view<T, Traits>& str, const T ch) noexcept
|
||||
{
|
||||
auto beg = str.data();
|
||||
auto end = beg + str.size();
|
||||
|
||||
for (; beg != end && *beg == ch; ++beg)
|
||||
{
|
||||
}
|
||||
|
||||
for (; beg != end && end[-1] == ch; --end)
|
||||
{
|
||||
}
|
||||
|
||||
return { beg, end };
|
||||
}
|
||||
|
||||
// Splits a font-family list into individual font-families. It loosely follows the CSS spec for font-family.
|
||||
// It splits by comma, handles quotes and simple escape characters, and it cleans whitespace.
|
||||
//
|
||||
// This is not the right place to put this, because it's highly specialized towards font-family names.
|
||||
// But this code is needed both, in our renderer and in our settings UI. At the time I couldn't find a better place for it.
|
||||
void iterate_font_families(const std::wstring_view& families, auto&& callback)
|
||||
{
|
||||
std::wstring family;
|
||||
bool escape = false;
|
||||
bool delayedSpace = false;
|
||||
wchar_t stringType = 0;
|
||||
|
||||
for (const auto ch : families)
|
||||
{
|
||||
if (!escape)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case ' ':
|
||||
if (stringType)
|
||||
{
|
||||
// Spaces are treated literally inside strings.
|
||||
break;
|
||||
}
|
||||
delayedSpace = !family.empty();
|
||||
continue;
|
||||
case '"':
|
||||
case '\'':
|
||||
if (stringType && stringType != ch)
|
||||
{
|
||||
// Single quotes inside double quotes are treated literally and vice versa.
|
||||
break;
|
||||
}
|
||||
stringType = stringType == ch ? 0 : ch;
|
||||
continue;
|
||||
case ',':
|
||||
if (stringType)
|
||||
{
|
||||
// Commas are treated literally inside strings.
|
||||
break;
|
||||
}
|
||||
if (!family.empty())
|
||||
{
|
||||
callback(std::move(family));
|
||||
family.clear();
|
||||
delayedSpace = false;
|
||||
}
|
||||
continue;
|
||||
case '\\':
|
||||
escape = true;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The `delayedSpace` logic automatically takes care for us to
|
||||
// strip leading and trailing spaces and deduplicate them too.
|
||||
if (delayedSpace)
|
||||
{
|
||||
delayedSpace = false;
|
||||
family.push_back(L' ');
|
||||
}
|
||||
|
||||
family.push_back(ch);
|
||||
escape = false;
|
||||
}
|
||||
|
||||
// Just like the comma handler above.
|
||||
if (!stringType && !family.empty())
|
||||
{
|
||||
callback(std::move(family));
|
||||
}
|
||||
}
|
||||
|
||||
//// This function is appropriate for case-insensitive equivalence testing of file paths and other "system" strings.
|
||||
//// Similar to memcmp, this returns <0, 0 or >0.
|
||||
//inline int compare_ordinal_insensitive(const std::wstring_view& lhs, const std::wstring_view& rhs) noexcept
|
||||
//{
|
||||
// const auto lhsLen = ::base::saturated_cast<int>(lhs.size());
|
||||
// const auto rhsLen = ::base::saturated_cast<int>(rhs.size());
|
||||
// // MSDN:
|
||||
// // > To maintain the C runtime convention of comparing strings,
|
||||
// // > the value 2 can be subtracted from a nonzero return value.
|
||||
// // > [...]
|
||||
// // > The function returns 0 if it does not succeed. [...] following error codes:
|
||||
// // > * ERROR_INVALID_PARAMETER. Any of the parameter values was invalid.
|
||||
// // -> We can just subtract 2.
|
||||
// return CompareStringOrdinal(lhs.data(), lhsLen, rhs.data(), rhsLen, TRUE) - 2;
|
||||
//}
|
||||
|
||||
// // This function is appropriate for sorting strings primarily used for human consumption, like a list of file names.
|
||||
// // Similar to memcmp, this returns <0, 0 or >0.
|
||||
// inline int compare_linguistic_insensitive(const std::wstring_view& lhs, const std::wstring_view& rhs) noexcept
|
||||
// {
|
||||
// const auto lhsLen = ::base::saturated_cast<int>(lhs.size());
|
||||
// const auto rhsLen = ::base::saturated_cast<int>(rhs.size());
|
||||
// // MSDN:
|
||||
// // > To maintain the C runtime convention of comparing strings,
|
||||
// // > the value 2 can be subtracted from a nonzero return value.
|
||||
// // > [...]
|
||||
// // > The function returns 0 if it does not succeed. [...] following error codes:
|
||||
// // > * ERROR_INVALID_FLAGS. The values supplied for flags were invalid.
|
||||
// // > * ERROR_INVALID_PARAMETER. Any of the parameter values was invalid.
|
||||
// // -> We can just subtract 2.
|
||||
//#pragma warning(suppress : 26477) // Use 'nullptr' rather than 0 or NULL (es.47).
|
||||
// return CompareStringEx(LOCALE_NAME_USER_DEFAULT, LINGUISTIC_IGNORECASE, lhs.data(), lhsLen, rhs.data(), rhsLen, nullptr, nullptr, 0) - 2;
|
||||
// }
|
||||
//
|
||||
// // This function is appropriate for strings primarily used for human consumption, like a list of file names.
|
||||
// inline bool contains_linguistic_insensitive(const std::wstring_view& str, const std::wstring_view& needle) noexcept
|
||||
// {
|
||||
// const auto strLen = ::base::saturated_cast<int>(str.size());
|
||||
// const auto needleLen = ::base::saturated_cast<int>(needle.size());
|
||||
// // MSDN:
|
||||
// // > Returns a 0-based index into the source string indicated by lpStringSource if successful.
|
||||
// // > [...]
|
||||
// // > The function returns -1 if it does not succeed.
|
||||
// // > * ERROR_INVALID_FLAGS. The values supplied for flags were not valid.
|
||||
// // > * ERROR_INVALID_PARAMETER. Any of the parameter values was invalid.
|
||||
// // > * ERROR_SUCCESS. The action completed successfully but yielded no results.
|
||||
// // -> We can just check for -1.
|
||||
//#pragma warning(suppress : 26477) // Use 'nullptr' rather than 0 or NULL (es.47).
|
||||
// return FindNLSStringEx(LOCALE_NAME_USER_DEFAULT, LINGUISTIC_IGNORECASE, str.data(), strLen, needle.data(), needleLen, nullptr, nullptr, nullptr, 0) != -1;
|
||||
// }
|
||||
}
|
||||
40
src/modules/cmdpal/Microsoft.Terminal.UI/version.rc
Normal file
40
src/modules/cmdpal/Microsoft.Terminal.UI/version.rc
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION FILE_VERSION
|
||||
PRODUCTVERSION PRODUCT_VERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
|
||||
BEGIN
|
||||
VALUE "CompanyName", COMPANY_NAME
|
||||
VALUE "FileDescription", FILE_DESCRIPTION
|
||||
VALUE "FileVersion", FILE_VERSION_STRING
|
||||
VALUE "InternalName", INTERNAL_NAME
|
||||
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||
VALUE "OriginalFilename", ORIGINAL_FILENAME
|
||||
VALUE "ProductName", PRODUCT_NAME
|
||||
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
|
||||
END
|
||||
END
|
||||
Reference in New Issue
Block a user