Migrate OSS up to 168d28b03

This commit is contained in:
Dustin Howett 2021-11-09 13:33:29 -06:00
commit 30f7f2082b
121 changed files with 2880 additions and 5863 deletions

View file

@ -557,6 +557,7 @@ DECSTR
DECSWL DECSWL
DECTCEM DECTCEM
Dedupe Dedupe
deduplicate
deduplicated deduplicated
DEFAPP DEFAPP
DEFAULTBACKGROUND DEFAULTBACKGROUND
@ -784,6 +785,7 @@ FINDSTRINGEXACT
FINDUP FINDUP
FIter FIter
FIXEDCONVERTED FIXEDCONVERTED
FIXEDFILEINFO
Flg Flg
flyout flyout
fmodern fmodern
@ -1992,6 +1994,7 @@ resx
retval retval
rfa rfa
rfc rfc
rfid
rftp rftp
rgb rgb
rgba rgba

View file

@ -289,6 +289,7 @@ If you would like to ask a question that you feel doesn't warrant an issue
* You must [enable Developer Mode in the Windows Settings * You must [enable Developer Mode in the Windows Settings
app](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development) app](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development)
to locally install and run Windows Terminal to locally install and run Windows Terminal
* You must have [PowerShell 7 or later](https://github.com/PowerShell/PowerShell/releases/latest) installed
* You must have the [Windows 10 1903 * You must have the [Windows 10 1903
SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk)
installed installed

View file

@ -1401,7 +1401,8 @@
"properties": { "properties": {
"acrylicOpacity": { "acrylicOpacity": {
"default": 0.5, "default": 0.5,
"description": "When useAcrylic is set to true, it sets the transparency of the window for the profile. Accepts floating point values from 0-1 (default 0.5).", "description": "[deprecated] Please use `opacity` instead.",
"deprecated": true,
"maximum": 1, "maximum": 1,
"minimum": 0, "minimum": 0,
"type": "number" "type": "number"
@ -1614,6 +1615,13 @@
"minLength": 1, "minLength": 1,
"type": "string" "type": "string"
}, },
"opacity": {
"default": 100,
"description": "Sets the opacity of the window for the profile. Accepts values from 0-100. Defaults to 50 when useAcrylic is set to true.",
"maximum": 100,
"minimum": 0,
"type": "number"
},
"padding": { "padding": {
"default": "8, 8, 8, 8", "default": "8, 8, 8, 8",
"description": "Sets the padding around the text within the window. Can have three different formats:\n -\"#\" sets the same padding for all sides \n -\"#, #\" sets the same padding for left-right and top-bottom\n -\"#, #, #, #\" sets the padding individually for left, top, right, and bottom.", "description": "Sets the padding around the text within the window. Can have three different formats:\n -\"#\" sets the same padding for all sides \n -\"#, #\" sets the same padding for left-right and top-bottom\n -\"#, #, #, #\" sets the padding individually for left, top, right, and bottom.",

View file

@ -140,12 +140,12 @@
<!-- **END VC LIBS HACK** --> <!-- **END VC LIBS HACK** -->
<!-- This is required to get the package dependency in the AppXManifest. --> <!-- This is required to get the package dependency in the AppXManifest. -->
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" /> <Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <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> <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> </PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" /> <Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets'))" />
</Target> </Target>

View file

@ -45,7 +45,7 @@ namespace winrt::SampleApp::implementation
WINRT_PROPERTY(winrt::hstring, ProfileName); WINRT_PROPERTY(winrt::hstring, ProfileName);
WINRT_PROPERTY(bool, UseAcrylic, false); WINRT_PROPERTY(bool, UseAcrylic, false);
WINRT_PROPERTY(double, TintOpacity, 0.5); WINRT_PROPERTY(double, Opacity, .5);
WINRT_PROPERTY(winrt::hstring, Padding, DEFAULT_PADDING); WINRT_PROPERTY(winrt::hstring, Padding, DEFAULT_PADDING);
WINRT_PROPERTY(winrt::hstring, FontFace, L"Consolas"); WINRT_PROPERTY(winrt::hstring, FontFace, L"Consolas");
WINRT_PROPERTY(int32_t, FontSize, DEFAULT_FONT_SIZE); WINRT_PROPERTY(int32_t, FontSize, DEFAULT_FONT_SIZE);

View file

@ -147,13 +147,13 @@
<!-- ========================= Globals ======================== --> <!-- ========================= Globals ======================== -->
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" /> <Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" /> <Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" /> <Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <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> <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> </PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" /> <Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" /> <Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
</Target> </Target>

View file

@ -80,13 +80,13 @@
</ItemGroup> </ItemGroup>
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" /> <Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" /> <Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <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> <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> </PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" /> <Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" /> <Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
</Target> </Target>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" /> <package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.5.0-prerelease.201202003" targetFramework="native" /> <package id="Microsoft.UI.Xaml" version="2.7.0-prerelease.210913003" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" /> <package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" />
</packages> </packages>

View file

@ -120,14 +120,14 @@
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" /> <Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" /> <Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" /> <Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Import Project="..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" /> <Import Project="..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <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> <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> </PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" /> <Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" /> <Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" /> <Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets'))" /> <Error Condition="!Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets'))" />

View file

@ -2,6 +2,6 @@
<packages> <packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" /> <package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" />
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" /> <package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.5.0-prerelease.201202003" targetFramework="native" /> <package id="Microsoft.UI.Xaml" version="2.7.0-prerelease.210913003" targetFramework="native" />
<package id="Microsoft.VCRTForwarders.140" version="1.0.4" targetFramework="native" /> <package id="Microsoft.VCRTForwarders.140" version="1.0.4" targetFramework="native" />
</packages> </packages>

View file

@ -146,12 +146,12 @@
<!-- **END VC LIBS HACK** --> <!-- **END VC LIBS HACK** -->
<!-- This is required to get the package dependency in the AppXManifest. --> <!-- This is required to get the package dependency in the AppXManifest. -->
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" /> <Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <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> <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> </PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" /> <Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets'))" />
</Target> </Target>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" /> <Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />

View file

@ -5,9 +5,11 @@
#include "../TerminalSettingsModel/ColorScheme.h" #include "../TerminalSettingsModel/ColorScheme.h"
#include "../TerminalSettingsModel/CascadiaSettings.h" #include "../TerminalSettingsModel/CascadiaSettings.h"
#include "../types/inc/colorTable.hpp"
#include "JsonTestClass.h" #include "JsonTestClass.h"
using namespace Microsoft::Console; using namespace Microsoft::Console;
using namespace winrt::Microsoft::Terminal;
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
using namespace WEX::Logging; using namespace WEX::Logging;
using namespace WEX::TestExecution; using namespace WEX::TestExecution;
@ -32,339 +34,293 @@ namespace SettingsModelLocalTests
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml") TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
END_TEST_CLASS() END_TEST_CLASS()
TEST_METHOD(CanLayerColorScheme); TEST_METHOD(ParseSimpleColorScheme);
TEST_METHOD(LayerColorSchemeProperties);
TEST_METHOD(LayerColorSchemesOnArray); TEST_METHOD(LayerColorSchemesOnArray);
TEST_METHOD(UpdateSchemeReferences); TEST_METHOD(UpdateSchemeReferences);
TEST_CLASS_SETUP(ClassSetup) static Core::Color rgb(uint8_t r, uint8_t g, uint8_t b) noexcept
{ {
InitializeJsonReader(); return Core::Color{ r, g, b, 255 };
return true;
} }
}; };
void ColorSchemeTests::CanLayerColorScheme() void ColorSchemeTests::ParseSimpleColorScheme()
{ {
const std::string scheme0String{ R"({ const std::string campbellScheme{ "{"
"name": "scheme0", "\"background\" : \"#0C0C0C\","
"foreground": "#000000", "\"black\" : \"#0C0C0C\","
"background": "#010101" "\"blue\" : \"#0037DA\","
})" }; "\"brightBlack\" : \"#767676\","
const std::string scheme1String{ R"({ "\"brightBlue\" : \"#3B78FF\","
"name": "scheme1", "\"brightCyan\" : \"#61D6D6\","
"foreground": "#020202", "\"brightGreen\" : \"#16C60C\","
"background": "#030303" "\"brightPurple\" : \"#B4009E\","
})" }; "\"brightRed\" : \"#E74856\","
const std::string scheme2String{ R"({ "\"brightWhite\" : \"#F2F2F2\","
"name": "scheme0", "\"brightYellow\" : \"#F9F1A5\","
"foreground": "#040404", "\"cursorColor\" : \"#FFFFFF\","
"background": "#050505" "\"cyan\" : \"#3A96DD\","
})" }; "\"foreground\" : \"#F2F2F2\","
const std::string scheme3String{ R"({ "\"green\" : \"#13A10E\","
// "name": "scheme3", "\"name\" : \"Campbell\","
"foreground": "#060606", "\"purple\" : \"#881798\","
"background": "#070707" "\"red\" : \"#C50F1F\","
})" }; "\"selectionBackground\" : \"#131313\","
"\"white\" : \"#CCCCCC\","
"\"yellow\" : \"#C19C00\""
"}" };
const auto scheme0Json = VerifyParseSucceeded(scheme0String); const auto schemeObject = VerifyParseSucceeded(campbellScheme);
const auto scheme1Json = VerifyParseSucceeded(scheme1String); auto scheme = ColorScheme::FromJson(schemeObject);
const auto scheme2Json = VerifyParseSucceeded(scheme2String); VERIFY_ARE_EQUAL(L"Campbell", scheme->Name());
const auto scheme3Json = VerifyParseSucceeded(scheme3String); VERIFY_ARE_EQUAL(til::color(0xf2, 0xf2, 0xf2, 255), til::color{ scheme->Foreground() });
VERIFY_ARE_EQUAL(til::color(0x0c, 0x0c, 0x0c, 255), til::color{ scheme->Background() });
VERIFY_ARE_EQUAL(til::color(0x13, 0x13, 0x13, 255), til::color{ scheme->SelectionBackground() });
VERIFY_ARE_EQUAL(til::color(0xFF, 0xFF, 0xFF, 255), til::color{ scheme->CursorColor() });
const auto scheme0 = ColorScheme::FromJson(scheme0Json); std::array<COLORREF, COLOR_TABLE_SIZE> expectedCampbellTable;
const auto campbellSpan = gsl::make_span(expectedCampbellTable);
Utils::InitializeCampbellColorTable(campbellSpan);
Utils::SetColorTableAlpha(campbellSpan, 0);
VERIFY_IS_TRUE(scheme0->ShouldBeLayered(scheme0Json)); for (size_t i = 0; i < expectedCampbellTable.size(); i++)
VERIFY_IS_FALSE(scheme0->ShouldBeLayered(scheme1Json)); {
VERIFY_IS_TRUE(scheme0->ShouldBeLayered(scheme2Json)); const auto& expected = expectedCampbellTable.at(i);
VERIFY_IS_FALSE(scheme0->ShouldBeLayered(scheme3Json)); const til::color actual{ scheme->Table().at(static_cast<uint32_t>(i)) };
VERIFY_ARE_EQUAL(expected, actual);
}
const auto scheme1 = ColorScheme::FromJson(scheme1Json); Log::Comment(L"Roundtrip Test for Color Scheme");
Json::Value outJson{ scheme->ToJson() };
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme0Json)); VERIFY_ARE_EQUAL(schemeObject, outJson);
VERIFY_IS_TRUE(scheme1->ShouldBeLayered(scheme1Json));
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme2Json));
VERIFY_IS_FALSE(scheme1->ShouldBeLayered(scheme3Json));
const auto scheme3 = ColorScheme::FromJson(scheme3Json);
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme0Json));
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme1Json));
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme2Json));
VERIFY_IS_FALSE(scheme3->ShouldBeLayered(scheme3Json));
}
void ColorSchemeTests::LayerColorSchemeProperties()
{
const std::string scheme0String{ R"({
"name": "scheme0",
"foreground": "#000000",
"background": "#010101",
"selectionBackground": "#010100",
"cursorColor": "#010001",
"red": "#010000",
"green": "#000100",
"blue": "#000001"
})" };
const std::string scheme1String{ R"({
"name": "scheme1",
"foreground": "#020202",
"background": "#030303",
"selectionBackground": "#020200",
"cursorColor": "#040004",
"red": "#020000",
"blue": "#000002"
})" };
const std::string scheme2String{ R"({
"name": "scheme0",
"foreground": "#040404",
"background": "#050505",
"selectionBackground": "#030300",
"cursorColor": "#060006",
"red": "#030000",
"green": "#000300"
})" };
const auto scheme0Json = VerifyParseSucceeded(scheme0String);
const auto scheme1Json = VerifyParseSucceeded(scheme1String);
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
auto scheme0 = ColorScheme::FromJson(scheme0Json);
VERIFY_ARE_EQUAL(L"scheme0", scheme0->_Name);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 1), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 1, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 1), scheme0->_table[XTERM_BLUE_ATTR]);
Log::Comment(NoThrowString().Format(
L"Layering scheme1 on top of scheme0"));
scheme0->LayerJson(scheme1Json);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 4, 0, 4), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 2, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 1, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 2), scheme0->_table[XTERM_BLUE_ATTR]);
Log::Comment(NoThrowString().Format(
L"Layering scheme2Json on top of (scheme0+scheme1)"));
scheme0->LayerJson(scheme2Json);
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 6, 0, 6), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 3, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 3, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 2), scheme0->_table[XTERM_BLUE_ATTR]);
} }
void ColorSchemeTests::LayerColorSchemesOnArray() void ColorSchemeTests::LayerColorSchemesOnArray()
{ {
const std::string scheme0String{ R"({ static constexpr std::string_view inboxSettings{ R"({
"name": "scheme0", "schemes": [
"foreground": "#000000", {
"background": "#010101" "background": "#0C0C0C",
"black": "#0C0C0C",
"blue": "#0037DA",
"brightBlack": "#767676",
"brightBlue": "#3B78FF",
"brightCyan": "#61D6D6",
"brightGreen": "#16C60C",
"brightPurple": "#B4009E",
"brightRed": "#E74856",
"brightWhite": "#F2F2F2",
"brightYellow": "#F9F1A5",
"cursorColor": "#FFFFFF",
"cyan": "#3A96DD",
"foreground": "#CCCCCC",
"green": "#13A10E",
"name": "Campbell",
"purple": "#881798",
"red": "#C50F1F",
"selectionBackground": "#FFFFFF",
"white": "#CCCCCC",
"yellow": "#C19C00"
}
]
})" }; })" };
const std::string scheme1String{ R"({ static constexpr std::string_view userSettings{ R"({
"name": "scheme1", "profiles": [
"foreground": "#020202", {
"background": "#030303" "name" : "profile0"
})" }; }
const std::string scheme2String{ R"({ ],
"name": "scheme0", "schemes": [
"foreground": "#040404", {
"background": "#050505" "background": "#121314",
})" }; "black": "#121314",
const std::string scheme3String{ R"({ "blue": "#121314",
// by not providing a name, the scheme will have the name "" "brightBlack": "#121314",
"foreground": "#060606", "brightBlue": "#121314",
"background": "#070707" "brightCyan": "#121314",
"brightGreen": "#121314",
"brightPurple": "#121314",
"brightRed": "#121314",
"brightWhite": "#121314",
"brightYellow": "#121314",
"cursorColor": "#121314",
"cyan": "#121314",
"foreground": "#121314",
"green": "#121314",
"name": "Campbell",
"purple": "#121314",
"red": "#121314",
"selectionBackground": "#121314",
"white": "#121314",
"yellow": "#121314"
},
{
"background": "#012456",
"black": "#0C0C0C",
"blue": "#0037DA",
"brightBlack": "#767676",
"brightBlue": "#3B78FF",
"brightCyan": "#61D6D6",
"brightGreen": "#16C60C",
"brightPurple": "#B4009E",
"brightRed": "#E74856",
"brightWhite": "#F2F2F2",
"brightYellow": "#F9F1A5",
"cursorColor": "#FFFFFF",
"cyan": "#3A96DD",
"foreground": "#CCCCCC",
"green": "#13A10E",
"name": "Campbell Powershell",
"purple": "#881798",
"red": "#C50F1F",
"selectionBackground": "#FFFFFF",
"white": "#CCCCCC",
"yellow": "#C19C00"
}
]
})" }; })" };
const auto scheme0Json = VerifyParseSucceeded(scheme0String); const auto settings = winrt::make_self<CascadiaSettings>(userSettings, inboxSettings);
const auto scheme1Json = VerifyParseSucceeded(scheme1String);
const auto scheme2Json = VerifyParseSucceeded(scheme2String);
const auto scheme3Json = VerifyParseSucceeded(scheme3String);
auto settings = winrt::make_self<CascadiaSettings>(); const auto colorSchemes = settings->GlobalSettings().ColorSchemes();
VERIFY_ARE_EQUAL(2u, colorSchemes.Size());
VERIFY_ARE_EQUAL(0u, settings->_globals->ColorSchemes().Size()); const auto scheme0 = winrt::get_self<ColorScheme>(colorSchemes.Lookup(L"Campbell"));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme0Json)); VERIFY_ARE_EQUAL(rgb(0x12, 0x13, 0x14), scheme0->Foreground());
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme1Json)); VERIFY_ARE_EQUAL(rgb(0x12, 0x13, 0x14), scheme0->Background());
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
settings->_LayerOrCreateColorScheme(scheme0Json); const auto scheme1 = winrt::get_self<ColorScheme>(colorSchemes.Lookup(L"Campbell Powershell"));
{ VERIFY_ARE_EQUAL(rgb(0xCC, 0xCC, 0xCC), scheme1->Foreground());
for (auto kv : settings->_globals->ColorSchemes()) VERIFY_ARE_EQUAL(rgb(0x01, 0x24, 0x56), scheme1->Background());
{
Log::Comment(NoThrowString().Format(
L"kv:%s->%s", kv.Key().data(), kv.Value().Name().data()));
}
VERIFY_ARE_EQUAL(1u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
}
settings->_LayerOrCreateColorScheme(scheme1Json);
{
VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme1"));
auto scheme1Proj = settings->_globals->ColorSchemes().Lookup(L"scheme1");
auto scheme1 = winrt::get_self<ColorScheme>(scheme1Proj);
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
}
settings->_LayerOrCreateColorScheme(scheme2Json);
{
VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme1"));
auto scheme1Proj = settings->_globals->ColorSchemes().Lookup(L"scheme1");
auto scheme1 = winrt::get_self<ColorScheme>(scheme1Proj);
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
}
settings->_LayerOrCreateColorScheme(scheme3Json);
{
VERIFY_ARE_EQUAL(3u, settings->_globals->ColorSchemes().Size());
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme0"));
auto scheme0Proj = settings->_globals->ColorSchemes().Lookup(L"scheme0");
auto scheme0 = winrt::get_self<ColorScheme>(scheme0Proj);
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L"scheme1"));
auto scheme1Proj = settings->_globals->ColorSchemes().Lookup(L"scheme1");
auto scheme1 = winrt::get_self<ColorScheme>(scheme1Proj);
VERIFY_IS_TRUE(settings->_globals->ColorSchemes().HasKey(L""));
auto scheme2Proj = settings->_globals->ColorSchemes().Lookup(L"");
auto scheme2 = winrt::get_self<ColorScheme>(scheme2Proj);
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 6, 6, 6), scheme2->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 7, 7, 7), scheme2->_Background);
}
} }
void ColorSchemeTests::UpdateSchemeReferences() void ColorSchemeTests::UpdateSchemeReferences()
{ {
const std::string settingsString{ R"json({ static constexpr std::string_view settingsString{ R"json({
"defaultProfile": "Inherited reference", "defaultProfile": "Inherited reference",
"profiles": { "profiles": {
"defaults": { "defaults": {
"colorScheme": "Scheme 1" "colorScheme": "Campbell"
}, },
"list": [ "list": [
{ {
"name": "Explicit scheme reference", "name": "Explicit scheme reference",
"colorScheme": "Scheme 1" "colorScheme": "Campbell"
}, },
{ {
"name": "Explicit reference; hidden", "name": "Explicit reference; hidden",
"colorScheme": "Scheme 1", "colorScheme": "Campbell",
"hidden": true "hidden": true
}, },
{ {
"name": "Inherited reference" "name": "Inherited reference"
}, },
{ {
"name": "Different reference", "name": "Different reference",
"colorScheme": "Scheme 2" "colorScheme": "One Half Dark"
} }
] ]
}, },
"schemes": [ "schemes": [
{ "name": "Scheme 1" }, {
{ "name": "Scheme 2" }, "background": "#0C0C0C",
{ "name": "Scheme 1 (renamed)" } "black": "#0C0C0C",
] "blue": "#0037DA",
})json" }; "brightBlack": "#767676",
"brightBlue": "#3B78FF",
"brightCyan": "#61D6D6",
"brightGreen": "#16C60C",
"brightPurple": "#B4009E",
"brightRed": "#E74856",
"brightWhite": "#F2F2F2",
"brightYellow": "#F9F1A5",
"cursorColor": "#FFFFFF",
"cyan": "#3A96DD",
"foreground": "#CCCCCC",
"green": "#13A10E",
"name": "Campbell",
"purple": "#881798",
"red": "#C50F1F",
"selectionBackground": "#FFFFFF",
"white": "#CCCCCC",
"yellow": "#C19C00"
},
{
"background": "#0C0C0C",
"black": "#0C0C0C",
"blue": "#0037DA",
"brightBlack": "#767676",
"brightBlue": "#3B78FF",
"brightCyan": "#61D6D6",
"brightGreen": "#16C60C",
"brightPurple": "#B4009E",
"brightRed": "#E74856",
"brightWhite": "#F2F2F2",
"brightYellow": "#F9F1A5",
"cursorColor": "#FFFFFF",
"cyan": "#3A96DD",
"foreground": "#CCCCCC",
"green": "#13A10E",
"name": "Campbell (renamed)",
"purple": "#881798",
"red": "#C50F1F",
"selectionBackground": "#FFFFFF",
"white": "#CCCCCC",
"yellow": "#C19C00"
},
{
"background": "#282C34",
"black": "#282C34",
"blue": "#61AFEF",
"brightBlack": "#5A6374",
"brightBlue": "#61AFEF",
"brightCyan": "#56B6C2",
"brightGreen": "#98C379",
"brightPurple": "#C678DD",
"brightRed": "#E06C75",
"brightWhite": "#DCDFE4",
"brightYellow": "#E5C07B",
"cursorColor": "#FFFFFF",
"cyan": "#56B6C2",
"foreground": "#DCDFE4",
"green": "#98C379",
"name": "One Half Dark",
"purple": "#C678DD",
"red": "#E06C75",
"selectionBackground": "#FFFFFF",
"white": "#DCDFE4",
"yellow": "#E5C07B"
}
]
})json" };
auto settings{ winrt::make_self<CascadiaSettings>(false) }; const auto settings{ winrt::make_self<CascadiaSettings>(settingsString) };
settings->_ParseJsonString(settingsString, false);
settings->_ApplyDefaultsFromUserSettings();
settings->LayerJson(settings->_userSettings);
settings->_ValidateSettings();
// update all references to "Scheme 1" const auto newName{ L"Campbell (renamed)" };
const auto newName{ L"Scheme 1 (renamed)" }; settings->UpdateColorSchemeReferences(L"Campbell", newName);
settings->UpdateColorSchemeReferences(L"Scheme 1", newName);
// verify profile defaults
Log::Comment(L"Profile Defaults");
VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().DefaultAppearance().ColorSchemeName()); VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(settings->ProfileDefaults().DefaultAppearance().HasColorSchemeName()); VERIFY_IS_TRUE(settings->ProfileDefaults().DefaultAppearance().HasColorSchemeName());
// verify all other profiles
const auto& profiles{ settings->AllProfiles() }; const auto& profiles{ settings->AllProfiles() };
{ {
const auto& prof{ profiles.GetAt(0) }; const auto& prof{ profiles.GetAt(0) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName()); VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName()); VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
} }
{ {
const auto& prof{ profiles.GetAt(1) }; const auto& prof{ profiles.GetAt(1) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName()); VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName()); VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
} }
{ {
const auto& prof{ profiles.GetAt(2) }; const auto& prof{ profiles.GetAt(2) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName()); VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_FALSE(prof.DefaultAppearance().HasColorSchemeName()); VERIFY_IS_FALSE(prof.DefaultAppearance().HasColorSchemeName());
} }
{ {
const auto& prof{ profiles.GetAt(3) }; const auto& prof{ profiles.GetAt(3) };
Log::Comment(prof.Name().c_str()); VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().ColorSchemeName());
VERIFY_ARE_EQUAL(L"Scheme 2", prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName()); VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
} }
} }

View file

@ -43,12 +43,6 @@ namespace SettingsModelLocalTests
TEST_METHOD(TestLayerOnAutogeneratedName); TEST_METHOD(TestLayerOnAutogeneratedName);
TEST_METHOD(TestGenerateCommandline); TEST_METHOD(TestGenerateCommandline);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
}; };
void CommandTests::ManyCommandsSameAction() void CommandTests::ManyCommandsSameAction()

File diff suppressed because it is too large Load diff

View file

@ -7,44 +7,34 @@ Module Name:
Abstract: Abstract:
- This class is a helper that can be used to quickly create tests that need to - This class is a helper that can be used to quickly create tests that need to
read & parse json data. Test classes that need to read JSON should make sure read & parse json data.
to derive from this class, and also make sure to call InitializeJsonReader()
in the TEST_CLASS_SETUP().
Author(s): Author(s):
Mike Griese (migrie) August-2019 Mike Griese (migrie) August-2019
--*/ --*/
#pragma once
class JsonTestClass class JsonTestClass
{ {
public: public:
void InitializeJsonReader() static Json::Value VerifyParseSucceeded(const std::string_view& content)
{ {
_reader = std::unique_ptr<Json::CharReader>(Json::CharReaderBuilder::CharReaderBuilder().newCharReader()); static const std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
};
void InitializeJsonWriter()
{
_writer = std::unique_ptr<Json::StreamWriter>(Json::StreamWriterBuilder::StreamWriterBuilder().newStreamWriter());
}
Json::Value VerifyParseSucceeded(std::string content)
{
Json::Value root; Json::Value root;
std::string errs; std::string errs;
const bool parseResult = _reader->parse(content.c_str(), content.c_str() + content.size(), &root, &errs); const bool parseResult = reader->parse(content.data(), content.data() + content.size(), &root, &errs);
VERIFY_IS_TRUE(parseResult, winrt::to_hstring(errs).c_str()); VERIFY_IS_TRUE(parseResult, winrt::to_hstring(errs).c_str());
return root; return root;
}; };
std::string toString(const Json::Value& json) static std::string toString(const Json::Value& json)
{ {
static const std::unique_ptr<Json::StreamWriter> writer{ Json::StreamWriterBuilder::StreamWriterBuilder().newStreamWriter() };
std::stringstream s; std::stringstream s;
_writer->write(json, &s); writer->write(json, &s);
return s.str(); return s.str();
} }
protected:
std::unique_ptr<Json::CharReader> _reader;
std::unique_ptr<Json::StreamWriter> _writer;
}; };

View file

@ -59,12 +59,6 @@ namespace SettingsModelLocalTests
TEST_METHOD(TestGetKeyBindingForAction); TEST_METHOD(TestGetKeyBindingForAction);
TEST_METHOD(KeybindingsWithoutVkey); TEST_METHOD(KeybindingsWithoutVkey);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
}; };
void KeyBindingsTests::KeyChords() void KeyBindingsTests::KeyChords()

View file

@ -7,6 +7,8 @@
#include "../TerminalSettingsModel/CascadiaSettings.h" #include "../TerminalSettingsModel/CascadiaSettings.h"
#include "JsonTestClass.h" #include "JsonTestClass.h"
#include <defaults.h>
using namespace Microsoft::Console; using namespace Microsoft::Console;
using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace WEX::Logging; using namespace WEX::Logging;
@ -32,81 +34,86 @@ namespace SettingsModelLocalTests
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml") TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
END_TEST_CLASS() END_TEST_CLASS()
TEST_METHOD(CanLayerProfile); TEST_METHOD(ProfileGeneratesGuid);
TEST_METHOD(LayerProfileProperties); TEST_METHOD(LayerProfileProperties);
TEST_METHOD(LayerProfileIcon); TEST_METHOD(LayerProfileIcon);
TEST_METHOD(LayerProfilesOnArray); TEST_METHOD(LayerProfilesOnArray);
TEST_METHOD(DuplicateProfileTest); TEST_METHOD(DuplicateProfileTest);
TEST_METHOD(TestGenGuidsForProfiles);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
}; };
void ProfileTests::CanLayerProfile() void ProfileTests::ProfileGeneratesGuid()
{ {
const std::string profile0String{ R"({ // Parse some profiles without guids. We should NOT generate new guids
"name" : "profile0", // for them. If a profile doesn't have a GUID, we'll leave its _guid
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}" // set to nullopt. The Profile::Guid() getter will
})" }; // ensure all profiles have a GUID that's actually set.
const std::string profile1String{ R"({ // The null guid _is_ a valid guid, so we won't re-generate that
"name" : "profile1", // guid. null is _not_ a valid guid, so we'll leave that nullopt
"guid" : "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile2String{ R"({
"name" : "profile2",
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile3String{ R"({
"name" : "profile3"
})" };
const auto profile0Json = VerifyParseSucceeded(profile0String); // See SettingsTests::ValidateProfilesGenerateGuids for a version of
const auto profile1Json = VerifyParseSucceeded(profile1String); // this test that includes synthesizing GUIDS for profiles without GUIDs
const auto profile2Json = VerifyParseSucceeded(profile2String); // set
const auto profile3Json = VerifyParseSucceeded(profile3String);
const std::string profileWithoutGuid{ R"({
"name" : "profile0"
})" };
const std::string secondProfileWithoutGuid{ R"({
"name" : "profile1"
})" };
const std::string profileWithNullForGuid{ R"({
"name" : "profile2",
"guid" : null
})" };
const std::string profileWithNullGuid{ R"({
"name" : "profile3",
"guid" : "{00000000-0000-0000-0000-000000000000}"
})" };
const std::string profileWithGuid{ R"({
"name" : "profile4",
"guid" : "{6239a42c-1de4-49a3-80bd-e8fdd045185c}"
})" };
const auto profile0Json = VerifyParseSucceeded(profileWithoutGuid);
const auto profile1Json = VerifyParseSucceeded(secondProfileWithoutGuid);
const auto profile2Json = VerifyParseSucceeded(profileWithNullForGuid);
const auto profile3Json = VerifyParseSucceeded(profileWithNullGuid);
const auto profile4Json = VerifyParseSucceeded(profileWithGuid);
const auto profile0 = implementation::Profile::FromJson(profile0Json); const auto profile0 = implementation::Profile::FromJson(profile0Json);
VERIFY_IS_FALSE(profile0->ShouldBeLayered(profile1Json));
VERIFY_IS_TRUE(profile0->ShouldBeLayered(profile2Json));
VERIFY_IS_FALSE(profile0->ShouldBeLayered(profile3Json));
const auto profile1 = implementation::Profile::FromJson(profile1Json); const auto profile1 = implementation::Profile::FromJson(profile1Json);
const auto profile2 = implementation::Profile::FromJson(profile2Json);
VERIFY_IS_FALSE(profile1->ShouldBeLayered(profile0Json));
// A profile _can_ be layered with itself, though what's the point?
VERIFY_IS_TRUE(profile1->ShouldBeLayered(profile1Json));
VERIFY_IS_FALSE(profile1->ShouldBeLayered(profile2Json));
VERIFY_IS_FALSE(profile1->ShouldBeLayered(profile3Json));
const auto profile3 = implementation::Profile::FromJson(profile3Json); const auto profile3 = implementation::Profile::FromJson(profile3Json);
const auto profile4 = implementation::Profile::FromJson(profile4Json);
const winrt::guid cmdGuid = Utils::GuidFromString(L"{6239a42c-1de4-49a3-80bd-e8fdd045185c}");
const winrt::guid nullGuid{};
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile0Json)); VERIFY_IS_FALSE(profile0->HasGuid());
// A profile _can_ be layered with itself, though what's the point? VERIFY_IS_FALSE(profile1->HasGuid());
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile1Json)); VERIFY_IS_FALSE(profile2->HasGuid());
VERIFY_IS_FALSE(profile3->ShouldBeLayered(profile2Json)); VERIFY_IS_TRUE(profile3->HasGuid());
VERIFY_IS_TRUE(profile3->ShouldBeLayered(profile3Json)); VERIFY_IS_TRUE(profile4->HasGuid());
VERIFY_ARE_EQUAL(profile3->Guid(), nullGuid);
VERIFY_ARE_EQUAL(profile4->Guid(), cmdGuid);
} }
void ProfileTests::LayerProfileProperties() void ProfileTests::LayerProfileProperties()
{ {
const std::string profile0String{ R"({ static constexpr std::string_view profile0String{ R"({
"name": "profile0", "name": "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"foreground": "#000000", "foreground": "#000000",
"background": "#010101", "background": "#010101",
"selectionBackground": "#010101" "selectionBackground": "#010101"
})" }; })" };
const std::string profile1String{ R"({ static constexpr std::string_view profile1String{ R"({
"name": "profile1", "name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"foreground": "#020202", "foreground": "#020202",
"startingDirectory": "C:/" "startingDirectory": "C:/"
})" }; })" };
const std::string profile2String{ R"({ static constexpr std::string_view profile2String{ R"({
"name": "profile2", "name": "profile2",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"foreground": "#030303", "foreground": "#030303",
@ -172,21 +179,21 @@ namespace SettingsModelLocalTests
void ProfileTests::LayerProfileIcon() void ProfileTests::LayerProfileIcon()
{ {
const std::string profile0String{ R"({ static constexpr std::string_view profile0String{ R"({
"name": "profile0", "name": "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"icon": "not-null.png" "icon": "not-null.png"
})" }; })" };
const std::string profile1String{ R"({ static constexpr std::string_view profile1String{ R"({
"name": "profile1", "name": "profile1",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"icon": null "icon": null
})" }; })" };
const std::string profile2String{ R"({ static constexpr std::string_view profile2String{ R"({
"name": "profile2", "name": "profile2",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
})" }; })" };
const std::string profile3String{ R"({ static constexpr std::string_view profile3String{ R"({
"name": "profile3", "name": "profile3",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"icon": "another-real.png" "icon": "another-real.png"
@ -228,102 +235,95 @@ namespace SettingsModelLocalTests
void ProfileTests::LayerProfilesOnArray() void ProfileTests::LayerProfilesOnArray()
{ {
const std::string profile0String{ R"({ static constexpr std::string_view inboxProfiles{ R"({
"name" : "profile0", "profiles": [
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}" {
"name" : "profile0",
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
}, {
"name" : "profile1",
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
}, {
"name" : "profile2",
"guid" : "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
}
]
})" }; })" };
const std::string profile1String{ R"({ static constexpr std::string_view userProfiles{ R"({
"name" : "profile1", "profiles": [
"guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}" {
})" }; "name" : "profile3",
const std::string profile2String{ R"({ "guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
"name" : "profile2", }, {
"guid" : "{6239a42c-2222-49a3-80bd-e8fdd045185c}" "name" : "profile4",
})" }; "guid" : "{6239a42c-1111-49a3-80bd-e8fdd045185c}"
const std::string profile3String{ R"({ }
"name" : "profile3", ]
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
})" };
const std::string profile4String{ R"({
"name" : "profile4",
"guid" : "{6239a42c-0000-49a3-80bd-e8fdd045185c}"
})" }; })" };
const auto profile0Json = VerifyParseSucceeded(profile0String); const auto settings = winrt::make_self<implementation::CascadiaSettings>(userProfiles, inboxProfiles);
const auto profile1Json = VerifyParseSucceeded(profile1String); const auto allProfiles = settings->AllProfiles();
const auto profile2Json = VerifyParseSucceeded(profile2String); VERIFY_ARE_EQUAL(3u, allProfiles.Size());
const auto profile3Json = VerifyParseSucceeded(profile3String); VERIFY_ARE_EQUAL(L"profile3", allProfiles.GetAt(0).Name());
const auto profile4Json = VerifyParseSucceeded(profile4String); VERIFY_ARE_EQUAL(L"profile4", allProfiles.GetAt(1).Name());
VERIFY_ARE_EQUAL(L"profile2", allProfiles.GetAt(2).Name());
auto settings = winrt::make_self<implementation::CascadiaSettings>();
VERIFY_ARE_EQUAL(0u, settings->_allProfiles.Size());
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile4Json));
settings->_LayerOrCreateProfile(profile0Json);
VERIFY_ARE_EQUAL(1u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
settings->_LayerOrCreateProfile(profile1Json);
VERIFY_ARE_EQUAL(2u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
settings->_LayerOrCreateProfile(profile2Json);
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
VERIFY_ARE_EQUAL(L"profile0", settings->_allProfiles.GetAt(0).Name());
settings->_LayerOrCreateProfile(profile3Json);
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
VERIFY_ARE_EQUAL(L"profile3", settings->_allProfiles.GetAt(0).Name());
settings->_LayerOrCreateProfile(profile4Json);
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile0Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile2Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile3Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingProfile(profile4Json));
VERIFY_ARE_EQUAL(L"profile4", settings->_allProfiles.GetAt(0).Name());
} }
void ProfileTests::DuplicateProfileTest() void ProfileTests::DuplicateProfileTest()
{ {
const std::string profile0String{ R"({ static constexpr std::string_view userProfiles{ R"({
"name" : "profile0", "profiles": [
"backgroundImage" : "some//path" {
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"backgroundImage": "file:///some/path",
"hidden": false,
}
]
})" }; })" };
const auto profile0Json = VerifyParseSucceeded(profile0String); const auto settings = winrt::make_self<implementation::CascadiaSettings>(userProfiles);
const auto profile = settings->AllProfiles().GetAt(0);
const auto duplicatedProfile = settings->DuplicateProfile(profile);
auto settings = winrt::make_self<implementation::CascadiaSettings>(); duplicatedProfile.Guid(profile.Guid());
duplicatedProfile.Name(profile.Name());
settings->_LayerOrCreateProfile(profile0Json);
auto duplicatedProfile = settings->DuplicateProfile(*settings->_FindMatchingProfile(profile0Json));
duplicatedProfile.Name(L"profile0");
const auto json = winrt::get_self<implementation::Profile>(profile)->ToJson();
const auto duplicatedJson = winrt::get_self<implementation::Profile>(duplicatedProfile)->ToJson(); const auto duplicatedJson = winrt::get_self<implementation::Profile>(duplicatedProfile)->ToJson();
VERIFY_ARE_EQUAL(profile0Json, duplicatedJson); VERIFY_ARE_EQUAL(json, duplicatedJson, til::u8u16(toString(duplicatedJson)).c_str());
}
void ProfileTests::TestGenGuidsForProfiles()
{
// We'll generate GUIDs in the Profile::Guid getter. We should make sure that
// the GUID generated for a dynamic profile (with a source) is different
// than that of a profile without a source.
static constexpr std::string_view userSettings{ R"({
"profiles": [
{
"name": "profile0",
"source": "Terminal.App.UnitTest.0",
},
{
"name": "profile0"
}
]
})" };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(userSettings, DefaultJson);
VERIFY_ARE_EQUAL(4u, settings->AllProfiles().Size());
VERIFY_ARE_EQUAL(L"profile0", settings->AllProfiles().GetAt(0).Name());
VERIFY_IS_TRUE(settings->AllProfiles().GetAt(0).HasGuid());
VERIFY_IS_FALSE(settings->AllProfiles().GetAt(0).Source().empty());
VERIFY_ARE_EQUAL(L"profile0", settings->AllProfiles().GetAt(1).Name());
VERIFY_IS_TRUE(settings->AllProfiles().GetAt(1).HasGuid());
VERIFY_IS_TRUE(settings->AllProfiles().GetAt(1).Source().empty());
VERIFY_ARE_NOT_EQUAL(settings->AllProfiles().GetAt(0).Guid(), settings->AllProfiles().GetAt(1).Guid());
} }
} }

View file

@ -8,7 +8,6 @@
#include "JsonTestClass.h" #include "JsonTestClass.h"
#include "TestUtils.h" #include "TestUtils.h"
#include <defaults.h> #include <defaults.h>
#include "../ut_app/TestDynamicProfileGenerator.h"
using namespace Microsoft::Console; using namespace Microsoft::Console;
using namespace WEX::Logging; using namespace WEX::Logging;
@ -43,13 +42,6 @@ namespace SettingsModelLocalTests
TEST_METHOD(CascadiaSettings); TEST_METHOD(CascadiaSettings);
TEST_METHOD(LegacyFontSettings); TEST_METHOD(LegacyFontSettings);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
InitializeJsonWriter();
return true;
}
private: private:
// Method Description: // Method Description:
// - deserializes and reserializes a json string representing a settings object model of type T // - deserializes and reserializes a json string representing a settings object model of type T
@ -309,10 +301,10 @@ namespace SettingsModelLocalTests
])" }; ])" };
const std::string actionsString9B{ R"([ const std::string actionsString9B{ R"([
{ {
"commands": "commands":
[ [
{ {
"command": "command":
{ {
"action": "sendInput", "action": "sendInput",
"input": "${profile.name}" "input": "${profile.name}"
@ -325,13 +317,13 @@ namespace SettingsModelLocalTests
])" }; ])" };
const std::string actionsString9C{ R""([ const std::string actionsString9C{ R""([
{ {
"commands": "commands":
[ [
{ {
"commands": "commands":
[ [
{ {
"command": "command":
{ {
"action": "sendInput", "action": "sendInput",
"input": "${profile.name} ${scheme.name}" "input": "${profile.name} ${scheme.name}"
@ -348,7 +340,7 @@ namespace SettingsModelLocalTests
])"" }; ])"" };
const std::string actionsString9D{ R""([ const std::string actionsString9D{ R""([
{ {
"command": "command":
{ {
"action": "newTab", "action": "newTab",
"profile": "${profile.name}" "profile": "${profile.name}"
@ -404,75 +396,71 @@ namespace SettingsModelLocalTests
void SerializationTests::CascadiaSettings() void SerializationTests::CascadiaSettings()
{ {
const std::string settingsString{ R"({ const std::string settingsString{ R"({
"$schema": "https://aka.ms/terminal-profiles-schema", "$help" : "https://aka.ms/terminal-documentation",
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}", "$schema" : "https://aka.ms/terminal-profiles-schema",
"disabledProfileSources": [ "Windows.Terminal.Wsl" ], "defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
"disabledProfileSources": [ "Windows.Terminal.Wsl" ],
"profiles": {
"defaults": {
"font": {
"face": "Zamora Code"
}
},
"list": [
{
"font": { "face": "Cascadia Code" },
"guid": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
"name": "HowettShell"
},
{
"hidden": true,
"guid": "{c08b0496-e71c-5503-b84e-3af7a7a6d2a7}",
"name": "BhojwaniShell"
},
{
"antialiasingMode": "aliased",
"guid": "{fe9df758-ac22-5c20-922d-c7766cdd13af}",
"name": "NiksaShell"
}
]
},
"schemes": [
{
"name": "Cinnamon Roll",
"profiles": { "cursorColor": "#FFFFFD",
"defaults": { "selectionBackground": "#FFFFFF",
"font": {
"face": "Zamora Code"
}
},
"list": [
{
"font": { "face": "Cascadia Code" },
"guid": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
"name": "HowettShell"
},
{
"hidden": true,
"name": "BhojwaniShell"
},
{
"antialiasingMode": "aliased",
"name": "NiksaShell"
}
]
},
"schemes": [
{
"name": "Cinnamon Roll",
"cursorColor": "#FFFFFD", "background": "#3C0315",
"selectionBackground": "#FFFFFF", "foreground": "#FFFFFD",
"background": "#3C0315", "black": "#282A2E",
"foreground": "#FFFFFD", "blue": "#0170C5",
"cyan": "#3F8D83",
"green": "#76AB23",
"purple": "#7D498F",
"red": "#BD0940",
"white": "#FFFFFD",
"yellow": "#E0DE48",
"brightBlack": "#676E7A",
"brightBlue": "#5C98C5",
"brightCyan": "#8ABEB7",
"brightGreen": "#B5D680",
"brightPurple": "#AC79BB",
"brightRed": "#BD6D85",
"brightWhite": "#FFFFFD",
"brightYellow": "#FFFD76"
}
],
"actions": [
{ "command": { "action": "sendInput", "input": "VT Griese Mode" }, "keys": "ctrl+k" }
]
})" };
"black": "#282A2E", const auto settings{ winrt::make_self<implementation::CascadiaSettings>(settingsString) };
"blue": "#0170C5",
"cyan": "#3F8D83",
"green": "#76AB23",
"purple": "#7D498F",
"red": "#BD0940",
"white": "#FFFFFD",
"yellow": "#E0DE48",
"brightBlack": "#676E7A",
"brightBlue": "#5C98C5",
"brightCyan": "#8ABEB7",
"brightGreen": "#B5D680",
"brightPurple": "#AC79BB",
"brightRed": "#BD6D85",
"brightWhite": "#FFFFFD",
"brightYellow": "#FFFD76"
}
],
"actions": [
{ "command": { "action": "renameTab", "title": "Liang Tab" }, "keys": "ctrl+t" },
{ "command": { "action": "sendInput", "input": "VT Griese Mode" }, "keys": "ctrl+k" },
{ "command": { "action": "renameWindow", "name": "Hecker Window" }, "keys": "ctrl+l" }
]
})" };
auto settings{ winrt::make_self<implementation::CascadiaSettings>(false) };
settings->_ParseJsonString(settingsString, false);
settings->_ApplyDefaultsFromUserSettings();
settings->LayerJson(settings->_userSettings);
settings->_ValidateSettings();
const auto result{ settings->ToJson() }; const auto result{ settings->ToJson() };
VERIFY_ARE_EQUAL(toString(settings->_userSettings), toString(result)); VERIFY_ARE_EQUAL(toString(VerifyParseSucceeded(settingsString)), toString(result));
} }
void SerializationTests::LegacyFontSettings() void SerializationTests::LegacyFontSettings()

View file

@ -98,10 +98,10 @@
<!-- From Microsoft.UI.Xaml.targets --> <!-- From Microsoft.UI.Xaml.targets -->
<Native-Platform Condition="'$(Platform)' == 'Win32'">x86</Native-Platform> <Native-Platform Condition="'$(Platform)' == 'Win32'">x86</Native-Platform>
<Native-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</Native-Platform> <Native-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</Native-Platform>
<_MUXBinRoot>&quot;$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\runtimes\win10-$(Native-Platform)\native\&quot;</_MUXBinRoot> <_MUXBinRoot>&quot;$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\runtimes\win10-$(Native-Platform)\native\&quot;</_MUXBinRoot>
</PropertyGroup> </PropertyGroup>
<!-- We actually can just straight up reference MUX here, it's fine --> <!-- We actually can just straight up reference MUX here, it's fine -->
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" /> <Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
</Project> </Project>

View file

@ -62,7 +62,7 @@ namespace SettingsModelLocalTests
void TerminalSettingsTests::TestTerminalArgsForBinding() void TerminalSettingsTests::TestTerminalArgsForBinding()
{ {
const std::string settingsJson{ R"( static constexpr std::string_view settingsJson{ R"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": { "list": [ "profiles": { "list": [
@ -106,12 +106,12 @@ namespace SettingsModelLocalTests
const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") }; const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") };
const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") }; const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") };
CascadiaSettings settings{ til::u8u16(settingsJson) }; const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
auto actionMap = settings.GlobalSettings().ActionMap(); auto actionMap = settings->GlobalSettings().ActionMap();
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(3u, settings->ActiveProfiles().Size());
const auto profile2Guid = settings.ActiveProfiles().GetAt(2).Guid(); const auto profile2Guid = settings->ActiveProfiles().GetAt(2).Guid();
VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid); VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid);
const auto& actionMapImpl{ winrt::get_self<implementation::ActionMap>(actionMap) }; const auto& actionMapImpl{ winrt::get_self<implementation::ActionMap>(actionMap) };
@ -131,8 +131,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid()); VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@ -153,8 +153,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid()); VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
@ -175,8 +175,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid()); VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline());
@ -197,8 +197,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid()); VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
@ -219,13 +219,13 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline()); VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
if constexpr (Feature_ShowProfileDefaultsInSettings::IsEnabled()) if constexpr (Feature_ShowProfileDefaultsInSettings::IsEnabled())
{ {
// This action specified a command but no profile; it gets reassigned to the base profile // This action specified a command but no profile; it gets reassigned to the base profile
VERIFY_ARE_EQUAL(settings.ProfileDefaults(), profile); VERIFY_ARE_EQUAL(settings->ProfileDefaults(), profile);
VERIFY_ARE_EQUAL(29, termSettings.HistorySize()); VERIFY_ARE_EQUAL(29, termSettings.HistorySize());
} }
else else
@ -251,8 +251,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline()); VERIFY_ARE_EQUAL(L"foo.exe", realArgs.TerminalArgs().Commandline());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid()); VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline());
@ -271,8 +271,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid()); VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@ -292,8 +292,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory()); VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid()); VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@ -315,8 +315,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory()); VERIFY_ARE_EQUAL(L"c:\\foo", realArgs.TerminalArgs().StartingDirectory());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid()); VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
@ -337,8 +337,8 @@ namespace SettingsModelLocalTests
VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle()); VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid0, profile.Guid()); VERIFY_ARE_EQUAL(guid0, profile.Guid());
VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline());
@ -360,8 +360,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle()); VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(profile2Guid, profile.Guid()); VERIFY_ARE_EQUAL(profile2Guid, profile.Guid());
VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline());
@ -385,8 +385,8 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle()); VERIFY_ARE_EQUAL(L"bar", realArgs.TerminalArgs().TabTitle());
VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile());
const auto profile{ settings.GetProfileForArgs(realArgs.TerminalArgs()) }; const auto profile{ settings->GetProfileForArgs(realArgs.TerminalArgs()) };
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, realArgs.TerminalArgs(), nullptr) };
const auto termSettings = settingsStruct.DefaultSettings(); const auto termSettings = settingsStruct.DefaultSettings();
VERIFY_ARE_EQUAL(guid1, profile.Guid()); VERIFY_ARE_EQUAL(guid1, profile.Guid());
VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(L"foo.exe", termSettings.Commandline());
@ -399,7 +399,7 @@ namespace SettingsModelLocalTests
void TerminalSettingsTests::MakeSettingsForProfile() void TerminalSettingsTests::MakeSettingsForProfile()
{ {
// Test that making settings generally works. // Test that making settings generally works.
const std::string settingsString{ R"( static constexpr std::string_view settingsString{ R"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -415,17 +415,17 @@ namespace SettingsModelLocalTests
} }
] ]
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsString) }; const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsString);
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
const auto guid2 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}"); const auto guid2 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}");
const auto profile1 = settings.FindProfile(guid1); const auto profile1 = settings->FindProfile(guid1);
const auto profile2 = settings.FindProfile(guid2); const auto profile2 = settings->FindProfile(guid2);
try try
{ {
auto terminalSettings{ TerminalSettings::CreateWithProfile(settings, profile1, nullptr) }; auto terminalSettings{ TerminalSettings::CreateWithProfile(*settings, profile1, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings); VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings);
VERIFY_ARE_EQUAL(1, terminalSettings.DefaultSettings().HistorySize()); VERIFY_ARE_EQUAL(1, terminalSettings.DefaultSettings().HistorySize());
} }
@ -436,7 +436,7 @@ namespace SettingsModelLocalTests
try try
{ {
auto terminalSettings{ TerminalSettings::CreateWithProfile(settings, profile2, nullptr) }; auto terminalSettings{ TerminalSettings::CreateWithProfile(*settings, profile2, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings); VERIFY_ARE_NOT_EQUAL(nullptr, terminalSettings);
VERIFY_ARE_EQUAL(2, terminalSettings.DefaultSettings().HistorySize()); VERIFY_ARE_EQUAL(2, terminalSettings.DefaultSettings().HistorySize());
} }
@ -447,7 +447,7 @@ namespace SettingsModelLocalTests
try try
{ {
const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(settings, nullptr, nullptr) }; const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(*settings, nullptr, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, termSettings); VERIFY_ARE_NOT_EQUAL(nullptr, termSettings);
VERIFY_ARE_EQUAL(1, termSettings.DefaultSettings().HistorySize()); VERIFY_ARE_EQUAL(1, termSettings.DefaultSettings().HistorySize());
} }
@ -463,7 +463,7 @@ namespace SettingsModelLocalTests
// defaultProfile that's not in the list, we validate the settings, and // defaultProfile that's not in the list, we validate the settings, and
// then call MakeSettings(nullopt). The validation should ensure that // then call MakeSettings(nullopt). The validation should ensure that
// the default profile is something reasonable // the default profile is something reasonable
const std::string settingsString{ R"( static constexpr std::string_view settingsString{ R"(
{ {
"defaultProfile": "{6239a42c-3333-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -479,14 +479,14 @@ namespace SettingsModelLocalTests
} }
] ]
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsString) }; const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsString);
VERIFY_ARE_EQUAL(2u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(2u, settings->Warnings().Size());
VERIFY_ARE_EQUAL(2u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(2u, settings->ActiveProfiles().Size());
VERIFY_ARE_EQUAL(settings.GlobalSettings().DefaultProfile(), settings.ActiveProfiles().GetAt(0).Guid()); VERIFY_ARE_EQUAL(settings->GlobalSettings().DefaultProfile(), settings->ActiveProfiles().GetAt(0).Guid());
try try
{ {
const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(settings, nullptr, nullptr) }; const auto termSettings{ TerminalSettings::CreateWithNewTerminalArgs(*settings, nullptr, nullptr) };
VERIFY_ARE_NOT_EQUAL(nullptr, termSettings); VERIFY_ARE_NOT_EQUAL(nullptr, termSettings);
VERIFY_ARE_EQUAL(1, termSettings.DefaultSettings().HistorySize()); VERIFY_ARE_EQUAL(1, termSettings.DefaultSettings().HistorySize());
} }
@ -501,7 +501,7 @@ namespace SettingsModelLocalTests
Log::Comment(NoThrowString().Format( Log::Comment(NoThrowString().Format(
L"Ensure that setting (or not) a property in the profile that should override a property of the color scheme works correctly.")); L"Ensure that setting (or not) a property in the profile that should override a property of the color scheme works correctly."));
const std::string settings0String{ R"( static constexpr std::string_view settings0String{ R"(
{ {
"defaultProfile": "profile5", "defaultProfile": "profile5",
"profiles": [ "profiles": [
@ -534,18 +534,50 @@ namespace SettingsModelLocalTests
"schemes": [ "schemes": [
{ {
"name": "schemeWithCursorColor", "name": "schemeWithCursorColor",
"cursorColor": "#123456" "cursorColor": "#123456",
"black": "#121314",
"red": "#121314",
"green": "#121314",
"yellow": "#121314",
"blue": "#121314",
"purple": "#121314",
"cyan": "#121314",
"white": "#121314",
"brightBlack": "#121314",
"brightRed": "#121314",
"brightGreen": "#121314",
"brightYellow": "#121314",
"brightBlue": "#121314",
"brightPurple": "#121314",
"brightCyan": "#121314",
"brightWhite": "#121314"
}, },
{ {
"name": "schemeWithoutCursorColor" "name": "schemeWithoutCursorColor",
"black": "#121314",
"red": "#121314",
"green": "#121314",
"yellow": "#121314",
"blue": "#121314",
"purple": "#121314",
"cyan": "#121314",
"white": "#121314",
"brightBlack": "#121314",
"brightRed": "#121314",
"brightGreen": "#121314",
"brightYellow": "#121314",
"brightBlue": "#121314",
"brightPurple": "#121314",
"brightCyan": "#121314",
"brightWhite": "#121314"
} }
] ]
})" }; })" };
CascadiaSettings settings{ til::u8u16(settings0String) }; const auto settings = winrt::make_self<implementation::CascadiaSettings>(settings0String);
VERIFY_ARE_EQUAL(6u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(6u, settings->ActiveProfiles().Size());
VERIFY_ARE_EQUAL(2u, settings.GlobalSettings().ColorSchemes().Size()); VERIFY_ARE_EQUAL(2u, settings->GlobalSettings().ColorSchemes().Size());
auto createTerminalSettings = [&](const auto& profile, const auto& schemes) { auto createTerminalSettings = [&](const auto& profile, const auto& schemes) {
auto terminalSettings{ winrt::make_self<implementation::TerminalSettings>() }; auto terminalSettings{ winrt::make_self<implementation::TerminalSettings>() };
@ -554,12 +586,14 @@ namespace SettingsModelLocalTests
return terminalSettings; return terminalSettings;
}; };
auto terminalSettings0 = createTerminalSettings(settings.ActiveProfiles().GetAt(0), settings.GlobalSettings().ColorSchemes()); const auto activeProfiles = settings->ActiveProfiles();
auto terminalSettings1 = createTerminalSettings(settings.ActiveProfiles().GetAt(1), settings.GlobalSettings().ColorSchemes()); const auto colorSchemes = settings->GlobalSettings().ColorSchemes();
auto terminalSettings2 = createTerminalSettings(settings.ActiveProfiles().GetAt(2), settings.GlobalSettings().ColorSchemes()); const auto terminalSettings0 = createTerminalSettings(activeProfiles.GetAt(0), colorSchemes);
auto terminalSettings3 = createTerminalSettings(settings.ActiveProfiles().GetAt(3), settings.GlobalSettings().ColorSchemes()); const auto terminalSettings1 = createTerminalSettings(activeProfiles.GetAt(1), colorSchemes);
auto terminalSettings4 = createTerminalSettings(settings.ActiveProfiles().GetAt(4), settings.GlobalSettings().ColorSchemes()); const auto terminalSettings2 = createTerminalSettings(activeProfiles.GetAt(2), colorSchemes);
auto terminalSettings5 = createTerminalSettings(settings.ActiveProfiles().GetAt(5), settings.GlobalSettings().ColorSchemes()); const auto terminalSettings3 = createTerminalSettings(activeProfiles.GetAt(3), colorSchemes);
const auto terminalSettings4 = createTerminalSettings(activeProfiles.GetAt(4), colorSchemes);
const auto terminalSettings5 = createTerminalSettings(activeProfiles.GetAt(5), colorSchemes);
VERIFY_ARE_EQUAL(ARGB(0, 0x12, 0x34, 0x56), terminalSettings0->CursorColor()); // from color scheme VERIFY_ARE_EQUAL(ARGB(0, 0x12, 0x34, 0x56), terminalSettings0->CursorColor()); // from color scheme
VERIFY_ARE_EQUAL(DEFAULT_CURSOR_COLOR, terminalSettings1->CursorColor()); // default VERIFY_ARE_EQUAL(DEFAULT_CURSOR_COLOR, terminalSettings1->CursorColor()); // default
@ -571,7 +605,7 @@ namespace SettingsModelLocalTests
void TerminalSettingsTests::TestCommandlineToTitlePromotion() void TerminalSettingsTests::TestCommandlineToTitlePromotion()
{ {
const std::string settingsJson{ R"( static constexpr std::string_view settingsJson{ R"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": { "list": [ "profiles": { "list": [
@ -587,65 +621,63 @@ namespace SettingsModelLocalTests
} } } }
})" }; })" };
const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") }; const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
CascadiaSettings settings{ til::u8u16(settingsJson) };
{ // just a profile (profile wins) { // just a profile (profile wins)
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Profile(L"profile0"); args.Profile(L"profile0");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"profile0", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"profile0", settingsStruct.DefaultSettings().StartingTitle());
} }
{ // profile and command line -> no promotion (profile wins) { // profile and command line -> no promotion (profile wins)
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Profile(L"profile0"); args.Profile(L"profile0");
args.Commandline(L"foo.exe"); args.Commandline(L"foo.exe");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"profile0", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"profile0", settingsStruct.DefaultSettings().StartingTitle());
} }
{ // just a title -> it is propagated { // just a title -> it is propagated
NewTerminalArgs args{}; NewTerminalArgs args{};
args.TabTitle(L"Analog Kid"); args.TabTitle(L"Analog Kid");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"Analog Kid", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"Analog Kid", settingsStruct.DefaultSettings().StartingTitle());
} }
{ // title and command line -> no promotion { // title and command line -> no promotion
NewTerminalArgs args{}; NewTerminalArgs args{};
args.TabTitle(L"Digital Man"); args.TabTitle(L"Digital Man");
args.Commandline(L"foo.exe"); args.Commandline(L"foo.exe");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"Digital Man", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"Digital Man", settingsStruct.DefaultSettings().StartingTitle());
} }
{ // just a commandline -> promotion { // just a commandline -> promotion
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Commandline(L"foo.exe"); args.Commandline(L"foo.exe");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"foo.exe", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"foo.exe", settingsStruct.DefaultSettings().StartingTitle());
} }
// various typesof commandline follow // various typesof commandline follow
{ {
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Commandline(L"foo.exe bar"); args.Commandline(L"foo.exe bar");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"foo.exe", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"foo.exe", settingsStruct.DefaultSettings().StartingTitle());
} }
{ {
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Commandline(L"\"foo exe.exe\" bar"); args.Commandline(L"\"foo exe.exe\" bar");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"foo exe.exe", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"foo exe.exe", settingsStruct.DefaultSettings().StartingTitle());
} }
{ {
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Commandline(L"\"\" grand designs"); args.Commandline(L"\"\" grand designs");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"", settingsStruct.DefaultSettings().StartingTitle());
} }
{ {
NewTerminalArgs args{}; NewTerminalArgs args{};
args.Commandline(L" imagine a man"); args.Commandline(L" imagine a man");
const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(settings, args, nullptr) }; const auto settingsStruct{ TerminalSettings::CreateWithNewTerminalArgs(*settings, args, nullptr) };
VERIFY_ARE_EQUAL(L"", settingsStruct.DefaultSettings().StartingTitle()); VERIFY_ARE_EQUAL(L"", settingsStruct.DefaultSettings().StartingTitle());
} }
} }

View file

@ -79,7 +79,7 @@ namespace TerminalAppLocalTests
// containing a ${profile.name} to replace. When we expand it, it should // containing a ${profile.name} to replace. When we expand it, it should
// have created one command for each profile. // have created one command for each profile.
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -111,10 +111,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}"); CascadiaSettings settings{ settingsJson, {} };
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
CascadiaSettings settings{ til::u8u16(settingsJson) };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
@ -207,7 +204,7 @@ namespace TerminalAppLocalTests
// For this test, put an iterable command without a given `name` to // For this test, put an iterable command without a given `name` to
// replace. When we expand it, it should still work. // replace. When we expand it, it should still work.
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -238,10 +235,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}"); CascadiaSettings settings{ settingsJson, {} };
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
CascadiaSettings settings{ til::u8u16(settingsJson) };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
@ -335,7 +329,7 @@ namespace TerminalAppLocalTests
// cause bad json to be filled in. Something like a profile with a name // cause bad json to be filled in. Something like a profile with a name
// of "Foo\"", so the trailing '"' might break the json parsing. // of "Foo\"", so the trailing '"' might break the json parsing.
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -367,10 +361,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
const auto guid0 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}"); CascadiaSettings settings{ settingsJson, {} };
const auto guid1 = ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
CascadiaSettings settings{ til::u8u16(settingsJson) };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
@ -468,7 +459,7 @@ namespace TerminalAppLocalTests
// ├─ first.com // ├─ first.com
// └─ second.com // └─ second.com
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -508,7 +499,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsJson) }; CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@ -558,7 +549,7 @@ namespace TerminalAppLocalTests
// ├─ child1 // ├─ child1
// └─ child2 // └─ child2
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -603,7 +594,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsJson) }; CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@ -691,7 +682,7 @@ namespace TerminalAppLocalTests
// ├─ Split pane, direction: right, profile: profile2 // ├─ Split pane, direction: right, profile: profile2
// └─ Split pane, direction: down, profile: profile2 // └─ Split pane, direction: down, profile: profile2
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -727,7 +718,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsJson) }; CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@ -828,7 +819,7 @@ namespace TerminalAppLocalTests
// ├─ Profile 2 // ├─ Profile 2
// └─ Profile 3 // └─ Profile 3
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -864,7 +855,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsJson) }; CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@ -926,7 +917,7 @@ namespace TerminalAppLocalTests
// ├─ Split right // ├─ Split right
// └─ Split down // └─ Split down
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -967,7 +958,7 @@ namespace TerminalAppLocalTests
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsJson) }; CascadiaSettings settings{ settingsJson, {} };
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
@ -1071,7 +1062,7 @@ namespace TerminalAppLocalTests
// containing a ${profile.name} to replace. When we expand it, it should // containing a ${profile.name} to replace. When we expand it, it should
// have created one command for each profile. // have created one command for each profile.
const std::string settingsJson{ R"( static constexpr std::wstring_view settingsJson{ LR"(
{ {
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -1107,7 +1098,7 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
CascadiaSettings settings{ til::u8u16(settingsJson) }; CascadiaSettings settings{ settingsJson, {} };
// Since at least one profile does not reference a color scheme, // Since at least one profile does not reference a color scheme,
// we add a warning saying "the color scheme is unknown" // we add a warning saying "the color scheme is unknown"

View file

@ -311,7 +311,7 @@ namespace TerminalAppLocalTests
// TerminalPage and not only create them successfully, but also create a // TerminalPage and not only create them successfully, but also create a
// tab using those settings successfully. // tab using those settings successfully.
const std::string settingsJson0{ R"( static constexpr std::wstring_view settingsJson0{ LR"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -328,7 +328,7 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) }; CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0); VERIFY_IS_NOT_NULL(settings0);
// This is super wacky, but we can't just initialize the // This is super wacky, but we can't just initialize the
@ -357,7 +357,7 @@ namespace TerminalAppLocalTests
// //
// Created to test GH#2455 // Created to test GH#2455
const std::string settingsJson0{ R"( static constexpr std::wstring_view settingsJson0{ LR"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -374,7 +374,7 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
const std::string settingsJson1{ R"( static constexpr std::wstring_view settingsJson1{ LR"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -386,10 +386,10 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) }; CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0); VERIFY_IS_NOT_NULL(settings0);
CascadiaSettings settings1{ til::u8u16(settingsJson1) }; CascadiaSettings settings1{ settingsJson1, {} };
VERIFY_IS_NOT_NULL(settings1); VERIFY_IS_NOT_NULL(settings1);
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
@ -444,7 +444,7 @@ namespace TerminalAppLocalTests
// //
// Created to test GH#2455 // Created to test GH#2455
const std::string settingsJson0{ R"( static constexpr std::wstring_view settingsJson0{ LR"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -461,7 +461,7 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
const std::string settingsJson1{ R"( static constexpr std::wstring_view settingsJson1{ LR"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"profiles": [ "profiles": [
@ -473,10 +473,10 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) }; CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0); VERIFY_IS_NOT_NULL(settings0);
CascadiaSettings settings1{ til::u8u16(settingsJson1) }; CascadiaSettings settings1{ settingsJson1, {} };
VERIFY_IS_NOT_NULL(settings1); VERIFY_IS_NOT_NULL(settings1);
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");
@ -558,7 +558,7 @@ namespace TerminalAppLocalTests
// - The initialized TerminalPage, ready to use. // - The initialized TerminalPage, ready to use.
winrt::com_ptr<winrt::TerminalApp::implementation::TerminalPage> TabTests::_commonSetup() winrt::com_ptr<winrt::TerminalApp::implementation::TerminalPage> TabTests::_commonSetup()
{ {
const std::string settingsJson0{ R"( static constexpr std::wstring_view settingsJson0{ LR"(
{ {
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", "defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"showTabsInTitlebar": false, "showTabsInTitlebar": false,
@ -659,7 +659,7 @@ namespace TerminalAppLocalTests
] ]
})" }; })" };
CascadiaSettings settings0{ til::u8u16(settingsJson0) }; CascadiaSettings settings0{ settingsJson0, {} };
VERIFY_IS_NOT_NULL(settings0); VERIFY_IS_NOT_NULL(settings0);
const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}"); const auto guid1 = Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}");

View file

@ -92,11 +92,11 @@
<!-- From Microsoft.UI.Xaml.targets --> <!-- From Microsoft.UI.Xaml.targets -->
<Native-Platform Condition="'$(Platform)' == 'Win32'">x86</Native-Platform> <Native-Platform Condition="'$(Platform)' == 'Win32'">x86</Native-Platform>
<Native-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</Native-Platform> <Native-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</Native-Platform>
<_MUXBinRoot>&quot;$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\runtimes\win10-$(Native-Platform)\native\&quot;</_MUXBinRoot> <_MUXBinRoot>&quot;$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\runtimes\win10-$(Native-Platform)\native\&quot;</_MUXBinRoot>
</PropertyGroup> </PropertyGroup>
<!-- We actually can just straight up reference MUX here, it's fine --> <!-- We actually can just straight up reference MUX here, it's fine -->
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" /> <Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" /> <Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
</Project> </Project>

View file

@ -123,7 +123,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<Import Project="$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" /> <Import Project="$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="$(OpenConsoleDir)\src\common.build.post.props" /> <Import Project="$(OpenConsoleDir)\src\common.build.post.props" />

View file

@ -50,6 +50,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// - Add the given peasant to the list of peasants we're tracking. This // - Add the given peasant to the list of peasants we're tracking. This
// Peasant may have already been assigned an ID. If it hasn't, then give // Peasant may have already been assigned an ID. If it hasn't, then give
// it an ID. // it an ID.
// - NB: this takes a unique_lock on _peasantsMutex.
// Arguments: // Arguments:
// - peasant: the new Peasant to track. // - peasant: the new Peasant to track.
// Return Value: // Return Value:
@ -71,10 +72,24 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
{ {
// Peasant already had an ID (from an older monarch). Leave that one // Peasant already had an ID (from an older monarch). Leave that one
// be. Make sure that the next peasant's ID is higher than it. // be. Make sure that the next peasant's ID is higher than it.
_nextPeasantID = providedID >= _nextPeasantID ? providedID + 1 : _nextPeasantID; // If multiple peasants are added concurrently we keep trying to update
// until we get to set the new id.
uint64_t current;
do
{
current = _nextPeasantID.load(std::memory_order_relaxed);
} while (current <= providedID && !_nextPeasantID.compare_exchange_weak(current, providedID + 1, std::memory_order_relaxed));
} }
auto newPeasantsId = peasant.GetID(); auto newPeasantsId = peasant.GetID();
// Keep track of which peasant we are
// SAFETY: this is only true for one peasant, and each peasant
// is only added to a monarch once, so we do not need synchronization here.
if (peasant.GetPID() == _ourPID)
{
_ourPeasantId = newPeasantsId;
}
// Add an event listener to the peasant's WindowActivated event. // Add an event listener to the peasant's WindowActivated event.
peasant.WindowActivated({ this, &Monarch::_peasantWindowActivated }); peasant.WindowActivated({ this, &Monarch::_peasantWindowActivated });
peasant.IdentifyWindowsRequested({ this, &Monarch::_identifyWindows }); peasant.IdentifyWindowsRequested({ this, &Monarch::_identifyWindows });
@ -84,7 +99,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
peasant.HideNotificationIconRequested([this](auto&&, auto&&) { _HideNotificationIconRequestedHandlers(*this, nullptr); }); peasant.HideNotificationIconRequested([this](auto&&, auto&&) { _HideNotificationIconRequestedHandlers(*this, nullptr); });
peasant.QuitAllRequested({ this, &Monarch::_handleQuitAll }); peasant.QuitAllRequested({ this, &Monarch::_handleQuitAll });
_peasants[newPeasantsId] = peasant; {
std::unique_lock lock{ _peasantsMutex };
_peasants[newPeasantsId] = peasant;
}
TraceLoggingWrite(g_hRemotingProvider, TraceLoggingWrite(g_hRemotingProvider,
"Monarch_AddPeasant", "Monarch_AddPeasant",
@ -124,9 +142,15 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// closing all windows. // closing all windows.
_QuitAllRequestedHandlers(*this, nullptr); _QuitAllRequestedHandlers(*this, nullptr);
_quitting.store(true);
// Tell all peasants to exit. // Tell all peasants to exit.
const auto callback = [&](const auto& /*id*/, const auto& p) { const auto callback = [&](const auto& id, const auto& p) {
p.Quit(); // We want to tell our peasant to quit last, so that we don't try
// to perform a bunch of elections on quit.
if (id != _ourPeasantId)
{
p.Quit();
}
}; };
const auto onError = [&](const auto& id) { const auto onError = [&](const auto& id) {
TraceLoggingWrite(g_hRemotingProvider, TraceLoggingWrite(g_hRemotingProvider,
@ -137,18 +161,46 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
}; };
_forEachPeasant(callback, onError); _forEachPeasant(callback, onError);
{
std::shared_lock lock{ _peasantsMutex };
const auto peasantSearch = _peasants.find(_ourPeasantId);
if (peasantSearch != _peasants.end())
{
peasantSearch->second.Quit();
}
else
{
// Somehow we don't have our own peasant, this should never happen.
// We are trying to quit anyways so just fail here.
assert(peasantSearch != _peasants.end());
}
}
} }
// Method Description: // Method Description:
// - Tells the monarch that a peasant is being closed. // - Tells the monarch that a peasant is being closed.
// - NB: this (separately) takes unique locks on _peasantsMutex and
// _mruPeasantsMutex.
// Arguments: // Arguments:
// - peasantId: the id of the peasant // - peasantId: the id of the peasant
// Return Value: // Return Value:
// - <none> // - <none>
void Monarch::SignalClose(const uint64_t peasantId) void Monarch::SignalClose(const uint64_t peasantId)
{ {
_clearOldMruEntries(peasantId); // If we are quitting we don't care about maintaining our list of
_peasants.erase(peasantId); // peasants anymore, and don't need to notify the host that something
// changed.
if (_quitting.load(std::memory_order_acquire))
{
return;
}
_clearOldMruEntries({ peasantId });
{
std::unique_lock lock{ _peasantsMutex };
_peasants.erase(peasantId);
}
_WindowClosedHandlers(nullptr, nullptr); _WindowClosedHandlers(nullptr, nullptr);
} }
@ -160,23 +212,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// - the number of active peasants. // - the number of active peasants.
uint64_t Monarch::GetNumberOfPeasants() uint64_t Monarch::GetNumberOfPeasants()
{ {
auto num = 0; std::shared_lock lock{ _peasantsMutex };
auto callback = [&](const auto& /*id*/, const auto& p) { return _peasants.size();
// Check that the peasant is alive, and if so increment the count
p.GetID();
num += 1;
};
auto onError = [](const auto& id) {
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_GetNumberOfPeasants_Failed",
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not enumerate"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
};
_forEachPeasant(callback, onError);
return num;
} }
// Method Description: // Method Description:
@ -197,16 +234,25 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// Method Description: // Method Description:
// - Lookup a peasant by its ID. If the peasant has died, this will also // - Lookup a peasant by its ID. If the peasant has died, this will also
// remove the peasant from our list of peasants. // remove the peasant from our list of peasants.
// - NB: this (separately) takes unique locks on _peasantsMutex and
// _mruPeasantsMutex.
// Arguments: // Arguments:
// - peasantID: The ID Of the peasant to find // - peasantID: The ID Of the peasant to find
// - clearMruPeasantOnFailure: When true this function will handle clearing
// from _mruPeasants if a peasant was not found, otherwise the caller is
// expected to handle that cleanup themselves.
// Return Value: // Return Value:
// - the peasant if it exists in our map, otherwise null // - the peasant if it exists in our map, otherwise null
Remoting::IPeasant Monarch::_getPeasant(uint64_t peasantID) Remoting::IPeasant Monarch::_getPeasant(uint64_t peasantID, bool clearMruPeasantOnFailure)
{ {
try try
{ {
const auto peasantSearch = _peasants.find(peasantID); IPeasant maybeThePeasant = nullptr;
auto maybeThePeasant = peasantSearch == _peasants.end() ? nullptr : peasantSearch->second; {
std::shared_lock lock{ _peasantsMutex };
const auto peasantSearch = _peasants.find(peasantID);
maybeThePeasant = peasantSearch == _peasants.end() ? nullptr : peasantSearch->second;
}
// Ask the peasant for their PID. This will validate that they're // Ask the peasant for their PID. This will validate that they're
// actually still alive. // actually still alive.
if (maybeThePeasant) if (maybeThePeasant)
@ -218,12 +264,19 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
catch (...) catch (...)
{ {
LOG_CAUGHT_EXCEPTION(); LOG_CAUGHT_EXCEPTION();
// Remove the peasant from the list of peasants
_peasants.erase(peasantID);
// Remove the peasant from the list of MRU windows. They're dead. // Remove the peasant from the list of peasants
// They can't be the MRU anymore. {
_clearOldMruEntries(peasantID); std::unique_lock lock{ _peasantsMutex };
_peasants.erase(peasantID);
}
if (clearMruPeasantOnFailure)
{
// Remove the peasant from the list of MRU windows. They're dead.
// They can't be the MRU anymore.
_clearOldMruEntries({ peasantID });
}
return nullptr; return nullptr;
} }
} }
@ -244,39 +297,27 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
return 0; return 0;
} }
std::vector<uint64_t> peasantsToErase{};
uint64_t result = 0; uint64_t result = 0;
for (const auto& [id, p] : _peasants)
{
try
{
auto otherName = p.WindowName();
if (otherName == name)
{
result = id;
break;
}
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
// Normally, we'd just erase the peasant here. However, we can't
// erase from the map while we're iterating over it like this.
// Instead, pull a good ole Java and collect this id for removal
// later.
peasantsToErase.push_back(id);
}
}
// Remove the dead peasants we came across while iterating. const auto callback = [&](const auto& id, const auto& p) {
for (const auto& id : peasantsToErase) auto otherName = p.WindowName();
{ if (otherName == name)
// Remove the peasant from the list of peasants {
_peasants.erase(id); result = id;
// Remove the peasant from the list of MRU windows. They're dead. return false;
// They can't be the MRU anymore. }
_clearOldMruEntries(id); return true;
} };
const auto onError = [&](const auto& id) {
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_lookupPeasantIdForName_Failed",
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not get the name of"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
};
_forEachPeasant(callback, onError);
TraceLoggingWrite(g_hRemotingProvider, TraceLoggingWrite(g_hRemotingProvider,
"Monarch_lookupPeasantIdForName", "Monarch_lookupPeasantIdForName",
@ -328,33 +369,42 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// - Helper for removing a peasant from the list of MRU peasants. We want to // - Helper for removing a peasant from the list of MRU peasants. We want to
// do this both when the peasant dies, and also when the peasant is newly // do this both when the peasant dies, and also when the peasant is newly
// activated (so that we don't leave an old entry for it in the list). // activated (so that we don't leave an old entry for it in the list).
// - NB: This takes a unique lock on _mruPeasantsMutex.
// Arguments: // Arguments:
// - peasantID: The ID of the peasant to remove from the MRU list // - peasantIds: The list of peasant IDs to remove from the MRU list
// Return Value: // Return Value:
// - <none> // - <none>
void Monarch::_clearOldMruEntries(const uint64_t peasantID) void Monarch::_clearOldMruEntries(const std::unordered_set<uint64_t>& peasantIds)
{ {
auto result = std::find_if(_mruPeasants.begin(), if (peasantIds.size() == 0)
_mruPeasants.end(),
[peasantID](auto&& other) {
return peasantID == other.PeasantID();
});
if (result != std::end(_mruPeasants))
{ {
TraceLoggingWrite(g_hRemotingProvider, return;
"Monarch_RemovedPeasantFromDesktop",
TraceLoggingUInt64(peasantID, "peasantID", "The ID of the peasant"),
TraceLoggingGuid(result->DesktopID(), "desktopGuid", "The GUID of the previous desktop the window was on"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
_mruPeasants.erase(result);
} }
std::unique_lock lock{ _mruPeasantsMutex };
auto partition = std::remove_if(_mruPeasants.begin(), _mruPeasants.end(), [&](const auto& p) {
const auto id = p.PeasantID();
// remove the element if it was found in the list to erase.
if (peasantIds.count(id) == 1)
{
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_RemovedPeasantFromDesktop",
TraceLoggingUInt64(id, "peasantID", "The ID of the peasant"),
TraceLoggingGuid(p.DesktopID(), "desktopGuid", "The GUID of the previous desktop the window was on"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
return true;
}
return false;
});
// Remove everything that was in the list
_mruPeasants.erase(partition, _mruPeasants.end());
} }
// Method Description: // Method Description:
// - Actually handle inserting the WindowActivatedArgs into our list of MRU windows. // - Actually handle inserting the WindowActivatedArgs into our list of MRU windows.
// - NB: this takes a unique_lock on _mruPeasantsMutex.
// Arguments: // Arguments:
// - localArgs: an in-proc WindowActivatedArgs that we should add to our list of MRU windows. // - localArgs: an in-proc WindowActivatedArgs that we should add to our list of MRU windows.
// Return Value: // Return Value:
@ -365,19 +415,22 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// * Check all the current lists to look for this peasant. // * Check all the current lists to look for this peasant.
// remove it from any where it exists. // remove it from any where it exists.
_clearOldMruEntries(localArgs->PeasantID()); _clearOldMruEntries({ localArgs->PeasantID() });
// * If the current desktop doesn't have a vector, add one. // * If the current desktop doesn't have a vector, add one.
const auto desktopGuid{ localArgs->DesktopID() }; const auto desktopGuid{ localArgs->DesktopID() };
// * Add this args list. By using lower_bound with insert, we can get it {
// into exactly the right spot, without having to re-sort the whole std::unique_lock lock{ _mruPeasantsMutex };
// array. // * Add this args list. By using lower_bound with insert, we can get it
_mruPeasants.insert(std::lower_bound(_mruPeasants.begin(), // into exactly the right spot, without having to re-sort the whole
_mruPeasants.end(), // array.
*localArgs, _mruPeasants.insert(std::lower_bound(_mruPeasants.begin(),
[](const auto& first, const auto& second) { return first.ActivatedTime() > second.ActivatedTime(); }), _mruPeasants.end(),
*localArgs); *localArgs,
[](const auto& first, const auto& second) { return first.ActivatedTime() > second.ActivatedTime(); }),
*localArgs);
}
TraceLoggingWrite(g_hRemotingProvider, TraceLoggingWrite(g_hRemotingProvider,
"Monarch_SetMostRecentPeasant", "Monarch_SetMostRecentPeasant",
@ -391,6 +444,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// Method Description: // Method Description:
// - Retrieves the ID of the MRU peasant window. If requested, will limit // - Retrieves the ID of the MRU peasant window. If requested, will limit
// the search to windows that are on the current desktop. // the search to windows that are on the current desktop.
// - NB: This method will hold a shared lock on _mruPeasantsMutex and
// potentially a unique_lock on _peasantsMutex at the same time.
// Separately it might hold a unique_lock on _mruPeasantsMutex.
// Arguments: // Arguments:
// - limitToCurrentDesktop: if true, only return the MRU peasant that's // - limitToCurrentDesktop: if true, only return the MRU peasant that's
// actually on the current desktop. // actually on the current desktop.
@ -403,8 +459,13 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// - the ID of the most recent peasant, otherwise 0 if we could not find one. // - the ID of the most recent peasant, otherwise 0 if we could not find one.
uint64_t Monarch::_getMostRecentPeasantID(const bool limitToCurrentDesktop, const bool ignoreQuakeWindow) uint64_t Monarch::_getMostRecentPeasantID(const bool limitToCurrentDesktop, const bool ignoreQuakeWindow)
{ {
std::shared_lock lock{ _mruPeasantsMutex };
if (_mruPeasants.empty()) if (_mruPeasants.empty())
{ {
// unlock the mruPeasants mutex to make sure we can't deadlock here.
lock.unlock();
// Only need a shared lock for read
std::shared_lock peasantsLock{ _peasantsMutex };
// We haven't yet been told the MRU peasant. Just use the first one. // We haven't yet been told the MRU peasant. Just use the first one.
// This is just gonna be a random one, but really shouldn't happen // This is just gonna be a random one, but really shouldn't happen
// in practice. The WindowManager should set the MRU peasant // in practice. The WindowManager should set the MRU peasant
@ -445,15 +506,17 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// - If it isn't on the current desktop, we'll loop again, on the // - If it isn't on the current desktop, we'll loop again, on the
// following peasant. // following peasant.
// * If we don't care, then we'll just return that one. // * If we don't care, then we'll just return that one.
// uint64_t result = 0;
// We're not just using an iterator because the contents of the list std::unordered_set<uint64_t> peasantsToErase{};
// might change while we're iterating here (if the peasant is dead we'll for (const auto& mruWindowArgs : _mruPeasants)
// remove it from the list).
int positionInList = 0;
while (_mruPeasants.cbegin() + positionInList < _mruPeasants.cend())
{ {
const auto mruWindowArgs{ *(_mruPeasants.begin() + positionInList) }; // Try to get the peasant, but do not have _getPeasant clean up old
const auto peasant{ _getPeasant(mruWindowArgs.PeasantID()) }; // _mruPeasants because we are iterating here.
// SAFETY: _getPeasant can take a unique_lock on _peasantsMutex if
// it detects a peasant is dead. Currently _getMostRecentPeasantId
// is the only method that holds a lock on both _mruPeasantsMutex and
// _peasantsMutex at the same time so there cannot be a deadlock here.
const auto peasant{ _getPeasant(mruWindowArgs.PeasantID(), false) };
if (!peasant) if (!peasant)
{ {
TraceLoggingWrite(g_hRemotingProvider, TraceLoggingWrite(g_hRemotingProvider,
@ -467,6 +530,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// We'll go through the loop again. We removed the current one // We'll go through the loop again. We removed the current one
// at positionInList, so the next one in positionInList will be // at positionInList, so the next one in positionInList will be
// a new, different peasant. // a new, different peasant.
peasantsToErase.emplace(mruWindowArgs.PeasantID());
continue; continue;
} }
@ -504,7 +568,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
"true if this window was in fact on the current desktop"), "true if this window was in fact on the current desktop"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE)); TraceLoggingKeyword(TIL_KEYWORD_TRACE));
return mruWindowArgs.PeasantID(); result = mruWindowArgs.PeasantID();
break;
} }
// If this window wasn't on the current desktop, another one // If this window wasn't on the current desktop, another one
// might be. We'll increment positionInList below, and try // might be. We'll increment positionInList below, and try
@ -518,20 +583,30 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE)); TraceLoggingKeyword(TIL_KEYWORD_TRACE));
return mruWindowArgs.PeasantID(); result = mruWindowArgs.PeasantID();
break;
} }
positionInList++;
} }
// Here, we've checked all the windows, and none of them was both alive lock.unlock();
// and the most recent (on this desktop). Just return 0 - the caller
// will use this to create a new window.
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_getMostRecentPeasantID_NotFound",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
return 0; if (peasantsToErase.size() > 0)
{
_clearOldMruEntries(peasantsToErase);
}
if (result == 0)
{
// Here, we've checked all the windows, and none of them was both alive
// and the most recent (on this desktop). Just return 0 - the caller
// will use this to create a new window.
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_getMostRecentPeasantID_NotFound",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
return result;
} }
// Method Description: // Method Description:
@ -855,7 +930,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
Windows::Foundation::Collections::IVectorView<PeasantInfo> Monarch::GetPeasantInfos() Windows::Foundation::Collections::IVectorView<PeasantInfo> Monarch::GetPeasantInfos()
{ {
std::vector<PeasantInfo> names; std::vector<PeasantInfo> names;
names.reserve(_peasants.size()); {
std::shared_lock lock{ _peasantsMutex };
names.reserve(_peasants.size());
}
const auto func = [&](const auto& id, const auto& p) -> void { const auto func = [&](const auto& id, const auto& p) -> void {
names.push_back({ id, p.WindowName(), p.ActiveTabTitle() }); names.push_back({ id, p.WindowName(), p.ActiveTabTitle() });

View file

@ -7,6 +7,7 @@
#include "Peasant.h" #include "Peasant.h"
#include "../cascadia/inc/cppwinrt_utils.h" #include "../cascadia/inc/cppwinrt_utils.h"
#include "WindowActivatedArgs.h" #include "WindowActivatedArgs.h"
#include <atomic>
// We sure different GUIDs here depending on whether we're running a Release, // We sure different GUIDs here depending on whether we're running a Release,
// Preview, or Dev build. This ensures that different installs don't // Preview, or Dev build. This ensures that different installs don't
@ -69,23 +70,29 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
private: private:
uint64_t _ourPID; uint64_t _ourPID;
uint64_t _nextPeasantID{ 1 }; std::atomic<uint64_t> _nextPeasantID{ 1 };
uint64_t _thisPeasantID{ 0 }; uint64_t _ourPeasantId{ 0 };
// When we're quitting we do not care as much about handling some events that we know will be triggered
std::atomic<bool> _quitting{ false };
winrt::com_ptr<IVirtualDesktopManager> _desktopManager{ nullptr }; winrt::com_ptr<IVirtualDesktopManager> _desktopManager{ nullptr };
std::unordered_map<uint64_t, winrt::Microsoft::Terminal::Remoting::IPeasant> _peasants; std::unordered_map<uint64_t, winrt::Microsoft::Terminal::Remoting::IPeasant> _peasants;
std::vector<Remoting::WindowActivatedArgs> _mruPeasants; std::vector<Remoting::WindowActivatedArgs> _mruPeasants;
// These should not be locked at the same time to prevent deadlocks
// unless they are both shared_locks.
std::shared_mutex _peasantsMutex{};
std::shared_mutex _mruPeasantsMutex{};
winrt::Microsoft::Terminal::Remoting::IPeasant _getPeasant(uint64_t peasantID); winrt::Microsoft::Terminal::Remoting::IPeasant _getPeasant(uint64_t peasantID, bool clearMruPeasantOnFailure = true);
uint64_t _getMostRecentPeasantID(bool limitToCurrentDesktop, const bool ignoreQuakeWindow); uint64_t _getMostRecentPeasantID(bool limitToCurrentDesktop, const bool ignoreQuakeWindow);
uint64_t _lookupPeasantIdForName(std::wstring_view name); uint64_t _lookupPeasantIdForName(std::wstring_view name);
void _peasantWindowActivated(const winrt::Windows::Foundation::IInspectable& sender, void _peasantWindowActivated(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs& args); const winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs& args);
void _doHandleActivatePeasant(const winrt::com_ptr<winrt::Microsoft::Terminal::Remoting::implementation::WindowActivatedArgs>& args); void _doHandleActivatePeasant(const winrt::com_ptr<winrt::Microsoft::Terminal::Remoting::implementation::WindowActivatedArgs>& args);
void _clearOldMruEntries(const uint64_t peasantID); void _clearOldMruEntries(const std::unordered_set<uint64_t>& peasantIds);
void _forAllPeasantsIgnoringTheDead(std::function<void(const winrt::Microsoft::Terminal::Remoting::IPeasant&, const uint64_t)> callback, void _forAllPeasantsIgnoringTheDead(std::function<void(const winrt::Microsoft::Terminal::Remoting::IPeasant&, const uint64_t)> callback,
std::function<void(const uint64_t)> errorCallback); std::function<void(const uint64_t)> errorCallback);
@ -107,6 +114,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// returns false. // returns false.
// - If any single peasant is dead, then we'll call onError and then add it to a // - If any single peasant is dead, then we'll call onError and then add it to a
// list of peasants to clean up once the loop ends. // list of peasants to clean up once the loop ends.
// - NB: this (separately) takes unique locks on _peasantsMutex and
// _mruPeasantsMutex.
// Arguments: // Arguments:
// - func: The function to call on each peasant // - func: The function to call on each peasant
// - onError: The function to call if a peasant is dead. // - onError: The function to call if a peasant is dead.
@ -119,44 +128,55 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
using R = std::invoke_result_t<F, Map::key_type, Map::mapped_type>; using R = std::invoke_result_t<F, Map::key_type, Map::mapped_type>;
static constexpr auto IsVoid = std::is_void_v<R>; static constexpr auto IsVoid = std::is_void_v<R>;
std::vector<uint64_t> peasantsToErase; std::unordered_set<uint64_t> peasantsToErase;
for (const auto& [id, p] : _peasants)
{ {
try std::shared_lock lock{ _peasantsMutex };
for (const auto& [id, p] : _peasants)
{ {
if constexpr (IsVoid) try
{ {
func(id, p); if constexpr (IsVoid)
}
else
{
if (!func(id, p))
{ {
break; func(id, p);
}
else
{
if (!func(id, p))
{
break;
}
} }
} }
} catch (const winrt::hresult_error& exception)
catch (const winrt::hresult_error& exception) {
{ onError(id);
onError(id);
if (exception.code() == 0x800706ba) // The RPC server is unavailable. if (exception.code() == 0x800706ba) // The RPC server is unavailable.
{ {
peasantsToErase.emplace_back(id); peasantsToErase.emplace(id);
} }
else else
{ {
LOG_CAUGHT_EXCEPTION(); LOG_CAUGHT_EXCEPTION();
throw; throw;
}
} }
} }
} }
for (const auto& id : peasantsToErase) if (peasantsToErase.size() > 0)
{ {
_peasants.erase(id); // Don't hold a lock on _peasants and _mruPeasants at the same
_clearOldMruEntries(id); // time to avoid deadlocks.
{
std::unique_lock lock{ _peasantsMutex };
for (const auto& id : peasantsToErase)
{
_peasants.erase(id);
}
}
_clearOldMruEntries(peasantsToErase);
} }
} }

View file

@ -324,6 +324,14 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE)); TraceLoggingKeyword(TIL_KEYWORD_TRACE));
// If the peasant asks us to quit we should not try to act in future elections.
_peasant.QuitRequested([weakThis{ get_weak() }](auto&&, auto&&) {
if (auto wm = weakThis.get())
{
wm->_monarchWaitInterrupt.SetEvent();
}
});
return _peasant; return _peasant;
} }

View file

@ -20,7 +20,8 @@
<ResourceDictionary> <ResourceDictionary>
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<!-- Include the MUX Controls resources --> <!-- Include the MUX Controls resources -->
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" /> <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls"
ControlsResourcesVersion="Version1" />
<ResourceDictionary> <ResourceDictionary>
<!-- <!--

View file

@ -29,12 +29,12 @@ namespace winrt
using IInspectable = Windows::Foundation::IInspectable; using IInspectable = Windows::Foundation::IInspectable;
} }
static const winrt::hstring StartupTaskName = L"StartTerminalOnLoginTask"; static constexpr std::wstring_view StartupTaskName = L"StartTerminalOnLoginTask";
// clang-format off // clang-format off
// !!! IMPORTANT !!! // !!! IMPORTANT !!!
// Make sure that these keys are in the same order as the // Make sure that these keys are in the same order as the
// SettingsLoadWarnings/Errors enum is! // SettingsLoadWarnings/Errors enum is!
static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadWarnings::WARNINGS_SIZE)> settingsLoadWarningsLabels { static const std::array settingsLoadWarningsLabels {
USES_RESOURCE(L"MissingDefaultProfileText"), USES_RESOURCE(L"MissingDefaultProfileText"),
USES_RESOURCE(L"DuplicateProfileText"), USES_RESOURCE(L"DuplicateProfileText"),
USES_RESOURCE(L"UnknownColorSchemeText"), USES_RESOURCE(L"UnknownColorSchemeText"),
@ -43,7 +43,6 @@ static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadWar
USES_RESOURCE(L"AtLeastOneKeybindingWarning"), USES_RESOURCE(L"AtLeastOneKeybindingWarning"),
USES_RESOURCE(L"TooManyKeysForChord"), USES_RESOURCE(L"TooManyKeysForChord"),
USES_RESOURCE(L"MissingRequiredParameter"), USES_RESOURCE(L"MissingRequiredParameter"),
USES_RESOURCE(L"LegacyGlobalsProperty"),
USES_RESOURCE(L"FailedToParseCommandJson"), USES_RESOURCE(L"FailedToParseCommandJson"),
USES_RESOURCE(L"FailedToWriteToSettings"), USES_RESOURCE(L"FailedToWriteToSettings"),
USES_RESOURCE(L"InvalidColorSchemeInCmd"), USES_RESOURCE(L"InvalidColorSchemeInCmd"),
@ -51,12 +50,15 @@ static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadWar
USES_RESOURCE(L"FailedToParseStartupActions"), USES_RESOURCE(L"FailedToParseStartupActions"),
USES_RESOURCE(L"FailedToParseSubCommands"), USES_RESOURCE(L"FailedToParseSubCommands"),
}; };
static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadErrors::ERRORS_SIZE)> settingsLoadErrorsLabels { static const std::array settingsLoadErrorsLabels {
USES_RESOURCE(L"NoProfilesText"), USES_RESOURCE(L"NoProfilesText"),
USES_RESOURCE(L"AllProfilesHiddenText") USES_RESOURCE(L"AllProfilesHiddenText")
}; };
// clang-format on // clang-format on
static_assert(settingsLoadWarningsLabels.size() == static_cast<size_t>(SettingsLoadWarnings::WARNINGS_SIZE));
static_assert(settingsLoadErrorsLabels.size() == static_cast<size_t>(SettingsLoadErrors::ERRORS_SIZE));
// Function Description: // Function Description:
// - General-purpose helper for looking up a localized string for a // - General-purpose helper for looking up a localized string for a
// warning/error. First will look for the given key in the provided map of // warning/error. First will look for the given key in the provided map of
@ -68,12 +70,12 @@ static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadErr
// - map: A map of keys->Resource keys. // - map: A map of keys->Resource keys.
// Return Value: // Return Value:
// - the localized string for the given type, if it exists. // - the localized string for the given type, if it exists.
template<std::size_t N> template<typename T>
static winrt::hstring _GetMessageText(uint32_t index, std::array<std::wstring_view, N> keys) winrt::hstring _GetMessageText(uint32_t index, const T& keys)
{ {
if (index < keys.size()) if (index < keys.size())
{ {
return GetLibraryResourceString(keys.at(index)); return GetLibraryResourceString(til::at(keys, index));
} }
return {}; return {};
} }
@ -488,27 +490,6 @@ namespace winrt::TerminalApp::implementation
if (!warningText.empty()) if (!warningText.empty())
{ {
warningsTextBlock.Inlines().Append(_BuildErrorRun(warningText, ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Resources())); warningsTextBlock.Inlines().Append(_BuildErrorRun(warningText, ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Resources()));
// The "LegacyGlobalsProperty" warning is special - it has a URL
// that goes with it. So we need to manually construct a
// Hyperlink and insert it along with the warning text.
if (warning == SettingsLoadWarnings::LegacyGlobalsProperty)
{
// Add the URL here too
const auto legacyGlobalsLinkLabel = RS_(L"LegacyGlobalsPropertyHrefLabel");
const auto legacyGlobalsLinkUriValue = RS_(L"LegacyGlobalsPropertyHrefUrl");
winrt::Windows::UI::Xaml::Documents::Run legacyGlobalsLinkText;
winrt::Windows::UI::Xaml::Documents::Hyperlink legacyGlobalsLink;
winrt::Windows::Foundation::Uri legacyGlobalsLinkUri{ legacyGlobalsLinkUriValue };
legacyGlobalsLinkText.Text(legacyGlobalsLinkLabel);
legacyGlobalsLink.NavigateUri(legacyGlobalsLinkUri);
legacyGlobalsLink.Inlines().Append(legacyGlobalsLinkText);
warningsTextBlock.Inlines().Append(legacyGlobalsLink);
}
warningsTextBlock.Inlines().Append(Documents::LineBreak{}); warningsTextBlock.Inlines().Append(Documents::LineBreak{});
} }
} }

View file

@ -53,10 +53,6 @@ Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFo
_SetupResources(); _SetupResources();
} }
// Use the unfocused border color as the pane background, so an actual color
// appears behind panes as we animate them sliding in.
_root.Background(s_unfocusedBorderBrush);
// Register an event with the control to have it inform us when it gains focus. // Register an event with the control to have it inform us when it gains focus.
_gotFocusRevoker = _control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler }); _gotFocusRevoker = _control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler });
_lostFocusRevoker = _control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler }); _lostFocusRevoker = _control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler });
@ -1616,6 +1612,8 @@ winrt::fire_and_forget Pane::_CloseChildRoutine(const bool closeFirst)
// Create the dummy grid. This grid will be the one we actually animate, // Create the dummy grid. This grid will be the one we actually animate,
// in the place of the closed pane. // in the place of the closed pane.
Controls::Grid dummyGrid; Controls::Grid dummyGrid;
// GH#603 - we can safely add a BG here, as the control is gone right
// away, to fill the space as the rest of the pane expands.
dummyGrid.Background(s_unfocusedBorderBrush); dummyGrid.Background(s_unfocusedBorderBrush);
// It should be the size of the closed pane. // It should be the size of the closed pane.
dummyGrid.Width(removedOriginalSize.Width); dummyGrid.Width(removedOriginalSize.Width);
@ -1871,6 +1869,19 @@ void Pane::_SetupEntranceAnimation()
return; return;
} }
// Use the unfocused border color as the pane background, so an actual color
// appears behind panes as we animate them sliding in.
//
// GH#603 - We set only the background of the new pane, while it animates
// in. Once the animation is done, we'll remove that background, so if the
// user wants vintage opacity, they'll be able to see what's under the
// window.
// * If we don't give it a background, then the BG will be entirely transparent.
// * If we give the parent (us) root BG a color, then a transparent pane
// will flash opaque during the animation, then back to transparent, which
// looks bad.
_secondChild->_root.Background(s_unfocusedBorderBrush);
const auto [firstSize, secondSize] = _CalcChildrenSizes(::base::saturated_cast<float>(totalSize)); const auto [firstSize, secondSize] = _CalcChildrenSizes(::base::saturated_cast<float>(totalSize));
// This is safe to capture this, because it's only being called in the // This is safe to capture this, because it's only being called in the
@ -1938,11 +1949,12 @@ void Pane::_SetupEntranceAnimation()
// When the animation is completed, undo the trickiness from before, to // When the animation is completed, undo the trickiness from before, to
// restore the controls to the behavior they'd usually have. // restore the controls to the behavior they'd usually have.
animation.Completed([childGrid, control](auto&&, auto&&) { animation.Completed([childGrid, control, root = _secondChild->_root](auto&&, auto&&) {
control.Width(NAN); control.Width(NAN);
childGrid.Width(NAN); childGrid.Width(NAN);
childGrid.HorizontalAlignment(HorizontalAlignment::Stretch); childGrid.HorizontalAlignment(HorizontalAlignment::Stretch);
control.HorizontalAlignment(HorizontalAlignment::Stretch); control.HorizontalAlignment(HorizontalAlignment::Stretch);
root.Background(nullptr);
}); });
} }
else else
@ -1956,11 +1968,12 @@ void Pane::_SetupEntranceAnimation()
// When the animation is completed, undo the trickiness from before, to // When the animation is completed, undo the trickiness from before, to
// restore the controls to the behavior they'd usually have. // restore the controls to the behavior they'd usually have.
animation.Completed([childGrid, control](auto&&, auto&&) { animation.Completed([childGrid, control, root = _secondChild->_root](auto&&, auto&&) {
control.Height(NAN); control.Height(NAN);
childGrid.Height(NAN); childGrid.Height(NAN);
childGrid.VerticalAlignment(VerticalAlignment::Stretch); childGrid.VerticalAlignment(VerticalAlignment::Stretch);
control.VerticalAlignment(VerticalAlignment::Stretch); control.VerticalAlignment(VerticalAlignment::Stretch);
root.Background(nullptr);
}); });
} }

View file

@ -87,7 +87,7 @@ namespace winrt::TerminalApp::implementation
TraceLoggingBool(usedManualProfile, "ProfileSpecified", "Whether the new tab specified a profile explicitly"), TraceLoggingBool(usedManualProfile, "ProfileSpecified", "Whether the new tab specified a profile explicitly"),
TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The GUID of the profile spawned in the new tab"), TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The GUID of the profile spawned in the new tab"),
TraceLoggingBool(settings.DefaultSettings().UseAcrylic(), "UseAcrylic", "The acrylic preference from the settings"), TraceLoggingBool(settings.DefaultSettings().UseAcrylic(), "UseAcrylic", "The acrylic preference from the settings"),
TraceLoggingFloat64(settings.DefaultSettings().TintOpacity(), "TintOpacity", "Opacity preference from the settings"), TraceLoggingFloat64(settings.DefaultSettings().Opacity(), "TintOpacity", "Opacity preference from the settings"),
TraceLoggingWideString(settings.DefaultSettings().FontFace().c_str(), "FontFace", "Font face chosen in the settings"), TraceLoggingWideString(settings.DefaultSettings().FontFace().c_str(), "FontFace", "Font face chosen in the settings"),
TraceLoggingWideString(schemeName.data(), "SchemeName", "Color scheme set in the settings"), TraceLoggingWideString(schemeName.data(), "SchemeName", "Color scheme set in the settings"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),

View file

@ -376,13 +376,14 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<!-- ========================= Globals ======================== --> <!-- ========================= Globals ======================== -->
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" /> <Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" /> <Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <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> <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> </PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" /> <Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" /> <Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets'))" /> <Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets'))" />
</Target> </Target>

View file

@ -9,10 +9,11 @@
xmlns:local="using:TerminalApp" xmlns:local="using:TerminalApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mux="using:Microsoft.UI.Xaml.Controls" xmlns:mux="using:Microsoft.UI.Xaml.Controls"
Background="Transparent"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid x:Name="Root" <Grid x:Name="Root"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> Background="Transparent">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />

View file

@ -1400,11 +1400,22 @@ namespace winrt::TerminalApp::implementation
deselectedTabBrush.Color(deselectedTabColor); deselectedTabBrush.Color(deselectedTabColor);
// currently if a tab has a custom color, a deselected state is // currently if a tab has a custom color, a deselected state is
// signified by using the same color with a bit ot transparency // signified by using the same color with a bit of transparency
//
// Prior to MUX 2.7, we set TabViewItemHeaderBackground, but now we can
// use TabViewItem().Background() for that. HOWEVER,
// TabViewItem().Background() only sets the color of the tab background
// when the TabViewItem is unselected. So we still need to set the other
// properties ourselves.
TabViewItem().Background(deselectedTabBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundSelected"), selectedTabBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundSelected"), selectedTabBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackground"), deselectedTabBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPointerOver"), hoverTabBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPointerOver"), hoverTabBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPressed"), selectedTabBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPressed"), selectedTabBrush);
// TabViewItem().Foreground() unfortunately does not work for us. It
// sets the color for the text when the TabViewItem isn't selected, but
// not when it is hovered, pressed, dragged, or selected, so we'll need
// to just set them all anyways.
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForeground"), fontBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForeground"), fontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForegroundSelected"), fontBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForegroundSelected"), fontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForegroundPointerOver"), fontBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForegroundPointerOver"), fontBrush);
@ -1442,7 +1453,6 @@ namespace winrt::TerminalApp::implementation
void TerminalTab::_ClearTabBackgroundColor() void TerminalTab::_ClearTabBackgroundColor()
{ {
winrt::hstring keys[] = { winrt::hstring keys[] = {
L"TabViewItemHeaderBackground",
L"TabViewItemHeaderBackgroundSelected", L"TabViewItemHeaderBackgroundSelected",
L"TabViewItemHeaderBackgroundPointerOver", L"TabViewItemHeaderBackgroundPointerOver",
L"TabViewItemHeaderForeground", L"TabViewItemHeaderForeground",
@ -1463,6 +1473,9 @@ namespace winrt::TerminalApp::implementation
} }
} }
// Clear out the Background.
TabViewItem().Background(nullptr);
_RefreshVisualState(); _RefreshVisualState();
_colorCleared(); _colorCleared();
} }
@ -1487,7 +1500,7 @@ namespace winrt::TerminalApp::implementation
// - <none> // - <none>
void TerminalTab::_RefreshVisualState() void TerminalTab::_RefreshVisualState()
{ {
if (_focusState != FocusState::Unfocused) if (TabViewItem().IsSelected())
{ {
VisualStateManager::GoToState(TabViewItem(), L"Normal", true); VisualStateManager::GoToState(TabViewItem(), L"Normal", true);
VisualStateManager::GoToState(TabViewItem(), L"Selected", true); VisualStateManager::GoToState(TabViewItem(), L"Selected", true);

View file

@ -89,13 +89,13 @@
</ItemGroup> </ItemGroup>
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" /> <Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" /> <Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <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> <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> </PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" /> <Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" /> <Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
</Target> </Target>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" /> <package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.5.0-prerelease.201202003" targetFramework="native" /> <package id="Microsoft.UI.Xaml" version="2.7.0-prerelease.210913003" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" /> <package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" />
</packages> </packages>

View file

@ -16,6 +16,10 @@
#include "LibraryResources.h" #include "LibraryResources.h"
using namespace ::Microsoft::Console; using namespace ::Microsoft::Console;
using namespace std::string_view_literals;
// Format is: "DecimalResult (HexadecimalForm)"
static constexpr auto _errorFormat = L"{0} ({0:#010x})"sv;
// Notes: // Notes:
// There is a number of ways that the Conpty connection can be terminated (voluntarily or not): // There is a number of ways that the Conpty connection can be terminated (voluntarily or not):
@ -417,7 +421,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
const auto hr = wil::ResultFromCaughtException(); const auto hr = wil::ResultFromCaughtException();
winrt::hstring failureText{ fmt::format(std::wstring_view{ RS_(L"ProcessFailedToLaunch") }, winrt::hstring failureText{ fmt::format(std::wstring_view{ RS_(L"ProcessFailedToLaunch") },
gsl::narrow_cast<unsigned long>(hr), fmt::format(_errorFormat, hr),
_commandline) }; _commandline) };
_TerminalOutputHandlers(failureText); _TerminalOutputHandlers(failureText);
@ -444,7 +448,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{ {
try try
{ {
winrt::hstring exitText{ fmt::format(std::wstring_view{ RS_(L"ProcessExited") }, status) }; winrt::hstring exitText{ fmt::format(std::wstring_view{ RS_(L"ProcessExited") }, fmt::format(_errorFormat, status)) };
_TerminalOutputHandlers(L"\r\n"); _TerminalOutputHandlers(L"\r\n");
_TerminalOutputHandlers(exitText); _TerminalOutputHandlers(exitText);
} }

View file

@ -205,15 +205,15 @@
</data> </data>
<data name="ProcessExited" xml:space="preserve"> <data name="ProcessExited" xml:space="preserve">
<value>[process exited with code {0}]</value> <value>[process exited with code {0}]</value>
<comment>The first argument {0} is the (positive) error code of the process. When there is no error, the number ZERO will be displayed.</comment> <comment>The first argument {0} is the error code of the process. When there is no error, the number ZERO will be displayed. </comment>
</data> </data>
<data name="ProcessFailedToLaunch" xml:space="preserve"> <data name="ProcessFailedToLaunch" xml:space="preserve">
<value>[error {0:#08x} when launching `{1}']</value> <value>[error {0} when launching `{1}']</value>
<comment>The first argument {0...} is the hexadecimal error code. The second argument {1} is the user-specified path to a program. <comment>The first argument {0} is the error code. The second argument {1} is the user-specified path to a program.
If this string is broken to multiple lines, it will not be displayed properly.</comment> If this string is broken to multiple lines, it will not be displayed properly.</comment>
</data> </data>
<data name="BadPathText" xml:space="preserve"> <data name="BadPathText" xml:space="preserve">
<value>Could not access starting directory "{0}"</value> <value>Could not access starting directory "{0}"</value>
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment> <comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
</data> </data>
</root> </root>

View file

@ -56,7 +56,9 @@
<Midl Include="AzureConnection.idl" /> <Midl Include="AzureConnection.idl" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PRIResource Include="Resources\en-US\Resources.resw" /> <PRIResource Include="Resources\en-US\Resources.resw">
<SubType>Designer</SubType>
</PRIResource>
<OCResourceDirectory Include="Resources" /> <OCResourceDirectory Include="Resources" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
@ -88,11 +90,11 @@
</Target> </Target>
<ItemDefinitionGroup> <ItemDefinitionGroup>
<ClCompile> <ClCompile>
<AdditionalIncludeDirectories>$(IntDir)..\OpenConsoleProxy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(IntDir)..\OpenConsoleProxy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>$(OpenConsoleCommonOutDir)\conptylib.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>$(OpenConsoleCommonOutDir)\conptylib.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" /> <Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
</Project> </Project>

View file

@ -32,6 +32,7 @@
<Midl Include="EchoConnection.idl" /> <Midl Include="EchoConnection.idl" />
<Midl Include="AzureConnection.idl" /> <Midl Include="AzureConnection.idl" />
<Midl Include="ConptyConnection.idl" /> <Midl Include="ConptyConnection.idl" />
<Midl Include="ConnectionInformation.idl" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="packages.config" /> <None Include="packages.config" />

View file

@ -276,7 +276,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// GH#5098: Inform the engine of the opacity of the default text background. // GH#5098: Inform the engine of the opacity of the default text background.
if (_settings.UseAcrylic()) if (_settings.UseAcrylic())
{ {
_renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast<float>(_settings.TintOpacity())); _renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast<float>(_settings.Opacity()));
} }
THROW_IF_FAILED(_renderEngine->Enable()); THROW_IF_FAILED(_renderEngine->Enable());
@ -425,41 +425,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return; return;
} }
auto newOpacity = std::clamp(_settings.TintOpacity() + adjustment, auto newOpacity = std::clamp(_settings.Opacity() + adjustment,
0.0, 0.0,
1.0); 1.0);
if (_settings.UseAcrylic())
{
try
{
_settings.TintOpacity(newOpacity);
if (newOpacity >= 1.0) // GH#5098: Inform the engine of the new opacity of the default text background.
{ SetBackgroundOpacity(::base::saturated_cast<float>(newOpacity));
_settings.UseAcrylic(false);
}
else
{
// GH#5098: Inform the engine of the new opacity of the default text background.
SetBackgroundOpacity(::base::saturated_cast<float>(newOpacity));
}
auto eventArgs = winrt::make_self<TransparencyChangedEventArgs>(newOpacity); _settings.Opacity(newOpacity);
_TransparencyChangedHandlers(*this, *eventArgs);
}
CATCH_LOG();
}
else if (adjustment < 0)
{
_settings.UseAcrylic(true);
//Setting initial opacity set to 1 to ensure smooth transition to acrylic during mouse scroll auto eventArgs = winrt::make_self<TransparencyChangedEventArgs>(newOpacity);
newOpacity = std::clamp(1.0 + adjustment, 0.0, 1.0); _TransparencyChangedHandlers(*this, *eventArgs);
_settings.TintOpacity(newOpacity);
auto eventArgs = winrt::make_self<TransparencyChangedEventArgs>(newOpacity);
_TransparencyChangedHandlers(*this, *eventArgs);
}
} }
void ControlCore::ToggleShaderEffects() void ControlCore::ToggleShaderEffects()
@ -1003,6 +979,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{ {
_terminal->WritePastedText(hstr); _terminal->WritePastedText(hstr);
_terminal->ClearSelection(); _terminal->ClearSelection();
_renderer->TriggerSelection();
_terminal->TrySnapOnInput(); _terminal->TrySnapOnInput();
} }

View file

@ -13,6 +13,7 @@ namespace Microsoft.Terminal.Control
Windows.UI.Xaml.VerticalAlignment BackgroundImageVerticalAlignment; Windows.UI.Xaml.VerticalAlignment BackgroundImageVerticalAlignment;
Boolean IntenseIsBold; Boolean IntenseIsBold;
// IntenseIsBright is in Core Appearance // IntenseIsBright is in Core Appearance
Double Opacity;
// Experimental settings // Experimental settings
Boolean RetroTerminalEffect; Boolean RetroTerminalEffect;

View file

@ -29,7 +29,6 @@ namespace Microsoft.Terminal.Control
String ProfileName; String ProfileName;
Boolean UseAcrylic; Boolean UseAcrylic;
Double TintOpacity;
ScrollbarState ScrollState; ScrollbarState ScrollState;
String FontFace; String FontFace;

View file

@ -428,6 +428,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none> // - <none>
void TermControl::_InitializeBackgroundBrush() void TermControl::_InitializeBackgroundBrush()
{ {
auto appearance = _settings.try_as<IControlAppearance>();
if (_settings.UseAcrylic()) if (_settings.UseAcrylic())
{ {
// See if we've already got an acrylic background brush // See if we've already got an acrylic background brush
@ -449,7 +450,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
acrylic.TintColor(bgColor); acrylic.TintColor(bgColor);
// Apply brush settings // Apply brush settings
acrylic.TintOpacity(_settings.TintOpacity()); acrylic.TintOpacity(appearance.Opacity());
// Apply brush to control if it's not already there // Apply brush to control if it's not already there
if (RootGrid().Background() != acrylic) if (RootGrid().Background() != acrylic)
@ -458,15 +459,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
} }
// GH#5098: Inform the engine of the new opacity of the default text background. // GH#5098: Inform the engine of the new opacity of the default text background.
_core.SetBackgroundOpacity(::base::saturated_cast<float>(_settings.TintOpacity())); _core.SetBackgroundOpacity(::base::saturated_cast<float>(appearance.Opacity()));
} }
else else
{ {
Media::SolidColorBrush solidColor{}; Media::SolidColorBrush solidColor{};
solidColor.Opacity(_settings.Opacity());
RootGrid().Background(solidColor); RootGrid().Background(solidColor);
// GH#5098: Inform the engine of the new opacity of the default text background. // GH#5098: Inform the engine of the new opacity of the default text background.
_core.SetBackgroundOpacity(1.0f); _core.SetBackgroundOpacity(appearance.Opacity());
} }
} }
@ -497,7 +499,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
} }
else if (auto solidColor = RootGrid().Background().try_as<Media::SolidColorBrush>()) else if (auto solidColor = RootGrid().Background().try_as<Media::SolidColorBrush>())
{ {
const auto originalOpacity = solidColor.Opacity();
solidColor.Color(bg); solidColor.Color(bg);
solidColor.Opacity(originalOpacity);
} }
} }
} }

View file

@ -14,6 +14,7 @@
d:DesignWidth="1024" d:DesignWidth="1024"
AllowDrop="True" AllowDrop="True"
AllowFocusOnInteraction="True" AllowFocusOnInteraction="True"
Background="Transparent"
CharacterReceived="_CharacterHandler" CharacterReceived="_CharacterHandler"
DragOver="_DragOverHandler" DragOver="_DragOverHandler"
Drop="_DragDropHandler" Drop="_DragDropHandler"

View file

@ -34,7 +34,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void Launch::OnNavigatedTo(const NavigationEventArgs& e) void Launch::OnNavigatedTo(const NavigationEventArgs& e)
{ {
_State = e.Parameter().as<Editor::LaunchPageNavigationState>(); _State = e.Parameter().as<Editor::LaunchPageNavigationState>();
_State.Settings().RefreshDefaultTerminals();
} }
IInspectable Launch::CurrentDefaultProfile() IInspectable Launch::CurrentDefaultProfile()

View file

@ -74,7 +74,7 @@
x:Uid="Globals_DefaultTerminal" x:Uid="Globals_DefaultTerminal"
x:Load="false"> x:Load="false">
<ComboBox x:Name="DefaultTerminal" <ComboBox x:Name="DefaultTerminal"
ItemsSource="{x:Bind State.Settings.DefaultTerminals, Mode=OneWay}" ItemsSource="{x:Bind State.Settings.DefaultTerminals}"
SelectedItem="{x:Bind State.Settings.CurrentDefaultTerminal, Mode=TwoWay}" SelectedItem="{x:Bind State.Settings.CurrentDefaultTerminal, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}"> Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>

View file

@ -8,6 +8,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls" xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d"> mc:Ignorable="d">
<Page.Resources> <Page.Resources>

View file

@ -312,12 +312,12 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" /> <Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" /> <Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <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> <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> </PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" /> <Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets'))" />
</Target> </Target>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" /> <Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
</Project> </Project>

View file

@ -22,7 +22,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void SetAcrylicOpacityPercentageValue(double value) void SetAcrylicOpacityPercentageValue(double value)
{ {
AcrylicOpacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(value)); _profile.DefaultAppearance().Opacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(value));
}; };
void SetPadding(double value) void SetPadding(double value)
@ -66,7 +66,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_profile, TabColor); OBSERVABLE_PROJECTED_SETTING(_profile, TabColor);
OBSERVABLE_PROJECTED_SETTING(_profile, SuppressApplicationTitle); OBSERVABLE_PROJECTED_SETTING(_profile, SuppressApplicationTitle);
OBSERVABLE_PROJECTED_SETTING(_profile, UseAcrylic); OBSERVABLE_PROJECTED_SETTING(_profile, UseAcrylic);
OBSERVABLE_PROJECTED_SETTING(_profile, AcrylicOpacity);
OBSERVABLE_PROJECTED_SETTING(_profile, ScrollState); OBSERVABLE_PROJECTED_SETTING(_profile, ScrollState);
OBSERVABLE_PROJECTED_SETTING(_profile, Padding); OBSERVABLE_PROJECTED_SETTING(_profile, Padding);
OBSERVABLE_PROJECTED_SETTING(_profile, Commandline); OBSERVABLE_PROJECTED_SETTING(_profile, Commandline);
@ -78,6 +77,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Background); OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Background);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), SelectionBackground); OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), SelectionBackground);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), CursorColor); OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), CursorColor);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Opacity);
OBSERVABLE_PROJECTED_SETTING(_profile, HistorySize); OBSERVABLE_PROJECTED_SETTING(_profile, HistorySize);
OBSERVABLE_PROJECTED_SETTING(_profile, SnapOnInput); OBSERVABLE_PROJECTED_SETTING(_profile, SnapOnInput);
OBSERVABLE_PROJECTED_SETTING(_profile, AltGrAliasing); OBSERVABLE_PROJECTED_SETTING(_profile, AltGrAliasing);

View file

@ -47,7 +47,7 @@ namespace Microsoft.Terminal.Settings.Editor
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, TabColor); OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, TabColor);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SuppressApplicationTitle); OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SuppressApplicationTitle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAcrylic); OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAcrylic);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Double, AcrylicOpacity); OBSERVABLE_PROJECTED_PROFILE_SETTING(Double, Opacity);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.ScrollbarState, ScrollState); OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.ScrollbarState, ScrollState);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Padding); OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Padding);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Commandline); OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Commandline);
@ -109,6 +109,6 @@ namespace Microsoft.Terminal.Settings.Editor
IInspectable CurrentScrollState; IInspectable CurrentScrollState;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> ScrollStateList { get; }; Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> ScrollStateList { get; };
Windows.UI.Xaml.Controls.Slider AcrylicOpacitySlider { get; }; Windows.UI.Xaml.Controls.Slider OpacitySlider { get; };
} }
} }

View file

@ -238,11 +238,33 @@
<local:Appearances Appearance="{x:Bind State.Profile.DefaultAppearance, Mode=OneWay}" <local:Appearances Appearance="{x:Bind State.Profile.DefaultAppearance, Mode=OneWay}"
SourceProfile="{x:Bind State.Profile, Mode=OneWay}" /> SourceProfile="{x:Bind State.Profile, Mode=OneWay}" />
<!-- Grouping: Acrylic --> <!-- Grouping: Transparency -->
<StackPanel Style="{StaticResource PivotStackStyle}"> <StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_AcrylicHeader" <TextBlock x:Uid="Profile_TransparencyHeader"
Style="{StaticResource SubtitleTextBlockStyle}" /> Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Opacity -->
<local:SettingContainer x:Name="OpacityContainer"
x:Uid="Profile_Opacity"
ClearSettingValue="{x:Bind State.Profile.ClearOpacity}"
HasSettingValue="{x:Bind State.Profile.HasOpacity, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.OpacityOverrideSource, Mode=OneWay}">
<StackPanel x:Name="OpacityControl">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="OpacitySlider"
Grid.Column="0"
Value="{x:Bind local:Converters.PercentageToPercentageValue(State.Profile.Opacity), BindBack=State.Profile.SetAcrylicOpacityPercentageValue, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{x:Bind local:Converters.AppendPercentageSign(OpacitySlider.Value), Mode=OneWay}" />
</Grid>
</StackPanel>
</local:SettingContainer>
<!-- Use Acrylic --> <!-- Use Acrylic -->
<local:SettingContainer x:Uid="Profile_UseAcrylic" <local:SettingContainer x:Uid="Profile_UseAcrylic"
Margin="0" Margin="0"
@ -253,28 +275,6 @@
IsOn="{x:Bind State.Profile.UseAcrylic, Mode=TwoWay}" /> IsOn="{x:Bind State.Profile.UseAcrylic, Mode=TwoWay}" />
</local:SettingContainer> </local:SettingContainer>
<!-- Acrylic Opacity -->
<local:SettingContainer x:Name="AcrylicOpacityContainer"
x:Uid="Profile_AcrylicOpacity"
ClearSettingValue="{x:Bind State.Profile.ClearAcrylicOpacity}"
HasSettingValue="{x:Bind State.Profile.HasAcrylicOpacity, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.AcrylicOpacityOverrideSource, Mode=OneWay}"
Visibility="{Binding ElementName=UseAcrylicToggleSwitch, Path=IsOn, Mode=OneWay}">
<StackPanel x:Name="AcrylicOpacityControl">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="AcrylicOpacitySlider"
Grid.Column="0"
Value="{x:Bind local:Converters.PercentageToPercentageValue(State.Profile.AcrylicOpacity), BindBack=State.Profile.SetAcrylicOpacityPercentageValue, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{x:Bind local:Converters.AppendPercentageSign(AcrylicOpacitySlider.Value), Mode=OneWay}" />
</Grid>
</StackPanel>
</local:SettingContainer>
</StackPanel> </StackPanel>
<!-- Grouping: Window --> <!-- Grouping: Window -->

View file

@ -495,6 +495,14 @@
<value>Sets the transparency of the window.</value> <value>Sets the transparency of the window.</value>
<comment>A description for what the "acrylic opacity" setting does. Presented near "Profile_AcrylicOpacity.Header".</comment> <comment>A description for what the "acrylic opacity" setting does. Presented near "Profile_AcrylicOpacity.Header".</comment>
</data> </data>
<data name="Profile_Opacity.Header" xml:space="preserve">
<value>Background Opacity</value>
<comment>Header for a control to determine the level of opacity for the background of the control. The user can choose to make the background of the app more or less opaque.</comment>
</data>
<data name="Profile_Opacity.HelpText" xml:space="preserve">
<value>Sets the transparency of the window.</value>
<comment>A description for what the "opacity" setting does. Presented near "Profile_Opacity.Header".</comment>
</data>
<data name="Profile_Advanced.Header" xml:space="preserve"> <data name="Profile_Advanced.Header" xml:space="preserve">
<value>Advanced</value> <value>Advanced</value>
<comment>Header for a sub-page of profile settings focused on more advanced scenarios.</comment> <comment>Header for a sub-page of profile settings focused on more advanced scenarios.</comment>
@ -986,6 +994,10 @@
<value>Acrylic</value> <value>Acrylic</value>
<comment>Header for a group of settings related to the acrylic texture rendering on the background of the app.</comment> <comment>Header for a group of settings related to the acrylic texture rendering on the background of the app.</comment>
</data> </data>
<data name="Profile_TransparencyHeader.Text" xml:space="preserve">
<value>Transparency</value>
<comment>Header for a group of settings related to transparency, including the acrylic texture rendering on the background of the app.</comment>
</data>
<data name="Profile_BackgroundHeader.Text" xml:space="preserve"> <data name="Profile_BackgroundHeader.Text" xml:space="preserve">
<value>Background image</value> <value>Background image</value>
<comment>Header for a group of settings that control the image presented on the background of the app. Presented near "Profile_BackgroundImage" and other keys starting with "Profile_BackgroundImage".</comment> <comment>Header for a group of settings that control the image presented on the background of the app. Presented near "Profile_BackgroundImage" and other keys starting with "Profile_BackgroundImage".</comment>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Microsoft.UI.Xaml" version="2.5.0-prerelease.201202003" targetFramework="native" /> <package id="Microsoft.UI.Xaml" version="2.7.0-prerelease.210913003" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" /> <package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" />
</packages> </packages>

View file

@ -26,30 +26,32 @@ static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageA
static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" }; static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" };
static constexpr std::string_view PixelShaderPathKey{ "experimental.pixelShaderPath" }; static constexpr std::string_view PixelShaderPathKey{ "experimental.pixelShaderPath" };
static constexpr std::string_view IntenseTextStyleKey{ "intenseTextStyle" }; static constexpr std::string_view IntenseTextStyleKey{ "intenseTextStyle" };
static constexpr std::string_view LegacyAcrylicTransparencyKey{ "acrylicOpacity" };
static constexpr std::string_view OpacityKey{ "opacity" };
winrt::Microsoft::Terminal::Settings::Model::implementation::AppearanceConfig::AppearanceConfig(const winrt::weak_ref<Profile> sourceProfile) : AppearanceConfig::AppearanceConfig(winrt::weak_ref<Profile> sourceProfile) :
_sourceProfile(sourceProfile) _sourceProfile(std::move(sourceProfile))
{ {
} }
winrt::com_ptr<AppearanceConfig> AppearanceConfig::CopyAppearance(const winrt::com_ptr<AppearanceConfig> source, const winrt::weak_ref<Profile> sourceProfile) winrt::com_ptr<AppearanceConfig> AppearanceConfig::CopyAppearance(const AppearanceConfig* source, winrt::weak_ref<Profile> sourceProfile)
{ {
auto appearance{ winrt::make_self<AppearanceConfig>(sourceProfile) }; auto appearance{ winrt::make_self<AppearanceConfig>(std::move(sourceProfile)) };
auto const sourceAppearance = source.try_as<AppearanceConfig>(); appearance->_BackgroundImagePath = source->_BackgroundImagePath;
appearance->_BackgroundImagePath = sourceAppearance->_BackgroundImagePath; appearance->_BackgroundImageOpacity = source->_BackgroundImageOpacity;
appearance->_BackgroundImageOpacity = sourceAppearance->_BackgroundImageOpacity; appearance->_BackgroundImageStretchMode = source->_BackgroundImageStretchMode;
appearance->_BackgroundImageStretchMode = sourceAppearance->_BackgroundImageStretchMode; appearance->_ColorSchemeName = source->_ColorSchemeName;
appearance->_ColorSchemeName = sourceAppearance->_ColorSchemeName; appearance->_Foreground = source->_Foreground;
appearance->_Foreground = sourceAppearance->_Foreground; appearance->_Background = source->_Background;
appearance->_Background = sourceAppearance->_Background; appearance->_SelectionBackground = source->_SelectionBackground;
appearance->_SelectionBackground = sourceAppearance->_SelectionBackground; appearance->_CursorColor = source->_CursorColor;
appearance->_CursorColor = sourceAppearance->_CursorColor; appearance->_CursorShape = source->_CursorShape;
appearance->_CursorShape = sourceAppearance->_CursorShape; appearance->_CursorHeight = source->_CursorHeight;
appearance->_CursorHeight = sourceAppearance->_CursorHeight; appearance->_BackgroundImageAlignment = source->_BackgroundImageAlignment;
appearance->_BackgroundImageAlignment = sourceAppearance->_BackgroundImageAlignment; appearance->_RetroTerminalEffect = source->_RetroTerminalEffect;
appearance->_RetroTerminalEffect = sourceAppearance->_RetroTerminalEffect; appearance->_PixelShaderPath = source->_PixelShaderPath;
appearance->_PixelShaderPath = sourceAppearance->_PixelShaderPath; appearance->_IntenseTextStyle = source->_IntenseTextStyle;
appearance->_IntenseTextStyle = sourceAppearance->_IntenseTextStyle; appearance->_Opacity = source->_Opacity;
return appearance; return appearance;
} }
@ -71,6 +73,7 @@ Json::Value AppearanceConfig::ToJson() const
JsonUtils::SetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect); JsonUtils::SetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect);
JsonUtils::SetValueForKey(json, PixelShaderPathKey, _PixelShaderPath); JsonUtils::SetValueForKey(json, PixelShaderPathKey, _PixelShaderPath);
JsonUtils::SetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle); JsonUtils::SetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle);
JsonUtils::SetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter<double, IntAsFloatPercentConversionTrait>{});
return json; return json;
} }
@ -102,6 +105,8 @@ void AppearanceConfig::LayerJson(const Json::Value& json)
JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect); JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect);
JsonUtils::GetValueForKey(json, PixelShaderPathKey, _PixelShaderPath); JsonUtils::GetValueForKey(json, PixelShaderPathKey, _PixelShaderPath);
JsonUtils::GetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle); JsonUtils::GetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle);
JsonUtils::GetValueForKey(json, LegacyAcrylicTransparencyKey, _Opacity);
JsonUtils::GetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter<double, IntAsFloatPercentConversionTrait>{});
} }
winrt::Microsoft::Terminal::Settings::Model::Profile AppearanceConfig::SourceProfile() winrt::Microsoft::Terminal::Settings::Model::Profile AppearanceConfig::SourceProfile()

View file

@ -18,7 +18,6 @@ Author(s):
#include "AppearanceConfig.g.h" #include "AppearanceConfig.g.h"
#include "JsonUtils.h" #include "JsonUtils.h"
#include "../inc/cppwinrt_utils.h"
#include "IInheritable.h" #include "IInheritable.h"
#include <DefaultSettings.h> #include <DefaultSettings.h>
@ -27,8 +26,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
struct AppearanceConfig : AppearanceConfigT<AppearanceConfig>, IInheritable<AppearanceConfig> struct AppearanceConfig : AppearanceConfigT<AppearanceConfig>, IInheritable<AppearanceConfig>
{ {
public: public:
AppearanceConfig(const winrt::weak_ref<Profile> sourceProfile); AppearanceConfig(winrt::weak_ref<Profile> sourceProfile);
static winrt::com_ptr<AppearanceConfig> CopyAppearance(const winrt::com_ptr<AppearanceConfig> source, const winrt::weak_ref<Profile> sourceProfile); static winrt::com_ptr<AppearanceConfig> CopyAppearance(const AppearanceConfig* source, winrt::weak_ref<Profile> sourceProfile);
Json::Value ToJson() const; Json::Value ToJson() const;
void LayerJson(const Json::Value& json); void LayerJson(const Json::Value& json);
@ -53,6 +52,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::IAppearanceConfig, bool, RetroTerminalEffect, false); INHERITABLE_SETTING(Model::IAppearanceConfig, bool, RetroTerminalEffect, false);
INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, PixelShaderPath, L""); INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, PixelShaderPath, L"");
INHERITABLE_SETTING(Model::IAppearanceConfig, Model::IntenseStyle, IntenseTextStyle, Model::IntenseStyle::Bright); INHERITABLE_SETTING(Model::IAppearanceConfig, Model::IntenseStyle, IntenseTextStyle, Model::IntenseStyle::Bright);
INHERITABLE_SETTING(Model::IAppearanceConfig, double, Opacity, 1.0);
private: private:
winrt::weak_ref<Profile> _sourceProfile; winrt::weak_ref<Profile> _sourceProfile;

View file

@ -6,16 +6,14 @@
#include "AzureCloudShellGenerator.h" #include "AzureCloudShellGenerator.h"
#include "LegacyProfileGeneratorNamespaces.h" #include "LegacyProfileGeneratorNamespaces.h"
#include "../../types/inc/utils.hpp"
#include "../../inc/DefaultSettings.h" #include "../../inc/DefaultSettings.h"
#include "Utils.h" #include "DynamicProfileUtils.h"
#include "DefaultProfileUtils.h"
using namespace ::Microsoft::Terminal::Settings::Model; using namespace ::Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::TerminalConnection; using namespace winrt::Microsoft::Terminal::TerminalConnection;
std::wstring_view AzureCloudShellGenerator::GetNamespace() std::wstring_view AzureCloudShellGenerator::GetNamespace() const noexcept
{ {
return AzureGeneratorNamespace; return AzureGeneratorNamespace;
} }
@ -27,19 +25,14 @@ std::wstring_view AzureCloudShellGenerator::GetNamespace()
// - <none> // - <none>
// Return Value: // Return Value:
// - a vector with the Azure Cloud Shell connection profile, if available. // - a vector with the Azure Cloud Shell connection profile, if available.
std::vector<Profile> AzureCloudShellGenerator::GenerateProfiles() void AzureCloudShellGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{ {
std::vector<Profile> profiles;
if (AzureConnection::IsAzureConnectionAvailable()) if (AzureConnection::IsAzureConnectionAvailable())
{ {
auto azureCloudShellProfile{ CreateDefaultProfile(L"Azure Cloud Shell") }; auto azureCloudShellProfile{ CreateDynamicProfile(L"Azure Cloud Shell") };
azureCloudShellProfile.Commandline(L"Azure"); azureCloudShellProfile->StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY });
azureCloudShellProfile.StartingDirectory(DEFAULT_STARTING_DIRECTORY); azureCloudShellProfile->DefaultAppearance().ColorSchemeName(L"Vintage");
azureCloudShellProfile.DefaultAppearance().ColorSchemeName(L"Vintage"); azureCloudShellProfile->ConnectionType(AzureConnection::ConnectionType());
azureCloudShellProfile.ConnectionType(AzureConnection::ConnectionType()); profiles.emplace_back(std::move(azureCloudShellProfile));
profiles.emplace_back(azureCloudShellProfile);
} }
return profiles;
} }

View file

@ -16,17 +16,15 @@ Author(s):
--*/ --*/
#pragma once #pragma once
#include "IDynamicProfileGenerator.h" #include "IDynamicProfileGenerator.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class AzureCloudShellGenerator : public IDynamicProfileGenerator class AzureCloudShellGenerator final : public IDynamicProfileGenerator
{ {
public: public:
AzureCloudShellGenerator() = default; std::wstring_view GetNamespace() const noexcept override;
~AzureCloudShellGenerator() = default; void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
std::wstring_view GetNamespace() override;
std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() override;
}; };
}; };

View file

@ -3,15 +3,12 @@
#include "pch.h" #include "pch.h"
#include "BaseVisualStudioGenerator.h" #include "BaseVisualStudioGenerator.h"
#include "DefaultProfileUtils.h" #include "DynamicProfileUtils.h"
using namespace Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model;
std::vector<Profile> BaseVisualStudioGenerator::GenerateProfiles() void BaseVisualStudioGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{ {
std::vector<Profile> profiles;
// There's no point in enumerating valid Visual Studio instances more than once, // There's no point in enumerating valid Visual Studio instances more than once,
// so cache them for use by both Visual Studio profile generators. // so cache them for use by both Visual Studio profile generators.
static const auto instances = VsSetupConfiguration::QueryInstances(); static const auto instances = VsSetupConfiguration::QueryInstances();
@ -25,27 +22,15 @@ std::vector<Profile> BaseVisualStudioGenerator::GenerateProfiles()
continue; continue;
} }
auto DevShell{ CreateProfile(GetProfileGuidSeed(instance)) }; const auto seed = GetProfileGuidSeed(instance);
DevShell.Name(GetProfileName(instance)); const winrt::guid profileGuid{ ::Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(seed))) };
DevShell.Commandline(GetProfileCommandLine(instance)); auto profile = winrt::make_self<implementation::Profile>(profileGuid);
DevShell.StartingDirectory(instance.GetInstallationPath()); profile->Name(winrt::hstring{ GetProfileName(instance) });
DevShell.Icon(GetProfileIconPath()); profile->Commandline(winrt::hstring{ GetProfileCommandLine(instance) });
profile->StartingDirectory(winrt::hstring{ instance.GetInstallationPath() });
profiles.emplace_back(DevShell); profile->Icon(winrt::hstring{ GetProfileIconPath() });
profiles.emplace_back(std::move(profile));
} }
CATCH_LOG(); CATCH_LOG();
} }
return profiles;
}
Profile BaseVisualStudioGenerator::CreateProfile(const std::wstring_view seed)
{
const winrt::guid profileGuid{ Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID,
gsl::as_bytes(gsl::make_span(seed))) };
auto newProfile = winrt::make_self<implementation::Profile>(profileGuid);
newProfile->Origin(OriginTag::Generated);
return *newProfile;
} }

View file

@ -18,14 +18,12 @@ Author(s):
#include "IDynamicProfileGenerator.h" #include "IDynamicProfileGenerator.h"
#include "VsSetupConfiguration.h" #include "VsSetupConfiguration.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class BaseVisualStudioGenerator : public IDynamicProfileGenerator class BaseVisualStudioGenerator : public IDynamicProfileGenerator
{ {
public: public:
// Inherited via IDynamicProfileGenerator void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
std::wstring_view GetNamespace() override = 0;
std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() override;
protected: protected:
virtual bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance& instance) const = 0; virtual bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
@ -33,8 +31,5 @@ namespace Microsoft::Terminal::Settings::Model
virtual std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const = 0; virtual std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
virtual std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const = 0; virtual std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
virtual std::wstring GetProfileIconPath() const = 0; virtual std::wstring GetProfileIconPath() const = 0;
private:
winrt::Microsoft::Terminal::Settings::Model::Profile CreateProfile(const std::wstring_view instanceId);
}; };
}; };

File diff suppressed because it is too large Load diff

View file

@ -20,163 +20,137 @@ Author(s):
#include "CascadiaSettings.g.h" #include "CascadiaSettings.g.h"
#include "GlobalAppSettings.h" #include "GlobalAppSettings.h"
#include "TerminalWarnings.h"
#include "IDynamicProfileGenerator.h"
#include "Profile.h" #include "Profile.h"
#include "ColorScheme.h"
// fwdecl unittest classes namespace winrt::Microsoft::Terminal::Settings::Model
namespace SettingsModelLocalTests
{ {
class SerializationTests; class IDynamicProfileGenerator;
class DeserializationTests; }
class ProfileTests;
class ColorSchemeTests;
class KeyBindingsTests;
};
namespace TerminalAppUnitTests
{
class DynamicProfileTests;
class JsonTests;
};
namespace Microsoft::Terminal::Settings::Model
{
class SettingsTypedDeserializationException;
};
class Microsoft::Terminal::Settings::Model::SettingsTypedDeserializationException final : public std::runtime_error
{
public:
SettingsTypedDeserializationException(const std::string_view description) :
runtime_error(description.data()) {}
};
namespace winrt::Microsoft::Terminal::Settings::Model::implementation namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{ {
winrt::com_ptr<Profile> CreateChild(const winrt::com_ptr<Profile>& parent);
class SettingsTypedDeserializationException final : public std::runtime_error
{
public:
SettingsTypedDeserializationException(const char* message) noexcept :
std::runtime_error(message) {}
};
struct ParsedSettings
{
winrt::com_ptr<implementation::GlobalAppSettings> globals;
winrt::com_ptr<implementation::Profile> baseLayerProfile;
std::vector<winrt::com_ptr<implementation::Profile>> profiles;
std::unordered_map<winrt::guid, winrt::com_ptr<implementation::Profile>> profilesByGuid;
};
struct SettingsLoader
{
static SettingsLoader Default(const std::string_view& userJSON, const std::string_view& inboxJSON);
SettingsLoader(const std::string_view& userJSON, const std::string_view& inboxJSON);
void GenerateProfiles();
void ApplyRuntimeInitialSettings();
void MergeInboxIntoUserSettings();
void FindFragmentsAndMergeIntoUserSettings();
void FinalizeLayering();
bool DisableDeletedProfiles();
ParsedSettings inboxSettings;
ParsedSettings userSettings;
bool duplicateProfile = false;
private:
static std::pair<size_t, size_t> _lineAndColumnFromPosition(const std::string_view& string, const size_t position);
static void _rethrowSerializationExceptionWithLocationInfo(const JsonUtils::DeserializationError& e, const std::string_view& settingsString);
static Json::Value _parseJSON(const std::string_view& content);
static const Json::Value& _getJSONValue(const Json::Value& json, const std::string_view& key) noexcept;
static bool _isValidProfileObject(const Json::Value& profileJson);
gsl::span<const winrt::com_ptr<implementation::Profile>> _getNonUserOriginProfiles() const;
void _parse(const OriginTag origin, const winrt::hstring& source, const std::string_view& content, ParsedSettings& settings);
void _appendProfile(winrt::com_ptr<implementation::Profile>&& profile, ParsedSettings& settings);
void _executeGenerator(const IDynamicProfileGenerator& generator);
std::unordered_set<std::wstring_view> _ignoredNamespaces;
// See _getNonUserOriginProfiles().
size_t _userProfileCount = 0;
};
struct CascadiaSettings : CascadiaSettingsT<CascadiaSettings> struct CascadiaSettings : CascadiaSettingsT<CascadiaSettings>
{ {
public: public:
CascadiaSettings();
explicit CascadiaSettings(const bool addDynamicProfiles);
CascadiaSettings(hstring json);
Model::CascadiaSettings Copy() const;
static Model::CascadiaSettings LoadDefaults(); static Model::CascadiaSettings LoadDefaults();
static Model::CascadiaSettings LoadAll(); static Model::CascadiaSettings LoadAll();
static Model::CascadiaSettings LoadUniversal(); static Model::CascadiaSettings LoadUniversal();
Model::GlobalAppSettings GlobalSettings() const; static winrt::hstring SettingsPath();
Windows::Foundation::Collections::IObservableVector<Model::Profile> AllProfiles() const noexcept; static winrt::hstring DefaultSettingsPath();
Windows::Foundation::Collections::IObservableVector<Model::Profile> ActiveProfiles() const noexcept;
Model::ActionMap ActionMap() const noexcept;
static com_ptr<CascadiaSettings> FromJson(const Json::Value& json);
void LayerJson(const Json::Value& json);
void WriteSettingsToDisk() const;
Json::Value ToJson() const;
static hstring SettingsPath();
static hstring DefaultSettingsPath();
Model::Profile ProfileDefaults() const;
static winrt::hstring ApplicationDisplayName(); static winrt::hstring ApplicationDisplayName();
static winrt::hstring ApplicationVersion(); static winrt::hstring ApplicationVersion();
CascadiaSettings() noexcept = default;
CascadiaSettings(const winrt::hstring& userJSON, const winrt::hstring& inboxJSON);
CascadiaSettings(const std::string_view& userJSON, const std::string_view& inboxJSON = {});
explicit CascadiaSettings(SettingsLoader&& loader);
// user settings
Model::CascadiaSettings Copy() const;
Model::GlobalAppSettings GlobalSettings() const;
winrt::Windows::Foundation::Collections::IObservableVector<Model::Profile> AllProfiles() const noexcept;
winrt::Windows::Foundation::Collections::IObservableVector<Model::Profile> ActiveProfiles() const noexcept;
Model::ActionMap ActionMap() const noexcept;
void WriteSettingsToDisk() const;
Json::Value ToJson() const;
Model::Profile ProfileDefaults() const;
Model::Profile CreateNewProfile(); Model::Profile CreateNewProfile();
Model::Profile FindProfile(const guid& profileGuid) const noexcept; Model::Profile FindProfile(const winrt::guid& guid) const noexcept;
Model::ColorScheme GetColorSchemeForProfile(const Model::Profile& profile) const; Model::ColorScheme GetColorSchemeForProfile(const Model::Profile& profile) const;
void UpdateColorSchemeReferences(const hstring oldName, const hstring newName); void UpdateColorSchemeReferences(const winrt::hstring& oldName, const winrt::hstring& newName);
Windows::Foundation::Collections::IVectorView<SettingsLoadWarnings> Warnings();
void ClearWarnings();
void AppendWarning(SettingsLoadWarnings warning);
Windows::Foundation::IReference<SettingsLoadErrors> GetLoadingError();
hstring GetSerializationErrorMessage();
Model::Profile GetProfileForArgs(const Model::NewTerminalArgs& newTerminalArgs) const; Model::Profile GetProfileForArgs(const Model::NewTerminalArgs& newTerminalArgs) const;
Model::Profile GetProfileByName(const winrt::hstring& name) const;
Model::Profile GetProfileByIndex(uint32_t index) const;
Model::Profile DuplicateProfile(const Model::Profile& source); Model::Profile DuplicateProfile(const Model::Profile& source);
void RefreshDefaultTerminals();
// load errors
winrt::Windows::Foundation::Collections::IVectorView<Model::SettingsLoadWarnings> Warnings() const;
winrt::Windows::Foundation::IReference<Model::SettingsLoadErrors> GetLoadingError() const;
winrt::hstring GetSerializationErrorMessage() const;
// defterm
static bool IsDefaultTerminalAvailable() noexcept; static bool IsDefaultTerminalAvailable() noexcept;
Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> DefaultTerminals() const noexcept; winrt::Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> DefaultTerminals() const noexcept;
Model::DefaultTerminal CurrentDefaultTerminal() const noexcept; Model::DefaultTerminal CurrentDefaultTerminal() noexcept;
void CurrentDefaultTerminal(Model::DefaultTerminal terminal); void CurrentDefaultTerminal(const Model::DefaultTerminal& terminal);
private: private:
com_ptr<GlobalAppSettings> _globals; static const std::filesystem::path& _settingsPath();
Windows::Foundation::Collections::IObservableVector<Model::Profile> _allProfiles;
Windows::Foundation::Collections::IObservableVector<Model::Profile> _activeProfiles;
Windows::Foundation::Collections::IVector<Model::SettingsLoadWarnings> _warnings;
Windows::Foundation::IReference<SettingsLoadErrors> _loadError;
hstring _deserializationErrorMessage;
Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> _defaultTerminals; winrt::com_ptr<implementation::Profile> _createNewProfile(const std::wstring_view& name) const;
Model::DefaultTerminal _currentDefaultTerminal;
std::vector<std::unique_ptr<::Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator>> _profileGenerators; void _resolveDefaultProfile() const;
std::string _userSettingsString; void _validateSettings();
Json::Value _userSettings; void _validateAllSchemesExist();
Json::Value _defaultSettings; void _validateMediaResources();
winrt::com_ptr<Profile> _userDefaultProfileSettings{ nullptr }; void _validateKeybindings() const;
void _validateColorSchemesInCommands() const;
bool _hasInvalidColorScheme(const Model::Command& command) const;
winrt::com_ptr<Profile> _CreateNewProfile(const std::wstring_view& name) const; // user settings
winrt::com_ptr<implementation::GlobalAppSettings> _globals;
winrt::com_ptr<implementation::Profile> _baseLayerProfile;
winrt::Windows::Foundation::Collections::IObservableVector<Model::Profile> _allProfiles;
winrt::Windows::Foundation::Collections::IObservableVector<Model::Profile> _activeProfiles;
void _LayerOrCreateProfile(const Json::Value& profileJson); // load errors
winrt::com_ptr<implementation::Profile> _FindMatchingProfile(const Json::Value& profileJson); winrt::Windows::Foundation::Collections::IVector<Model::SettingsLoadWarnings> _warnings;
std::optional<uint32_t> _FindMatchingProfileIndex(const Json::Value& profileJson); winrt::Windows::Foundation::IReference<Model::SettingsLoadErrors> _loadError;
void _LayerOrCreateColorScheme(const Json::Value& schemeJson); winrt::hstring _deserializationErrorMessage;
Json::Value _ParseUtf8JsonString(std::string_view fileData);
winrt::com_ptr<implementation::ColorScheme> _FindMatchingColorScheme(const Json::Value& schemeJson); // defterm
void _ParseJsonString(std::string_view fileData, const bool isDefaultSettings); Model::DefaultTerminal _currentDefaultTerminal{ nullptr };
static const Json::Value& _GetProfilesJsonObject(const Json::Value& json);
static const Json::Value& _GetDisabledProfileSourcesJsonObject(const Json::Value& json);
bool _PrependSchemaDirective();
bool _AppendDynamicProfilesToUserSettings();
std::string _ApplyFirstRunChangesToSettingsTemplate(std::string_view settingsTemplate) const;
void _CopyProfileInheritanceTree(com_ptr<CascadiaSettings>& cloneSettings) const;
void _ApplyDefaultsFromUserSettings();
void _LoadDynamicProfiles();
void _LoadFragmentExtensions();
void _ApplyJsonStubsHelper(const std::wstring_view directory, const std::unordered_set<std::wstring>& ignoredNamespaces);
std::unordered_set<std::string> _AccumulateJsonFilesInDirectory(const std::wstring_view directory);
void _ParseAndLayerFragmentFiles(const std::unordered_set<std::string> files, const winrt::hstring source);
static const std::filesystem::path& _SettingsPath();
static std::optional<std::string> _ReadUserSettings();
std::optional<guid> _GetProfileGuidByName(const hstring) const;
std::optional<guid> _GetProfileGuidByIndex(std::optional<int> index) const;
void _ValidateSettings();
void _ValidateProfilesExist();
void _ValidateDefaultProfileExists();
void _ValidateNoDuplicateProfiles();
void _ResolveDefaultProfile();
void _ReorderProfilesToMatchUserSettingsOrder();
void _UpdateActiveProfiles();
void _ValidateAllSchemesExist();
void _ValidateMediaResources();
void _ValidateKeybindings();
void _ValidateColorSchemesInCommands();
void _ValidateNoGlobalsKey();
bool _HasInvalidColorScheme(const Model::Command& command);
friend class SettingsModelLocalTests::SerializationTests;
friend class SettingsModelLocalTests::DeserializationTests;
friend class SettingsModelLocalTests::ProfileTests;
friend class SettingsModelLocalTests::ColorSchemeTests;
friend class SettingsModelLocalTests::KeyBindingsTests;
friend class TerminalAppUnitTests::DynamicProfileTests;
friend class TerminalAppUnitTests::JsonTests;
}; };
} }

View file

@ -9,11 +9,6 @@ import "DefaultTerminal.idl";
namespace Microsoft.Terminal.Settings.Model namespace Microsoft.Terminal.Settings.Model
{ {
[default_interface] runtimeclass CascadiaSettings { [default_interface] runtimeclass CascadiaSettings {
CascadiaSettings(String json);
CascadiaSettings Copy();
void WriteSettingsToDisk();
static CascadiaSettings LoadDefaults(); static CascadiaSettings LoadDefaults();
static CascadiaSettings LoadAll(); static CascadiaSettings LoadAll();
static CascadiaSettings LoadUniversal(); static CascadiaSettings LoadUniversal();
@ -23,19 +18,24 @@ namespace Microsoft.Terminal.Settings.Model
static String ApplicationDisplayName { get; }; static String ApplicationDisplayName { get; };
static String ApplicationVersion { get; }; static String ApplicationVersion { get; };
CascadiaSettings(String userJSON, String inboxJSON);
CascadiaSettings Copy();
void WriteSettingsToDisk();
GlobalAppSettings GlobalSettings { get; }; GlobalAppSettings GlobalSettings { get; };
Profile ProfileDefaults { get; }; Profile ProfileDefaults { get; };
Windows.Foundation.Collections.IObservableVector<Profile> AllProfiles { get; }; IObservableVector<Profile> AllProfiles { get; };
Windows.Foundation.Collections.IObservableVector<Profile> ActiveProfiles { get; }; IObservableVector<Profile> ActiveProfiles { get; };
Profile DuplicateProfile(Profile sourceProfile); Profile DuplicateProfile(Profile sourceProfile);
ActionMap ActionMap { get; }; ActionMap ActionMap { get; };
Windows.Foundation.Collections.IVectorView<SettingsLoadWarnings> Warnings { get; }; IVectorView<SettingsLoadWarnings> Warnings { get; };
Windows.Foundation.IReference<SettingsLoadErrors> GetLoadingError { get; }; Windows.Foundation.IReference<SettingsLoadErrors> GetLoadingError { get; };
String GetSerializationErrorMessage { get; }; String GetSerializationErrorMessage { get; };
@ -46,9 +46,8 @@ namespace Microsoft.Terminal.Settings.Model
Profile GetProfileForArgs(NewTerminalArgs newTerminalArgs); Profile GetProfileForArgs(NewTerminalArgs newTerminalArgs);
void RefreshDefaultTerminals();
static Boolean IsDefaultTerminalAvailable { get; }; static Boolean IsDefaultTerminalAvailable { get; };
Windows.Foundation.Collections.IObservableVector<DefaultTerminal> DefaultTerminals { get; }; IObservableVector<DefaultTerminal> DefaultTerminals { get; };
DefaultTerminal CurrentDefaultTerminal; DefaultTerminal CurrentDefaultTerminal;
} }
} }

View file

@ -3,7 +3,6 @@
#include "pch.h" #include "pch.h"
#include "ColorScheme.h" #include "ColorScheme.h"
#include "DefaultSettings.h"
#include "../../types/inc/Utils.hpp" #include "../../types/inc/Utils.hpp"
#include "../../types/inc/colorTable.hpp" #include "../../types/inc/colorTable.hpp"
#include "Utils.h" #include "Utils.h"
@ -41,25 +40,16 @@ static constexpr std::array<std::string_view, 16> TableColors = {
"brightWhite" "brightWhite"
}; };
ColorScheme::ColorScheme() : ColorScheme::ColorScheme() noexcept :
ColorScheme(L"", DEFAULT_FOREGROUND, DEFAULT_BACKGROUND, DEFAULT_CURSOR_COLOR) ColorScheme{ winrt::hstring{} }
{ {
Utils::InitializeCampbellColorTable(_table);
} }
ColorScheme::ColorScheme(winrt::hstring name) : ColorScheme::ColorScheme(const winrt::hstring& name) noexcept :
ColorScheme(name, DEFAULT_FOREGROUND, DEFAULT_BACKGROUND, DEFAULT_CURSOR_COLOR) _Name{ name }
{
Utils::InitializeCampbellColorTable(_table);
}
ColorScheme::ColorScheme(winrt::hstring name, til::color defaultFg, til::color defaultBg, til::color cursorColor) :
_Name{ name },
_Foreground{ defaultFg },
_Background{ defaultBg },
_SelectionBackground{ DEFAULT_FOREGROUND },
_CursorColor{ cursorColor }
{ {
const auto table = Utils::CampbellColorTable();
std::copy_n(table.data(), table.size(), _table.data());
} }
winrt::com_ptr<ColorScheme> ColorScheme::Copy() const winrt::com_ptr<ColorScheme> ColorScheme::Copy() const
@ -79,30 +69,11 @@ winrt::com_ptr<ColorScheme> ColorScheme::Copy() const
// Arguments: // Arguments:
// - json: an object which should be a serialization of a ColorScheme object. // - json: an object which should be a serialization of a ColorScheme object.
// Return Value: // Return Value:
// - a new ColorScheme instance created from the values in `json` // - Returns nullptr for invalid JSON.
winrt::com_ptr<ColorScheme> ColorScheme::FromJson(const Json::Value& json) winrt::com_ptr<ColorScheme> ColorScheme::FromJson(const Json::Value& json)
{ {
auto result = winrt::make_self<ColorScheme>(); auto result = winrt::make_self<ColorScheme>(uninitialized_t{});
result->LayerJson(json); return result->_layerJson(json) ? result : nullptr;
return result;
}
// Method Description:
// - Returns true if we think the provided json object represents an instance of
// the same object as this object. If true, we should layer that json object
// on us, instead of creating a new object.
// Arguments:
// - json: The json object to query to see if it's the same
// Return Value:
// - true iff the json object has the same `name` as we do.
bool ColorScheme::ShouldBeLayered(const Json::Value& json) const
{
std::wstring nameFromJson{};
if (JsonUtils::GetValueForKey(json, NameKey, nameFromJson))
{
return nameFromJson == _Name;
}
return false;
} }
// Method Description: // Method Description:
@ -112,21 +83,27 @@ bool ColorScheme::ShouldBeLayered(const Json::Value& json) const
// the new json object. Properties that _aren't_ in the json object will _not_ // the new json object. Properties that _aren't_ in the json object will _not_
// be replaced. // be replaced.
// Arguments: // Arguments:
// - json: an object which should be a partial serialization of a ColorScheme object. // - json: an object which should be a full serialization of a ColorScheme object.
// Return Value: // Return Value:
// <none> // - Returns true if the given JSON was valid.
void ColorScheme::LayerJson(const Json::Value& json) bool ColorScheme::_layerJson(const Json::Value& json)
{ {
JsonUtils::GetValueForKey(json, NameKey, _Name); // Required fields
auto isValid = JsonUtils::GetValueForKey(json, NameKey, _Name);
// Optional fields (they have defaults in ColorScheme.h)
JsonUtils::GetValueForKey(json, ForegroundKey, _Foreground); JsonUtils::GetValueForKey(json, ForegroundKey, _Foreground);
JsonUtils::GetValueForKey(json, BackgroundKey, _Background); JsonUtils::GetValueForKey(json, BackgroundKey, _Background);
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground); JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor); JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor);
// Required fields
for (unsigned int i = 0; i < TableColors.size(); ++i) for (unsigned int i = 0; i < TableColors.size(); ++i)
{ {
JsonUtils::GetValueForKey(json, til::at(TableColors, i), _table.at(i)); isValid &= JsonUtils::GetValueForKey(json, til::at(TableColors, i), til::at(_table, i));
} }
return isValid;
} }
// Method Description: // Method Description:
@ -147,7 +124,7 @@ Json::Value ColorScheme::ToJson() const
for (unsigned int i = 0; i < TableColors.size(); ++i) for (unsigned int i = 0; i < TableColors.size(); ++i)
{ {
JsonUtils::SetValueForKey(json, til::at(TableColors, i), _table.at(i)); JsonUtils::SetValueForKey(json, til::at(TableColors, i), til::at(_table, i));
} }
return json; return json;
@ -155,9 +132,7 @@ Json::Value ColorScheme::ToJson() const
winrt::com_array<winrt::Microsoft::Terminal::Core::Color> ColorScheme::Table() const noexcept winrt::com_array<winrt::Microsoft::Terminal::Core::Color> ColorScheme::Table() const noexcept
{ {
winrt::com_array<winrt::Microsoft::Terminal::Core::Color> result{ base::checked_cast<uint32_t>(_table.size()) }; return winrt::com_array<Core::Color>{ _table };
std::transform(_table.begin(), _table.end(), result.begin(), [](til::color c) -> winrt::Microsoft::Terminal::Core::Color { return c; });
return result;
} }
// Method Description: // Method Description:
@ -167,44 +142,8 @@ winrt::com_array<winrt::Microsoft::Terminal::Core::Color> ColorScheme::Table() c
// - value: the color value we are setting the color table color to // - value: the color value we are setting the color table color to
// Return Value: // Return Value:
// - none // - none
void ColorScheme::SetColorTableEntry(uint8_t index, const winrt::Microsoft::Terminal::Core::Color& value) noexcept void ColorScheme::SetColorTableEntry(uint8_t index, const Core::Color& value) noexcept
{ {
THROW_HR_IF(E_INVALIDARG, index > _table.size() - 1); THROW_HR_IF(E_INVALIDARG, index >= _table.size());
_table[index] = value; _table[index] = value;
} }
// Method Description:
// - Validates a given color scheme
// - A color scheme is valid if it has a name and defines all the colors
// Arguments:
// - The color scheme to validate
// Return Value:
// - true if the scheme is valid, false otherwise
bool ColorScheme::ValidateColorScheme(const Json::Value& scheme)
{
for (const auto& key : TableColors)
{
if (!scheme.isMember(JsonKey(key)))
{
return false;
}
}
if (!scheme.isMember(JsonKey(NameKey)))
{
return false;
}
return true;
}
// Method Description:
// - Parse the name from the JSON representation of a ColorScheme.
// Arguments:
// - json: an object which should be a serialization of a ColorScheme object.
// Return Value:
// - the name of the color scheme represented by `json` as a std::wstring optional
// i.e. the value of the `name` property.
// - returns std::nullopt if `json` doesn't have the `name` property
std::optional<std::wstring> ColorScheme::GetNameFromJson(const Json::Value& json)
{
return JsonUtils::GetValueForKey<std::optional<std::wstring>>(json, NameKey);
}

View file

@ -15,38 +15,28 @@ Author(s):
--*/ --*/
#pragma once #pragma once
#include "../../inc/conattrs.hpp" #include "../../inc/conattrs.hpp"
#include "inc/cppwinrt_utils.h" #include "inc/cppwinrt_utils.h"
#include "DefaultSettings.h"
#include "ColorScheme.g.h" #include "ColorScheme.g.h"
// fwdecl unittest classes
namespace SettingsModelLocalTests
{
class SettingsTests;
class ColorSchemeTests;
};
// Use this macro to quick implement both the getter and setter for a color property.
// This should only be used for color types where there's no logic in the
// getter/setter beyond just accessing/updating the value.
// This takes advantage of til::color
#define WINRT_TERMINAL_COLOR_PROPERTY(name, ...) \
public: \
winrt::Microsoft::Terminal::Core::Color name() const noexcept { return _##name; } \
void name(const winrt::Microsoft::Terminal::Core::Color& value) noexcept { _##name = value; } \
\
private: \
til::color _##name{ __VA_ARGS__ };
namespace winrt::Microsoft::Terminal::Settings::Model::implementation namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{ {
struct ColorScheme : ColorSchemeT<ColorScheme> struct ColorScheme : ColorSchemeT<ColorScheme>
{ {
// A ColorScheme constructed with uninitialized_t
// leaves _table uninitialized.
struct uninitialized_t
{
};
public: public:
ColorScheme(); ColorScheme() noexcept;
ColorScheme(hstring name); explicit ColorScheme(uninitialized_t) noexcept {}
ColorScheme(hstring name, til::color defaultFg, til::color defaultBg, til::color cursorColor); explicit ColorScheme(const winrt::hstring& name) noexcept;
com_ptr<ColorScheme> Copy() const; com_ptr<ColorScheme> Copy() const;
hstring ToString() hstring ToString()
@ -55,29 +45,21 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
} }
static com_ptr<ColorScheme> FromJson(const Json::Value& json); static com_ptr<ColorScheme> FromJson(const Json::Value& json);
bool ShouldBeLayered(const Json::Value& json) const;
void LayerJson(const Json::Value& json);
Json::Value ToJson() const; Json::Value ToJson() const;
static std::optional<std::wstring> GetNameFromJson(const Json::Value& json); com_array<Core::Color> Table() const noexcept;
void SetColorTableEntry(uint8_t index, const Core::Color& value) noexcept;
com_array<winrt::Microsoft::Terminal::Core::Color> Table() const noexcept;
void SetColorTableEntry(uint8_t index, const winrt::Microsoft::Terminal::Core::Color& value) noexcept;
static bool ValidateColorScheme(const Json::Value& scheme);
WINRT_PROPERTY(winrt::hstring, Name); WINRT_PROPERTY(winrt::hstring, Name);
WINRT_TERMINAL_COLOR_PROPERTY(Foreground); // defined in constructor WINRT_PROPERTY(Core::Color, Foreground, static_cast<Core::Color>(DEFAULT_FOREGROUND));
WINRT_TERMINAL_COLOR_PROPERTY(Background); // defined in constructor WINRT_PROPERTY(Core::Color, Background, static_cast<Core::Color>(DEFAULT_BACKGROUND));
WINRT_TERMINAL_COLOR_PROPERTY(SelectionBackground); // defined in constructor WINRT_PROPERTY(Core::Color, SelectionBackground, static_cast<Core::Color>(DEFAULT_FOREGROUND));
WINRT_TERMINAL_COLOR_PROPERTY(CursorColor); // defined in constructor WINRT_PROPERTY(Core::Color, CursorColor, static_cast<Core::Color>(DEFAULT_CURSOR_COLOR));
private: private:
std::array<til::color, COLOR_TABLE_SIZE> _table; bool _layerJson(const Json::Value& json);
friend class SettingsModelLocalTests::SettingsTests; std::array<Core::Color, COLOR_TABLE_SIZE> _table;
friend class SettingsModelLocalTests::ColorSchemeTests;
}; };
} }

View file

@ -2,7 +2,7 @@
// Licensed under the MIT license. // Licensed under the MIT license.
#include "pch.h" #include "pch.h"
#include "DefaultProfileUtils.h" #include "DynamicProfileUtils.h"
#include "../../types/inc/utils.hpp" #include "../../types/inc/utils.hpp"
static constexpr std::wstring_view PACKAGED_PROFILE_ICON_PATH{ L"ms-appx:///ProfileIcons/" }; static constexpr std::wstring_view PACKAGED_PROFILE_ICON_PATH{ L"ms-appx:///ProfileIcons/" };
@ -15,20 +15,16 @@ static constexpr std::wstring_view PACKAGED_PROFILE_ICON_EXTENSION{ L".png" };
// - name: the name of the new profile. // - name: the name of the new profile.
// Return Value: // Return Value:
// - A Profile, ready to be filled in // - A Profile, ready to be filled in
winrt::Microsoft::Terminal::Settings::Model::Profile CreateDefaultProfile(const std::wstring_view name) winrt::com_ptr<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile> CreateDynamicProfile(const std::wstring_view& name)
{ {
const winrt::guid profileGuid{ Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, const auto profileGuid = Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(name)));
gsl::as_bytes(gsl::make_span(name))) };
auto newProfile = winrt::make_self<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile>(profileGuid);
newProfile->Name(winrt::hstring{ name });
std::wstring iconPath{ PACKAGED_PROFILE_ICON_PATH }; std::wstring iconPath{ PACKAGED_PROFILE_ICON_PATH };
iconPath.append(Microsoft::Console::Utils::GuidToString(profileGuid)); iconPath.append(Microsoft::Console::Utils::GuidToString(profileGuid));
iconPath.append(PACKAGED_PROFILE_ICON_EXTENSION); iconPath.append(PACKAGED_PROFILE_ICON_EXTENSION);
newProfile->Icon(winrt::hstring{ iconPath }); auto profile = winrt::make_self<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile>(profileGuid);
newProfile->Origin(winrt::Microsoft::Terminal::Settings::Model::OriginTag::Generated); profile->Name(winrt::hstring{ name });
profile->Icon(winrt::hstring{ iconPath });
return *newProfile; return profile;
} }

View file

@ -23,4 +23,4 @@ Author(s):
// uuidv5 properties: name format is UTF-16LE bytes // uuidv5 properties: name format is UTF-16LE bytes
static constexpr GUID TERMINAL_PROFILE_NAMESPACE_GUID = { 0x2bde4a90, 0xd05f, 0x401c, { 0x94, 0x92, 0xe4, 0x8, 0x84, 0xea, 0xd1, 0xd8 } }; static constexpr GUID TERMINAL_PROFILE_NAMESPACE_GUID = { 0x2bde4a90, 0xd05f, 0x401c, { 0x94, 0x92, 0xe4, 0x8, 0x84, 0xea, 0xd1, 0xd8 } };
winrt::Microsoft::Terminal::Settings::Model::Profile CreateDefaultProfile(const std::wstring_view name); winrt::com_ptr<winrt::Microsoft::Terminal::Settings::Model::implementation::Profile> CreateDynamicProfile(const std::wstring_view& name);

View file

@ -11,7 +11,7 @@
static constexpr std::string_view Utf8Bom{ u8"\uFEFF" }; static constexpr std::string_view Utf8Bom{ u8"\uFEFF" };
static constexpr std::wstring_view UnpackagedSettingsFolderName{ L"Microsoft\\Windows Terminal\\" }; static constexpr std::wstring_view UnpackagedSettingsFolderName{ L"Microsoft\\Windows Terminal\\" };
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
// Returns a path like C:\Users\<username>\AppData\Local\Packages\<packagename>\LocalState // Returns a path like C:\Users\<username>\AppData\Local\Packages\<packagename>\LocalState
// You can put your settings.json or state.json in this directory. // You can put your settings.json or state.json in this directory.
@ -106,7 +106,7 @@ namespace Microsoft::Terminal::Settings::Model
} }
} }
void WriteUTF8File(const std::filesystem::path& path, const std::string_view content) void WriteUTF8File(const std::filesystem::path& path, const std::string_view& content)
{ {
wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) }; wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) };
THROW_LAST_ERROR_IF(!file); THROW_LAST_ERROR_IF(!file);
@ -121,7 +121,7 @@ namespace Microsoft::Terminal::Settings::Model
} }
} }
void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view content) void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view& content)
{ {
// GH#10787: rename() will replace symbolic links themselves and not the path they point at. // GH#10787: rename() will replace symbolic links themselves and not the path they point at.
// It's thus important that we first resolve them before generating temporary path. // It's thus important that we first resolve them before generating temporary path.

View file

@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT license. // Licensed under the MIT license.
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
std::filesystem::path GetBaseSettingsPath(); std::filesystem::path GetBaseSettingsPath();
std::string ReadUTF8File(const std::filesystem::path& path); std::string ReadUTF8File(const std::filesystem::path& path);
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path); std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path);
void WriteUTF8File(const std::filesystem::path& path, const std::string_view content); void WriteUTF8File(const std::filesystem::path& path, const std::string_view& content);
void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view content); void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view& content);
} }

View file

@ -4,6 +4,7 @@
#include "pch.h" #include "pch.h"
#include "FontConfig.h" #include "FontConfig.h"
#include "FontConfig.g.cpp" #include "FontConfig.g.cpp"
#include "TerminalSettingsSerializationHelpers.h" #include "TerminalSettingsSerializationHelpers.h"
#include "JsonUtils.h" #include "JsonUtils.h"
@ -25,7 +26,7 @@ winrt::Microsoft::Terminal::Settings::Model::implementation::FontConfig::FontCon
{ {
} }
winrt::com_ptr<FontConfig> FontConfig::CopyFontInfo(const winrt::com_ptr<FontConfig> source, winrt::weak_ref<Profile> sourceProfile) winrt::com_ptr<FontConfig> FontConfig::CopyFontInfo(const FontConfig* source, winrt::weak_ref<Profile> sourceProfile)
{ {
auto fontInfo{ winrt::make_self<FontConfig>(std::move(sourceProfile)) }; auto fontInfo{ winrt::make_self<FontConfig>(std::move(sourceProfile)) };
fontInfo->_FontFace = source->_FontFace; fontInfo->_FontFace = source->_FontFace;

View file

@ -32,7 +32,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{ {
public: public:
FontConfig(winrt::weak_ref<Profile> sourceProfile); FontConfig(winrt::weak_ref<Profile> sourceProfile);
static winrt::com_ptr<FontConfig> CopyFontInfo(const winrt::com_ptr<FontConfig> source, winrt::weak_ref<Profile> sourceProfile); static winrt::com_ptr<FontConfig> CopyFontInfo(const FontConfig* source, winrt::weak_ref<Profile> sourceProfile);
Json::Value ToJson() const; Json::Value ToJson() const;
void LayerJson(const Json::Value& json); void LayerJson(const Json::Value& json);
bool HasAnyOptionSet() const; bool HasAnyOptionSet() const;

View file

@ -4,9 +4,7 @@
#include "pch.h" #include "pch.h"
#include "GlobalAppSettings.h" #include "GlobalAppSettings.h"
#include "../../types/inc/Utils.hpp" #include "../../types/inc/Utils.hpp"
#include "../../inc/DefaultSettings.h"
#include "JsonUtils.h" #include "JsonUtils.h"
#include "TerminalSettingsSerializationHelpers.h"
#include "KeyChordSerialization.h" #include "KeyChordSerialization.h"
#include "GlobalAppSettings.g.cpp" #include "GlobalAppSettings.g.cpp"
@ -52,6 +50,7 @@ static constexpr std::string_view WindowingBehaviorKey{ "windowingBehavior" };
static constexpr std::string_view TrimBlockSelectionKey{ "trimBlockSelection" }; static constexpr std::string_view TrimBlockSelectionKey{ "trimBlockSelection" };
static constexpr std::string_view AlwaysShowNotificationIconKey{ "alwaysShowNotificationIcon" }; static constexpr std::string_view AlwaysShowNotificationIconKey{ "alwaysShowNotificationIcon" };
static constexpr std::string_view MinimizeToNotificationAreaKey{ "minimizeToNotificationArea" }; static constexpr std::string_view MinimizeToNotificationAreaKey{ "minimizeToNotificationArea" };
static constexpr std::string_view DisabledProfileSourcesKey{ "disabledProfileSources" };
static constexpr std::string_view DebugFeaturesKey{ "debugFeatures" }; static constexpr std::string_view DebugFeaturesKey{ "debugFeatures" };
@ -60,26 +59,6 @@ static constexpr std::string_view SoftwareRenderingKey{ "experimental.rendering.
static constexpr std::string_view ForceVTInputKey{ "experimental.input.forceVT" }; static constexpr std::string_view ForceVTInputKey{ "experimental.input.forceVT" };
static constexpr std::string_view DetectURLsKey{ "experimental.detectURLs" }; static constexpr std::string_view DetectURLsKey{ "experimental.detectURLs" };
#ifdef _DEBUG
static constexpr bool debugFeaturesDefault{ true };
#else
static constexpr bool debugFeaturesDefault{ false };
#endif
bool GlobalAppSettings::_getDefaultDebugFeaturesValue()
{
return debugFeaturesDefault;
}
GlobalAppSettings::GlobalAppSettings() :
_actionMap{ winrt::make_self<implementation::ActionMap>() },
_keybindingsWarnings{},
_validDefaultProfile{ false },
_defaultProfile{}
{
_colorSchemes = winrt::single_threaded_map<winrt::hstring, Model::ColorScheme>();
}
// Method Description: // Method Description:
// - Copies any extraneous data from the parent before completing a CreateChild call // - Copies any extraneous data from the parent before completing a CreateChild call
// Arguments: // Arguments:
@ -88,13 +67,17 @@ GlobalAppSettings::GlobalAppSettings() :
// - <none> // - <none>
void GlobalAppSettings::_FinalizeInheritance() void GlobalAppSettings::_FinalizeInheritance()
{ {
// Globals only ever has 1 parent for (const auto& parent : _parents)
FAIL_FAST_IF(_parents.size() > 1);
for (auto parent : _parents)
{ {
_actionMap->InsertParent(parent->_actionMap); _actionMap->InsertParent(parent->_actionMap);
_keybindingsWarnings = std::move(parent->_keybindingsWarnings); _keybindingsWarnings.insert(_keybindingsWarnings.end(), parent->_keybindingsWarnings.begin(), parent->_keybindingsWarnings.end());
_colorSchemes = std::move(parent->_colorSchemes); for (const auto& [k, v] : parent->_colorSchemes)
{
if (!_colorSchemes.HasKey(k))
{
_colorSchemes.Insert(k, v);
}
}
} }
} }
@ -137,12 +120,12 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
globals->_DetectURLs = _DetectURLs; globals->_DetectURLs = _DetectURLs;
globals->_MinimizeToNotificationArea = _MinimizeToNotificationArea; globals->_MinimizeToNotificationArea = _MinimizeToNotificationArea;
globals->_AlwaysShowNotificationIcon = _AlwaysShowNotificationIcon; globals->_AlwaysShowNotificationIcon = _AlwaysShowNotificationIcon;
globals->_DisabledProfileSources = _DisabledProfileSources;
globals->_UnparsedDefaultProfile = _UnparsedDefaultProfile; globals->_UnparsedDefaultProfile = _UnparsedDefaultProfile;
globals->_validDefaultProfile = _validDefaultProfile;
globals->_defaultProfile = _defaultProfile; globals->_defaultProfile = _defaultProfile;
globals->_actionMap = _actionMap->Copy(); globals->_actionMap = _actionMap->Copy();
std::copy(_keybindingsWarnings.begin(), _keybindingsWarnings.end(), std::back_inserter(globals->_keybindingsWarnings)); globals->_keybindingsWarnings = _keybindingsWarnings;
if (_colorSchemes) if (_colorSchemes)
{ {
@ -153,9 +136,7 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
} }
} }
// Globals only ever has 1 parent for (const auto& parent : _parents)
FAIL_FAST_IF(_parents.size() > 1);
for (auto parent : _parents)
{ {
globals->InsertParent(parent->Copy()); globals->InsertParent(parent->Copy());
} }
@ -168,69 +149,18 @@ winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Microso
} }
#pragma region DefaultProfile #pragma region DefaultProfile
void GlobalAppSettings::DefaultProfile(const winrt::guid& defaultProfile) noexcept void GlobalAppSettings::DefaultProfile(const winrt::guid& defaultProfile) noexcept
{ {
_validDefaultProfile = true;
_defaultProfile = defaultProfile; _defaultProfile = defaultProfile;
_UnparsedDefaultProfile = Utils::GuidToString(defaultProfile); _UnparsedDefaultProfile = Utils::GuidToString(defaultProfile);
} }
winrt::guid GlobalAppSettings::DefaultProfile() const winrt::guid GlobalAppSettings::DefaultProfile() const
{ {
// If we have an unresolved default profile, we should likely explode.
THROW_HR_IF(E_INVALIDARG, !_validDefaultProfile);
return _defaultProfile; return _defaultProfile;
} }
bool GlobalAppSettings::HasUnparsedDefaultProfile() const
{
return _UnparsedDefaultProfile.has_value();
}
winrt::hstring GlobalAppSettings::UnparsedDefaultProfile() const
{
const auto val{ _getUnparsedDefaultProfileImpl() };
return val ? *val : hstring{ L"" };
}
void GlobalAppSettings::UnparsedDefaultProfile(const hstring& value)
{
if (_UnparsedDefaultProfile != value)
{
_UnparsedDefaultProfile = value;
_validDefaultProfile = false;
}
}
void GlobalAppSettings::ClearUnparsedDefaultProfile()
{
if (HasUnparsedDefaultProfile())
{
_UnparsedDefaultProfile = std::nullopt;
}
}
std::optional<winrt::hstring> GlobalAppSettings::_getUnparsedDefaultProfileImpl() const
{
/*return user set value*/
if (_UnparsedDefaultProfile)
{
return _UnparsedDefaultProfile;
}
/*user set value was not set*/
/*iterate through parents to find a value*/
for (auto parent : _parents)
{
if (auto val{ parent->_getUnparsedDefaultProfileImpl() })
{
return val;
}
}
/*no value was found*/
return std::nullopt;
}
#pragma endregion #pragma endregion
winrt::Microsoft::Terminal::Settings::Model::ActionMap GlobalAppSettings::ActionMap() const noexcept winrt::Microsoft::Terminal::Settings::Model::ActionMap GlobalAppSettings::ActionMap() const noexcept
@ -253,92 +183,53 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::FromJson(const Json::Value&
void GlobalAppSettings::LayerJson(const Json::Value& json) void GlobalAppSettings::LayerJson(const Json::Value& json)
{ {
// _validDefaultProfile keeps track of whether we've verified that DefaultProfile points to something
// CascadiaSettings::_ResolveDefaultProfile performs a validation and updates DefaultProfile() with the
// resolved value, then making it valid.
_validDefaultProfile = false;
JsonUtils::GetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile); JsonUtils::GetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile);
JsonUtils::GetValueForKey(json, AlwaysShowTabsKey, _AlwaysShowTabs); JsonUtils::GetValueForKey(json, AlwaysShowTabsKey, _AlwaysShowTabs);
JsonUtils::GetValueForKey(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs); JsonUtils::GetValueForKey(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs);
JsonUtils::GetValueForKey(json, InitialRowsKey, _InitialRows); JsonUtils::GetValueForKey(json, InitialRowsKey, _InitialRows);
JsonUtils::GetValueForKey(json, InitialColsKey, _InitialCols); JsonUtils::GetValueForKey(json, InitialColsKey, _InitialCols);
JsonUtils::GetValueForKey(json, InitialPositionKey, _InitialPosition); JsonUtils::GetValueForKey(json, InitialPositionKey, _InitialPosition);
JsonUtils::GetValueForKey(json, CenterOnLaunchKey, _CenterOnLaunch); JsonUtils::GetValueForKey(json, CenterOnLaunchKey, _CenterOnLaunch);
JsonUtils::GetValueForKey(json, ShowTitleInTitlebarKey, _ShowTitleInTitlebar); JsonUtils::GetValueForKey(json, ShowTitleInTitlebarKey, _ShowTitleInTitlebar);
JsonUtils::GetValueForKey(json, ShowTabsInTitlebarKey, _ShowTabsInTitlebar); JsonUtils::GetValueForKey(json, ShowTabsInTitlebarKey, _ShowTabsInTitlebar);
JsonUtils::GetValueForKey(json, WordDelimitersKey, _WordDelimiters); JsonUtils::GetValueForKey(json, WordDelimitersKey, _WordDelimiters);
JsonUtils::GetValueForKey(json, CopyOnSelectKey, _CopyOnSelect); JsonUtils::GetValueForKey(json, CopyOnSelectKey, _CopyOnSelect);
JsonUtils::GetValueForKey(json, InputServiceWarningKey, _InputServiceWarning); JsonUtils::GetValueForKey(json, InputServiceWarningKey, _InputServiceWarning);
JsonUtils::GetValueForKey(json, CopyFormattingKey, _CopyFormatting); JsonUtils::GetValueForKey(json, CopyFormattingKey, _CopyFormatting);
JsonUtils::GetValueForKey(json, WarnAboutLargePasteKey, _WarnAboutLargePaste); JsonUtils::GetValueForKey(json, WarnAboutLargePasteKey, _WarnAboutLargePaste);
JsonUtils::GetValueForKey(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste); JsonUtils::GetValueForKey(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste);
JsonUtils::GetValueForKey(json, FirstWindowPreferenceKey, _FirstWindowPreference); JsonUtils::GetValueForKey(json, FirstWindowPreferenceKey, _FirstWindowPreference);
JsonUtils::GetValueForKey(json, LaunchModeKey, _LaunchMode); JsonUtils::GetValueForKey(json, LaunchModeKey, _LaunchMode);
JsonUtils::GetValueForKey(json, LanguageKey, _Language); JsonUtils::GetValueForKey(json, LanguageKey, _Language);
JsonUtils::GetValueForKey(json, ThemeKey, _Theme); JsonUtils::GetValueForKey(json, ThemeKey, _Theme);
JsonUtils::GetValueForKey(json, TabWidthModeKey, _TabWidthMode); JsonUtils::GetValueForKey(json, TabWidthModeKey, _TabWidthMode);
JsonUtils::GetValueForKey(json, UseAcrylicInTabRowKey, _UseAcrylicInTabRow); JsonUtils::GetValueForKey(json, UseAcrylicInTabRowKey, _UseAcrylicInTabRow);
JsonUtils::GetValueForKey(json, SnapToGridOnResizeKey, _SnapToGridOnResize); JsonUtils::GetValueForKey(json, SnapToGridOnResizeKey, _SnapToGridOnResize);
// GetValueForKey will only override the current value if the key exists // GetValueForKey will only override the current value if the key exists
JsonUtils::GetValueForKey(json, DebugFeaturesKey, _DebugFeaturesEnabled); JsonUtils::GetValueForKey(json, DebugFeaturesKey, _DebugFeaturesEnabled);
JsonUtils::GetValueForKey(json, ForceFullRepaintRenderingKey, _ForceFullRepaintRendering); JsonUtils::GetValueForKey(json, ForceFullRepaintRenderingKey, _ForceFullRepaintRendering);
JsonUtils::GetValueForKey(json, SoftwareRenderingKey, _SoftwareRendering); JsonUtils::GetValueForKey(json, SoftwareRenderingKey, _SoftwareRendering);
JsonUtils::GetValueForKey(json, ForceVTInputKey, _ForceVTInput); JsonUtils::GetValueForKey(json, ForceVTInputKey, _ForceVTInput);
JsonUtils::GetValueForKey(json, EnableStartupTaskKey, _StartOnUserLogin); JsonUtils::GetValueForKey(json, EnableStartupTaskKey, _StartOnUserLogin);
JsonUtils::GetValueForKey(json, AlwaysOnTopKey, _AlwaysOnTop); JsonUtils::GetValueForKey(json, AlwaysOnTopKey, _AlwaysOnTop);
// GH#8076 - when adding enum values to this key, we also changed it from // GH#8076 - when adding enum values to this key, we also changed it from
// "useTabSwitcher" to "tabSwitcherMode". Continue supporting // "useTabSwitcher" to "tabSwitcherMode". Continue supporting
// "useTabSwitcher", but prefer "tabSwitcherMode" // "useTabSwitcher", but prefer "tabSwitcherMode"
JsonUtils::GetValueForKey(json, LegacyUseTabSwitcherModeKey, _TabSwitcherMode); JsonUtils::GetValueForKey(json, LegacyUseTabSwitcherModeKey, _TabSwitcherMode);
JsonUtils::GetValueForKey(json, TabSwitcherModeKey, _TabSwitcherMode); JsonUtils::GetValueForKey(json, TabSwitcherModeKey, _TabSwitcherMode);
JsonUtils::GetValueForKey(json, DisableAnimationsKey, _DisableAnimations); JsonUtils::GetValueForKey(json, DisableAnimationsKey, _DisableAnimations);
JsonUtils::GetValueForKey(json, StartupActionsKey, _StartupActions); JsonUtils::GetValueForKey(json, StartupActionsKey, _StartupActions);
JsonUtils::GetValueForKey(json, FocusFollowMouseKey, _FocusFollowMouse); JsonUtils::GetValueForKey(json, FocusFollowMouseKey, _FocusFollowMouse);
JsonUtils::GetValueForKey(json, WindowingBehaviorKey, _WindowingBehavior); JsonUtils::GetValueForKey(json, WindowingBehaviorKey, _WindowingBehavior);
JsonUtils::GetValueForKey(json, TrimBlockSelectionKey, _TrimBlockSelection); JsonUtils::GetValueForKey(json, TrimBlockSelectionKey, _TrimBlockSelection);
JsonUtils::GetValueForKey(json, DetectURLsKey, _DetectURLs); JsonUtils::GetValueForKey(json, DetectURLsKey, _DetectURLs);
JsonUtils::GetValueForKey(json, MinimizeToNotificationAreaKey, _MinimizeToNotificationArea); JsonUtils::GetValueForKey(json, MinimizeToNotificationAreaKey, _MinimizeToNotificationArea);
JsonUtils::GetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon); JsonUtils::GetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon);
JsonUtils::GetValueForKey(json, DisabledProfileSourcesKey, _DisabledProfileSources);
// This is a helper lambda to get the keybindings and commands out of both static constexpr std::array bindingsKeys{ LegacyKeybindingsKey, ActionsKey };
// and array of objects. We'll use this twice, once on the legacy for (const auto& jsonKey : bindingsKeys)
// `keybindings` key, and again on the newer `bindings` key. {
auto parseBindings = [this, &json](auto jsonKey) {
if (auto bindings{ json[JsonKey(jsonKey)] }) if (auto bindings{ json[JsonKey(jsonKey)] })
{ {
auto warnings = _actionMap->LayerJson(bindings); auto warnings = _actionMap->LayerJson(bindings);
@ -351,9 +242,7 @@ void GlobalAppSettings::LayerJson(const Json::Value& json)
// list of warnings. // list of warnings.
_keybindingsWarnings.insert(_keybindingsWarnings.end(), warnings.begin(), warnings.end()); _keybindingsWarnings.insert(_keybindingsWarnings.end(), warnings.begin(), warnings.end());
} }
}; }
parseBindings(LegacyKeybindingsKey);
parseBindings(ActionsKey);
} }
// Method Description: // Method Description:
@ -381,7 +270,7 @@ void GlobalAppSettings::RemoveColorScheme(hstring schemeName)
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
std::vector<winrt::Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> GlobalAppSettings::KeybindingsWarnings() const const std::vector<winrt::Microsoft::Terminal::Settings::Model::SettingsLoadWarnings>& GlobalAppSettings::KeybindingsWarnings() const
{ {
return _keybindingsWarnings; return _keybindingsWarnings;
} }
@ -433,7 +322,8 @@ Json::Value GlobalAppSettings::ToJson() const
JsonUtils::SetValueForKey(json, TrimBlockSelectionKey, _TrimBlockSelection); JsonUtils::SetValueForKey(json, TrimBlockSelectionKey, _TrimBlockSelection);
JsonUtils::SetValueForKey(json, DetectURLsKey, _DetectURLs); JsonUtils::SetValueForKey(json, DetectURLsKey, _DetectURLs);
JsonUtils::SetValueForKey(json, MinimizeToNotificationAreaKey, _MinimizeToNotificationArea); JsonUtils::SetValueForKey(json, MinimizeToNotificationAreaKey, _MinimizeToNotificationArea);
JsonUtils::SetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon); JsonUtils::SetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon);
JsonUtils::SetValueForKey(json, DisabledProfileSourcesKey, _DisabledProfileSources);
// clang-format on // clang-format on
json[JsonKey(ActionsKey)] = _actionMap->ToJson(); json[JsonKey(ActionsKey)] = _actionMap->ToJson();

View file

@ -34,7 +34,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
struct GlobalAppSettings : GlobalAppSettingsT<GlobalAppSettings>, IInheritable<GlobalAppSettings> struct GlobalAppSettings : GlobalAppSettingsT<GlobalAppSettings>, IInheritable<GlobalAppSettings>
{ {
public: public:
GlobalAppSettings();
void _FinalizeInheritance() override; void _FinalizeInheritance() override;
com_ptr<GlobalAppSettings> Copy() const; com_ptr<GlobalAppSettings> Copy() const;
@ -49,16 +48,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
Json::Value ToJson() const; Json::Value ToJson() const;
std::vector<SettingsLoadWarnings> KeybindingsWarnings() const; const std::vector<SettingsLoadWarnings>& KeybindingsWarnings() const;
// These are implemented manually to handle the string/GUID exchange // This DefaultProfile() setter is called by CascadiaSettings,
// by higher layers in the app. // when it parses UnparsedDefaultProfile in _finalizeSettings().
void DefaultProfile(const guid& defaultProfile) noexcept; void DefaultProfile(const guid& defaultProfile) noexcept;
guid DefaultProfile() const; guid DefaultProfile() const;
bool HasUnparsedDefaultProfile() const;
winrt::hstring UnparsedDefaultProfile() const;
void UnparsedDefaultProfile(const hstring& value);
void ClearUnparsedDefaultProfile();
// TODO GH#9207: Remove this once we have a GlobalAppSettingsViewModel in TerminalSettingsEditor // TODO GH#9207: Remove this once we have a GlobalAppSettingsViewModel in TerminalSettingsEditor
void SetInvertedDisableAnimationsValue(bool invertedDisableAnimationsValue) void SetInvertedDisableAnimationsValue(bool invertedDisableAnimationsValue)
@ -90,7 +85,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ForceFullRepaintRendering, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ForceFullRepaintRendering, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, SoftwareRendering, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, SoftwareRendering, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ForceVTInput, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ForceVTInput, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, DebugFeaturesEnabled, _getDefaultDebugFeaturesValue()); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, DebugFeaturesEnabled, debugFeaturesDefault);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, StartOnUserLogin, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, StartOnUserLogin, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysOnTop, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysOnTop, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, Model::TabSwitcherMode, TabSwitcherMode, Model::TabSwitcherMode::InOrder); INHERITABLE_SETTING(Model::GlobalAppSettings, Model::TabSwitcherMode, TabSwitcherMode, Model::TabSwitcherMode::InOrder);
@ -102,21 +97,19 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, DetectURLs, true); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, DetectURLs, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, MinimizeToNotificationArea, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, MinimizeToNotificationArea, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysShowNotificationIcon, false); INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysShowNotificationIcon, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, DisabledProfileSources, nullptr);
INHERITABLE_SETTING(Model::GlobalAppSettings, hstring, UnparsedDefaultProfile, L"");
private: private:
guid _defaultProfile; #ifdef NDEBUG
std::optional<hstring> _UnparsedDefaultProfile{ std::nullopt }; static constexpr bool debugFeaturesDefault{ false };
bool _validDefaultProfile; #else
static constexpr bool debugFeaturesDefault{ true };
#endif
com_ptr<implementation::ActionMap> _actionMap; winrt::guid _defaultProfile;
winrt::com_ptr<implementation::ActionMap> _actionMap{ winrt::make_self<implementation::ActionMap>() };
std::vector<SettingsLoadWarnings> _keybindingsWarnings; std::vector<SettingsLoadWarnings> _keybindingsWarnings;
Windows::Foundation::Collections::IMap<winrt::hstring, Model::ColorScheme> _colorSchemes{ winrt::single_threaded_map<winrt::hstring, Model::ColorScheme>() };
Windows::Foundation::Collections::IMap<hstring, Model::ColorScheme> _colorSchemes;
std::optional<hstring> _getUnparsedDefaultProfileImpl() const;
static bool _getDefaultDebugFeaturesValue();
friend class SettingsModelLocalTests::DeserializationTests;
friend class SettingsModelLocalTests::ColorSchemeTests;
}; };
} }

View file

@ -83,6 +83,7 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_SETTING(Boolean, DetectURLs); INHERITABLE_SETTING(Boolean, DetectURLs);
INHERITABLE_SETTING(Boolean, MinimizeToNotificationArea); INHERITABLE_SETTING(Boolean, MinimizeToNotificationArea);
INHERITABLE_SETTING(Boolean, AlwaysShowNotificationIcon); INHERITABLE_SETTING(Boolean, AlwaysShowNotificationIcon);
INHERITABLE_SETTING(IVector<String>, DisabledProfileSources);
Windows.Foundation.Collections.IMapView<String, ColorScheme> ColorSchemes(); Windows.Foundation.Collections.IMapView<String, ColorScheme> ColorSchemes();
void AddColorScheme(ColorScheme scheme); void AddColorScheme(ColorScheme scheme);

View file

@ -51,5 +51,6 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_APPEARANCE_SETTING(Boolean, RetroTerminalEffect); INHERITABLE_APPEARANCE_SETTING(Boolean, RetroTerminalEffect);
INHERITABLE_APPEARANCE_SETTING(String, PixelShaderPath); INHERITABLE_APPEARANCE_SETTING(String, PixelShaderPath);
INHERITABLE_APPEARANCE_SETTING(IntenseStyle, IntenseTextStyle); INHERITABLE_APPEARANCE_SETTING(IntenseStyle, IntenseTextStyle);
INHERITABLE_APPEARANCE_SETTING(Double, Opacity);
}; };
} }

View file

@ -20,18 +20,16 @@ Author(s):
--*/ --*/
#pragma once #pragma once
#include "Profile.h" #include "Profile.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class IDynamicProfileGenerator; class IDynamicProfileGenerator
{
public:
virtual ~IDynamicProfileGenerator(){};
virtual std::wstring_view GetNamespace() const noexcept = 0;
virtual void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const = 0;
};
}; };
class Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator
{
public:
virtual ~IDynamicProfileGenerator() = 0;
virtual std::wstring_view GetNamespace() = 0;
virtual std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() = 0;
};
inline Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator::~IDynamicProfileGenerator() {}

View file

@ -48,13 +48,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
void InsertParent(com_ptr<T> parent) void InsertParent(com_ptr<T> parent)
{ {
_parents.push_back(parent); _parents.emplace_back(std::move(parent));
} }
void InsertParent(size_t index, com_ptr<T> parent) void InsertParent(size_t index, com_ptr<T> parent)
{ {
auto pos{ _parents.begin() + index }; auto pos{ _parents.begin() + index };
_parents.insert(pos, parent); _parents.emplace(pos, std::move(parent));
} }
const std::vector<com_ptr<T>>& Parents() const std::vector<com_ptr<T>>& Parents()

View file

@ -678,7 +678,7 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
{ {
GUID FromJson(const Json::Value& json) GUID FromJson(const Json::Value& json)
{ {
return ::Microsoft::Console::Utils::GuidFromString(til::u8u16(Detail::GetStringView(json))); return ::Microsoft::Console::Utils::GuidFromString(til::u8u16(Detail::GetStringView(json)).c_str());
} }
bool CanConvert(const Json::Value& json) bool CanConvert(const Json::Value& json)

View file

@ -44,7 +44,7 @@
<ClInclude Include="Command.h"> <ClInclude Include="Command.h">
<DependentUpon>Command.idl</DependentUpon> <DependentUpon>Command.idl</DependentUpon>
</ClInclude> </ClInclude>
<ClInclude Include="DefaultProfileUtils.h" /> <ClInclude Include="DynamicProfileUtils.h" />
<ClInclude Include="FileUtils.h" /> <ClInclude Include="FileUtils.h" />
<ClInclude Include="GlobalAppSettings.h"> <ClInclude Include="GlobalAppSettings.h">
<DependentUpon>GlobalAppSettings.idl</DependentUpon> <DependentUpon>GlobalAppSettings.idl</DependentUpon>
@ -123,7 +123,7 @@
<ClCompile Include="Command.cpp"> <ClCompile Include="Command.cpp">
<DependentUpon>Command.idl</DependentUpon> <DependentUpon>Command.idl</DependentUpon>
</ClCompile> </ClCompile>
<ClCompile Include="DefaultProfileUtils.cpp" /> <ClCompile Include="DynamicProfileUtils.cpp" />
<ClCompile Include="FileUtils.cpp" /> <ClCompile Include="FileUtils.cpp" />
<ClCompile Include="GlobalAppSettings.cpp"> <ClCompile Include="GlobalAppSettings.cpp">
<DependentUpon>GlobalAppSettings.idl</DependentUpon> <DependentUpon>GlobalAppSettings.idl</DependentUpon>
@ -241,28 +241,29 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<!-- ========================= Globals ======================== --> <!-- ========================= Globals ======================== -->
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" /> <Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <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> <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> </PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" /> <Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets'))" /> <Error Condition="!Exists('..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets'))" />
</Target> </Target>
<!-- This target will take our defaults.json and stamp it into a .h file that <!-- This target will take our defaults.json and stamp it into a .h file that
we can include in the code directly. This way, we don't need to worry about we can include in the code directly. This way, we don't need to worry about
failing to load the default settings at runtime. --> failing to load the default settings at runtime. -->
<Target Name="_TerminalAppGenerateDefaultsH" Inputs="defaults.json" Outputs="Generated Files\defaults.h" BeforeTargets="BeforeClCompile"> <Target Name="_TerminalAppGenerateDefaultsH" Inputs="defaults.json" Outputs="Generated Files\defaults.h" BeforeTargets="BeforeClCompile">
<Exec Command="powershell.exe -noprofile ExecutionPolicy Unrestricted $(OpenConsoleDir)\tools\GenerateHeaderForJson.ps1 -JsonFile defaults.json -OutPath '&quot;Generated Files\defaults.h&quot;' -VariableName DefaultJson" /> <Exec Command="pwsh.exe -NoProfile ExecutionPolicy Unrestricted $(OpenConsoleDir)\tools\GenerateHeaderForJson.ps1 -JsonFile defaults.json -OutPath &quot;Generated Files\defaults.h&quot; -VariableName DefaultJson" />
</Target> </Target>
<!-- A different set of defaults for Universal variant --> <!-- A different set of defaults for Universal variant -->
<Target Name="_TerminalAppGenerateDefaultsUniversalH" Inputs="defaults-universal.json" Outputs="Generated Files\defaults-universal.h" BeforeTargets="BeforeClCompile"> <Target Name="_TerminalAppGenerateDefaultsUniversalH" Inputs="defaults-universal.json" Outputs="Generated Files\defaults-universal.h" BeforeTargets="BeforeClCompile">
<Exec Command="powershell.exe -noprofile ExecutionPolicy Unrestricted $(OpenConsoleDir)\tools\GenerateHeaderForJson.ps1 -JsonFile defaults-universal.json -OutPath '&quot;Generated Files\defaults-universal.h&quot;' -VariableName DefaultUniversalJson" /> <Exec Command="pwsh.exe -NoProfile ExecutionPolicy Unrestricted $(OpenConsoleDir)\tools\GenerateHeaderForJson.ps1 -JsonFile defaults-universal.json -OutPath &quot;Generated Files\defaults-universal.h&quot; -VariableName DefaultUniversalJson" />
</Target> </Target>
<!-- Same as above, but for the default settings.json template --> <!-- Same as above, but for the default settings.json template -->
<Target Name="_TerminalAppGenerateUserSettingsH" Inputs="userDefaults.json" Outputs="Generated Files\userDefaults.h" BeforeTargets="BeforeClCompile"> <Target Name="_TerminalAppGenerateUserSettingsH" Inputs="userDefaults.json" Outputs="Generated Files\userDefaults.h" BeforeTargets="BeforeClCompile">
<Exec Command="powershell.exe -noprofile ExecutionPolicy Unrestricted $(OpenConsoleDir)\tools\GenerateHeaderForJson.ps1 -JsonFile userDefaults.json -OutPath '&quot;Generated Files\userDefaults.h&quot;' -VariableName UserSettingsJson" /> <Exec Command="pwsh.exe -NoProfile ExecutionPolicy Unrestricted $(OpenConsoleDir)\tools\GenerateHeaderForJson.ps1 -JsonFile userDefaults.json -OutPath &quot;Generated Files\userDefaults.h&quot; -VariableName UserSettingsJson" />
</Target> </Target>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" /> <Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
<Import Project="..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets" Condition="Exists('..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" /> <Import Project="..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets" Condition="Exists('..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" />
</Project> </Project>

View file

@ -24,7 +24,7 @@
<ClCompile Include="KeyChordSerialization.cpp" /> <ClCompile Include="KeyChordSerialization.cpp" />
<ClCompile Include="Profile.cpp" /> <ClCompile Include="Profile.cpp" />
<ClCompile Include="ColorScheme.cpp" /> <ClCompile Include="ColorScheme.cpp" />
<ClCompile Include="DefaultProfileUtils.cpp"> <ClCompile Include="DynamicProfileUtils.cpp">
<Filter>profileGeneration</Filter> <Filter>profileGeneration</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="$(OpenConsoleDir)\dep\jsoncpp\jsoncpp.cpp"> <ClCompile Include="$(OpenConsoleDir)\dep\jsoncpp\jsoncpp.cpp">
@ -69,7 +69,7 @@
<ClInclude Include="SettingsTypes.h" /> <ClInclude Include="SettingsTypes.h" />
<ClInclude Include="TerminalWarnings.h" /> <ClInclude Include="TerminalWarnings.h" />
<ClInclude Include="ColorScheme.h" /> <ClInclude Include="ColorScheme.h" />
<ClInclude Include="DefaultProfileUtils.h"> <ClInclude Include="DynamicProfileUtils.h">
<Filter>profileGeneration</Filter> <Filter>profileGeneration</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="JsonUtils.h"> <ClInclude Include="JsonUtils.h">
@ -123,4 +123,4 @@
<UniqueIdentifier>{81a6314f-aa5b-4533-a499-13bc3a5c4af0}</UniqueIdentifier> <UniqueIdentifier>{81a6314f-aa5b-4533-a499-13bc3a5c4af0}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -8,7 +8,7 @@
#include "../../types/inc/utils.hpp" #include "../../types/inc/utils.hpp"
#include "../../inc/DefaultSettings.h" #include "../../inc/DefaultSettings.h"
#include "Utils.h" #include "Utils.h"
#include "DefaultProfileUtils.h" #include "DynamicProfileUtils.h"
// These four are headers we do not want proliferating, so they're not in the PCH. // These four are headers we do not want proliferating, so they're not in the PCH.
#include <winrt/Windows.ApplicationModel.h> #include <winrt/Windows.ApplicationModel.h>
@ -289,7 +289,7 @@ static std::vector<PowerShellInstance> _collectPowerShellInstances()
// - PowerShell Core 574e775e-4f2a-5b96-ac1e-a2962a402336 // - PowerShell Core 574e775e-4f2a-5b96-ac1e-a2962a402336
static constexpr winrt::guid PowershellCoreGuid{ 0x574e775e, 0x4f2a, 0x5b96, { 0xac, 0x1e, 0xa2, 0x96, 0x2a, 0x40, 0x23, 0x36 } }; static constexpr winrt::guid PowershellCoreGuid{ 0x574e775e, 0x4f2a, 0x5b96, { 0xac, 0x1e, 0xa2, 0x96, 0x2a, 0x40, 0x23, 0x36 } };
std::wstring_view PowershellCoreProfileGenerator::GetNamespace() std::wstring_view PowershellCoreProfileGenerator::GetNamespace() const noexcept
{ {
return PowershellCoreGeneratorNamespace; return PowershellCoreGeneratorNamespace;
} }
@ -300,34 +300,33 @@ std::wstring_view PowershellCoreProfileGenerator::GetNamespace()
// - <none> // - <none>
// Return Value: // Return Value:
// - a vector with the PowerShell Core profile, if available. // - a vector with the PowerShell Core profile, if available.
std::vector<Profile> PowershellCoreProfileGenerator::GenerateProfiles() void PowershellCoreProfileGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{ {
std::vector<Profile> profiles; const auto psInstances = _collectPowerShellInstances();
bool first = true;
auto psInstances = _collectPowerShellInstances();
for (const auto& psI : psInstances) for (const auto& psI : psInstances)
{ {
const auto name = psI.Name(); const auto name = psI.Name();
auto profile{ CreateDefaultProfile(name) }; auto profile{ CreateDynamicProfile(name) };
profile.Commandline(psI.executablePath.wstring()); profile->Commandline(winrt::hstring{ psI.executablePath.native() });
profile.StartingDirectory(DEFAULT_STARTING_DIRECTORY); profile->StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY });
profile.DefaultAppearance().ColorSchemeName(L"Campbell"); profile->DefaultAppearance().ColorSchemeName(L"Campbell");
profile->Icon(winrt::hstring{ WI_IsFlagSet(psI.flags, PowerShellFlags::Preview) ? POWERSHELL_PREVIEW_ICON : POWERSHELL_ICON });
if (first)
{
// Give the first ("algorithmically best") profile the official, and original, "PowerShell Core" GUID.
// This will turn the anchored default profile into "PowerShell Core Latest for Native Architecture through Store"
// (or the closest approximation thereof). It may choose a preview instance as the "best" if it is a higher version.
profile->Guid(PowershellCoreGuid);
profile->Name(winrt::hstring{ POWERSHELL_PREFERRED_PROFILE_NAME });
first = false;
}
profile.Icon(WI_IsFlagSet(psI.flags, PowerShellFlags::Preview) ? POWERSHELL_PREVIEW_ICON : POWERSHELL_ICON);
profiles.emplace_back(std::move(profile)); profiles.emplace_back(std::move(profile));
} }
if (profiles.size() > 0)
{
// Give the first ("algorithmically best") profile the official, and original, "PowerShell Core" GUID.
// This will turn the anchored default profile into "PowerShell Core Latest for Native Architecture through Store"
// (or the closest approximation thereof). It may choose a preview instance as the "best" if it is a higher version.
auto firstProfile = profiles.begin();
firstProfile->Guid(PowershellCoreGuid);
firstProfile->Name(POWERSHELL_PREFERRED_PROFILE_NAME);
}
return profiles;
} }
// Function Description: // Function Description:

View file

@ -18,17 +18,14 @@ Author(s):
#include "IDynamicProfileGenerator.h" #include "IDynamicProfileGenerator.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class PowershellCoreProfileGenerator : public Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator class PowershellCoreProfileGenerator final : public IDynamicProfileGenerator
{ {
public: public:
static const std::wstring_view GetPreferredPowershellProfileName(); static const std::wstring_view GetPreferredPowershellProfileName();
PowershellCoreProfileGenerator() = default; std::wstring_view GetNamespace() const noexcept override;
~PowershellCoreProfileGenerator() = default; void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
std::wstring_view GetNamespace() override;
std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() override;
}; };
}; };

View file

@ -5,9 +5,7 @@
#include "Profile.h" #include "Profile.h"
#include "JsonUtils.h" #include "JsonUtils.h"
#include "../../types/inc/Utils.hpp" #include "../../types/inc/Utils.hpp"
#include <DefaultSettings.h>
#include "LegacyProfileGeneratorNamespaces.h"
#include "TerminalSettingsSerializationHelpers.h" #include "TerminalSettingsSerializationHelpers.h"
#include "AppearanceConfig.h" #include "AppearanceConfig.h"
#include "FontConfig.h" #include "FontConfig.h"
@ -22,6 +20,7 @@ using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Foundation;
using namespace ::Microsoft::Console; using namespace ::Microsoft::Console;
static constexpr std::string_view UpdatesKey{ "updates" };
static constexpr std::string_view NameKey{ "name" }; static constexpr std::string_view NameKey{ "name" };
static constexpr std::string_view GuidKey{ "guid" }; static constexpr std::string_view GuidKey{ "guid" };
static constexpr std::string_view SourceKey{ "source" }; static constexpr std::string_view SourceKey{ "source" };
@ -36,7 +35,6 @@ static constexpr std::string_view AltGrAliasingKey{ "altGrAliasing" };
static constexpr std::string_view ConnectionTypeKey{ "connectionType" }; static constexpr std::string_view ConnectionTypeKey{ "connectionType" };
static constexpr std::string_view CommandlineKey{ "commandline" }; static constexpr std::string_view CommandlineKey{ "commandline" };
static constexpr std::string_view FontInfoKey{ "font" }; static constexpr std::string_view FontInfoKey{ "font" };
static constexpr std::string_view AcrylicTransparencyKey{ "acrylicOpacity" };
static constexpr std::string_view UseAcrylicKey{ "useAcrylic" }; static constexpr std::string_view UseAcrylicKey{ "useAcrylic" };
static constexpr std::string_view ScrollbarStateKey{ "scrollbarState" }; static constexpr std::string_view ScrollbarStateKey{ "scrollbarState" };
static constexpr std::string_view CloseOnExitKey{ "closeOnExit" }; static constexpr std::string_view CloseOnExitKey{ "closeOnExit" };
@ -48,13 +46,7 @@ static constexpr std::string_view TabColorKey{ "tabColor" };
static constexpr std::string_view BellStyleKey{ "bellStyle" }; static constexpr std::string_view BellStyleKey{ "bellStyle" };
static constexpr std::string_view UnfocusedAppearanceKey{ "unfocusedAppearance" }; static constexpr std::string_view UnfocusedAppearanceKey{ "unfocusedAppearance" };
static constexpr std::wstring_view DesktopWallpaperEnum{ L"desktopWallpaper" }; Profile::Profile(guid guid) noexcept :
Profile::Profile()
{
}
Profile::Profile(guid guid) :
_Guid(guid) _Guid(guid)
{ {
} }
@ -80,62 +72,81 @@ void Profile::DeleteUnfocusedAppearance()
_UnfocusedAppearance = std::nullopt; _UnfocusedAppearance = std::nullopt;
} }
winrt::com_ptr<Profile> Profile::CopySettings(winrt::com_ptr<Profile> source) // See CopyInheritanceGraph (singular) for more information.
// This does the same, but runs it on a list of graph nodes and clones each sub-graph.
void Profile::CopyInheritanceGraphs(std::unordered_map<const Profile*, winrt::com_ptr<Profile>>& visited, const std::vector<winrt::com_ptr<Profile>>& source, std::vector<winrt::com_ptr<Profile>>& target)
{ {
auto profile{ winrt::make_self<Profile>() }; for (const auto& sourceProfile : source)
{
target.emplace_back(sourceProfile->CopyInheritanceGraph(visited));
}
}
profile->_Deleted = source->_Deleted; // A profile and its IInheritable parents basically behave like a directed acyclic graph (DAG).
profile->_Guid = source->_Guid; // Cloning a DAG requires us to prevent the duplication of already cloned nodes (or profiles).
profile->_Name = source->_Name; // This is where "visited" comes into play: It contains previously cloned sub-graphs of profiles and "interns" them.
profile->_Source = source->_Source; winrt::com_ptr<Profile>& Profile::CopyInheritanceGraph(std::unordered_map<const Profile*, winrt::com_ptr<Profile>>& visited) const
profile->_Hidden = source->_Hidden; {
profile->_Icon = source->_Icon; // The operator[] is usually considered to suck, because it implicitly creates entries
profile->_CloseOnExit = source->_CloseOnExit; // in maps/sets if the entry doesn't exist yet, which is often an unwanted behavior.
profile->_TabTitle = source->_TabTitle; // But in this case it's just perfect. We want to return a reference to the profile if it's
profile->_TabColor = source->_TabColor; // been created before and create a cloned profile if it doesn't. With the operator[]
profile->_SuppressApplicationTitle = source->_SuppressApplicationTitle; // we can just assign the returned reference allowing us to write some lean code.
profile->_UseAcrylic = source->_UseAcrylic; auto& clone = visited[this];
profile->_AcrylicOpacity = source->_AcrylicOpacity;
profile->_ScrollState = source->_ScrollState;
profile->_Padding = source->_Padding;
profile->_Commandline = source->_Commandline;
profile->_StartingDirectory = source->_StartingDirectory;
profile->_AntialiasingMode = source->_AntialiasingMode;
profile->_ForceFullRepaintRendering = source->_ForceFullRepaintRendering;
profile->_SoftwareRendering = source->_SoftwareRendering;
profile->_HistorySize = source->_HistorySize;
profile->_SnapOnInput = source->_SnapOnInput;
profile->_AltGrAliasing = source->_AltGrAliasing;
profile->_BellStyle = source->_BellStyle;
profile->_ConnectionType = source->_ConnectionType;
profile->_Origin = source->_Origin;
// Copy over the font info if (!clone)
const auto weakRefToProfile = weak_ref<Model::Profile>(*profile); {
winrt::com_ptr<FontConfig> sourceFontInfoImpl; clone = CopySettings();
sourceFontInfoImpl.copy_from(winrt::get_self<FontConfig>(source->_FontInfo)); CopyInheritanceGraphs(visited, _parents, clone->_parents);
auto copiedFontInfo = FontConfig::CopyFontInfo(sourceFontInfoImpl, weakRefToProfile); clone->_FinalizeInheritance();
profile->_FontInfo = *copiedFontInfo; }
// Copy over the appearance return clone;
winrt::com_ptr<AppearanceConfig> sourceDefaultAppearanceImpl; }
sourceDefaultAppearanceImpl.copy_from(winrt::get_self<AppearanceConfig>(source->_DefaultAppearance));
auto copiedDefaultAppearance = AppearanceConfig::CopyAppearance(sourceDefaultAppearanceImpl, weakRefToProfile);
profile->_DefaultAppearance = *copiedDefaultAppearance;
if (source->_UnfocusedAppearance.has_value()) winrt::com_ptr<Profile> Profile::CopySettings() const
{
const auto profile = winrt::make_self<Profile>();
const auto weakProfile = winrt::make_weak<Model::Profile>(*profile);
const auto fontInfo = FontConfig::CopyFontInfo(winrt::get_self<FontConfig>(_FontInfo), weakProfile);
const auto defaultAppearance = AppearanceConfig::CopyAppearance(winrt::get_self<AppearanceConfig>(_DefaultAppearance), weakProfile);
profile->_Deleted = _Deleted;
profile->_Updates = _Updates;
profile->_Guid = _Guid;
profile->_Name = _Name;
profile->_Source = _Source;
profile->_Hidden = _Hidden;
profile->_Icon = _Icon;
profile->_CloseOnExit = _CloseOnExit;
profile->_TabTitle = _TabTitle;
profile->_TabColor = _TabColor;
profile->_SuppressApplicationTitle = _SuppressApplicationTitle;
profile->_UseAcrylic = _UseAcrylic;
profile->_ScrollState = _ScrollState;
profile->_Padding = _Padding;
profile->_Commandline = _Commandline;
profile->_StartingDirectory = _StartingDirectory;
profile->_AntialiasingMode = _AntialiasingMode;
profile->_ForceFullRepaintRendering = _ForceFullRepaintRendering;
profile->_SoftwareRendering = _SoftwareRendering;
profile->_HistorySize = _HistorySize;
profile->_SnapOnInput = _SnapOnInput;
profile->_AltGrAliasing = _AltGrAliasing;
profile->_BellStyle = _BellStyle;
profile->_ConnectionType = _ConnectionType;
profile->_Origin = _Origin;
profile->_FontInfo = *fontInfo;
profile->_DefaultAppearance = *defaultAppearance;
if (_UnfocusedAppearance)
{ {
Model::AppearanceConfig unfocused{ nullptr }; Model::AppearanceConfig unfocused{ nullptr };
if (source->_UnfocusedAppearance.value() != nullptr) if (*_UnfocusedAppearance)
{ {
// Copy over the unfocused appearance const auto appearance = AppearanceConfig::CopyAppearance(winrt::get_self<AppearanceConfig>(*_UnfocusedAppearance), weakProfile);
winrt::com_ptr<AppearanceConfig> sourceUnfocusedAppearanceImpl; appearance->InsertParent(defaultAppearance);
sourceUnfocusedAppearanceImpl.copy_from(winrt::get_self<AppearanceConfig>(source->_UnfocusedAppearance.value())); unfocused = *appearance;
auto copiedUnfocusedAppearance = AppearanceConfig::CopyAppearance(sourceUnfocusedAppearanceImpl, weakRefToProfile);
// Make sure to add the default appearance as a parent
copiedUnfocusedAppearance->InsertParent(copiedDefaultAppearance);
unfocused = *copiedUnfocusedAppearance;
} }
profile->_UnfocusedAppearance = unfocused; profile->_UnfocusedAppearance = unfocused;
} }
@ -143,104 +154,6 @@ winrt::com_ptr<Profile> Profile::CopySettings(winrt::com_ptr<Profile> source)
return profile; return profile;
} }
// Method Description:
// - Creates a copy of the inheritance graph by performing a depth-first traversal recursively.
// Profiles are recorded as visited via the "visited" parameter.
// Unvisited Profiles are copied into the "cloneGraph" parameter, then marked as visited.
// Arguments:
// - sourceGraph - the graph of Profile's we're cloning
// - cloneGraph - the clone of sourceGraph that is being constructed
// - visited - a map of which Profiles have been visited, and, if so, a reference to the Profile's clone
// Return Value:
// - a clone in both inheritance structure and Profile values of sourceGraph
winrt::com_ptr<Profile> Profile::CloneInheritanceGraph(winrt::com_ptr<Profile> sourceGraph, winrt::com_ptr<Profile> cloneGraph, std::unordered_map<void*, winrt::com_ptr<Profile>>& visited)
{
// If this is an unexplored Profile
// and we have parents...
if (visited.find(sourceGraph.get()) == visited.end() && !sourceGraph->_parents.empty())
{
// iterate through all of our parents to copy them
for (const auto& sourceParent : sourceGraph->_parents)
{
// If we visited this Profile already...
auto kv{ visited.find(sourceParent.get()) };
if (kv != visited.end())
{
// add this Profile's clone as a parent
InsertParentHelper(cloneGraph, kv->second);
}
else
{
// We have not visited this Profile yet,
// copy contents of sourceParent to clone
winrt::com_ptr<Profile> clone{ CopySettings(sourceParent) };
// add the new copy to the cloneGraph
InsertParentHelper(cloneGraph, clone);
// copy the sub-graph at "clone"
CloneInheritanceGraph(sourceParent, clone, visited);
// mark clone as "visited"
// save it to the map in case somebody else references it
visited[sourceParent.get()] = clone;
}
}
}
// we have no more to explore down this path.
return cloneGraph;
}
// Method Description:
// - Inserts a parent profile into a child profile, at the specified index if one was provided
// - Makes sure to call _FinalizeInheritance after inserting the parent
// Arguments:
// - child: the child profile to insert the parent into
// - parent: the parent profile to insert into the child
// - index: an optional index value to insert the parent into
void Profile::InsertParentHelper(winrt::com_ptr<Profile> child, winrt::com_ptr<Profile> parent, std::optional<size_t> index)
{
if (index)
{
child->InsertParent(index.value(), parent);
}
else
{
child->InsertParent(parent);
}
child->_FinalizeInheritance();
}
// Method Description:
// - Generates a Json::Value which is a "stub" of this profile. This stub will
// have enough information that it could be layered with this profile.
// - This method is used during dynamic profile generation - if a profile is
// ever generated that didn't already exist in the user's settings, we'll add
// this stub to the user's settings file, so the user has an easy point to
// modify the generated profile.
// Arguments:
// - <none>
// Return Value:
// - A json::Value with a guid, name and source (if applicable).
Json::Value Profile::GenerateStub() const
{
Json::Value stub;
///// Profile-specific settings /////
stub[JsonKey(GuidKey)] = winrt::to_string(Utils::GuidToString(Guid()));
stub[JsonKey(NameKey)] = winrt::to_string(Name());
const auto source{ Source() };
if (!source.empty())
{
stub[JsonKey(SourceKey)] = winrt::to_string(source);
}
return stub;
}
// Method Description: // Method Description:
// - Create a new instance of this class from a serialized JsonObject. // - Create a new instance of this class from a serialized JsonObject.
// Arguments: // Arguments:
@ -254,71 +167,6 @@ winrt::com_ptr<winrt::Microsoft::Terminal::Settings::Model::implementation::Prof
return result; return result;
} }
// Method Description:
// - Returns true if we think the provided json object represents an instance of
// the same object as this object. If true, we should layer that json object
// on us, instead of creating a new object.
// Arguments:
// - json: The json object to query to see if it's the same
// Return Value:
// - true iff the json object has the same `GUID` as we do.
bool Profile::ShouldBeLayered(const Json::Value& json) const
{
// First, check that GUIDs match. This is easy. If they don't match, they
// should _definitely_ not layer.
const auto otherGuid{ JsonUtils::GetValueForKey<std::optional<winrt::guid>>(json, GuidKey) };
const auto otherSource{ JsonUtils::GetValueForKey<std::optional<winrt::hstring>>(json, SourceKey) };
if (otherGuid)
{
if (otherGuid.value() != Guid())
{
return false;
}
}
else
{
// If the other json object didn't have a GUID,
// check if we auto-generate the same guid using the name and source.
const auto otherName{ JsonUtils::GetValueForKey<std::optional<winrt::hstring>>(json, NameKey) };
if (Guid() != _GenerateGuidForProfile(otherName ? *otherName : L"Default", otherSource ? *otherSource : L""))
{
return false;
}
}
// For profiles with a `source`, also check the `source` property.
bool sourceMatches = false;
const auto mySource{ Source() };
if (!mySource.empty())
{
if (otherSource.has_value())
{
// If we have a source and the other has a source, compare them!
sourceMatches = *otherSource == mySource;
}
else
{
// Special case the legacy dynamic profiles here. In this case,
// `this` is a dynamic profile with a source, and our _source is one
// of the legacy DPG namespaces. We're looking to see if the other
// json object has the same guid, but _no_ "source"
if (mySource == WslGeneratorNamespace ||
mySource == AzureGeneratorNamespace ||
mySource == PowershellCoreGeneratorNamespace)
{
sourceMatches = true;
}
}
}
else
{
// We do not have a source. The only way we match is if source is unset or set to "".
sourceMatches = (!otherSource.has_value() || otherSource.value() == L"");
}
return sourceMatches;
}
// Method Description: // Method Description:
// - Layer values from the given json object on top of the existing properties // - Layer values from the given json object on top of the existing properties
// of this object. For any keys we're expecting to be able to parse in the // of this object. For any keys we're expecting to be able to parse in the
@ -343,6 +191,7 @@ void Profile::LayerJson(const Json::Value& json)
// Profile-specific Settings // Profile-specific Settings
JsonUtils::GetValueForKey(json, NameKey, _Name); JsonUtils::GetValueForKey(json, NameKey, _Name);
JsonUtils::GetValueForKey(json, UpdatesKey, _Updates);
JsonUtils::GetValueForKey(json, GuidKey, _Guid); JsonUtils::GetValueForKey(json, GuidKey, _Guid);
JsonUtils::GetValueForKey(json, HiddenKey, _Hidden); JsonUtils::GetValueForKey(json, HiddenKey, _Hidden);
JsonUtils::GetValueForKey(json, SourceKey, _Source); JsonUtils::GetValueForKey(json, SourceKey, _Source);
@ -356,7 +205,6 @@ void Profile::LayerJson(const Json::Value& json)
// Control Settings // Control Settings
JsonUtils::GetValueForKey(json, ConnectionTypeKey, _ConnectionType); JsonUtils::GetValueForKey(json, ConnectionTypeKey, _ConnectionType);
JsonUtils::GetValueForKey(json, CommandlineKey, _Commandline); JsonUtils::GetValueForKey(json, CommandlineKey, _Commandline);
JsonUtils::GetValueForKey(json, AcrylicTransparencyKey, _AcrylicOpacity);
JsonUtils::GetValueForKey(json, UseAcrylicKey, _UseAcrylic); JsonUtils::GetValueForKey(json, UseAcrylicKey, _UseAcrylic);
JsonUtils::GetValueForKey(json, SuppressApplicationTitleKey, _SuppressApplicationTitle); JsonUtils::GetValueForKey(json, SuppressApplicationTitleKey, _SuppressApplicationTitle);
JsonUtils::GetValueForKey(json, CloseOnExitKey, _CloseOnExit); JsonUtils::GetValueForKey(json, CloseOnExitKey, _CloseOnExit);
@ -462,27 +310,13 @@ std::wstring Profile::EvaluateStartingDirectory(const std::wstring& directory)
return wil::ExpandEnvironmentStringsW<std::wstring>(directory.c_str()); return wil::ExpandEnvironmentStringsW<std::wstring>(directory.c_str());
} }
// Function Description:
// - Returns true if the given JSON object represents a dynamic profile object.
// If it is a dynamic profile object, we should make sure to only layer the
// object on a matching profile from a dynamic source.
// Arguments:
// - json: the partial serialization of a profile object to check
// Return Value:
// - true iff the object has a non-null `source` property
bool Profile::IsDynamicProfileObject(const Json::Value& json)
{
const auto& source = json.isMember(JsonKey(SourceKey)) ? json[JsonKey(SourceKey)] : Json::Value::null;
return !source.isNull();
}
// Function Description: // Function Description:
// - Generates a unique guid for a profile, given the name. For an given name, will always return the same GUID. // - Generates a unique guid for a profile, given the name. For an given name, will always return the same GUID.
// Arguments: // Arguments:
// - name: The name to generate a unique GUID from // - name: The name to generate a unique GUID from
// Return Value: // Return Value:
// - a uuidv5 GUID generated from the given name. // - a uuidv5 GUID generated from the given name.
winrt::guid Profile::_GenerateGuidForProfile(const hstring& name, const hstring& source) noexcept winrt::guid Profile::_GenerateGuidForProfile(const std::wstring_view& name, const std::wstring_view& source) noexcept
{ {
// If we have a _source, then we can from a dynamic profile generator. Use // If we have a _source, then we can from a dynamic profile generator. Use
// our source to build the namespace guid, instead of using the default GUID. // our source to build the namespace guid, instead of using the default GUID.
@ -496,27 +330,6 @@ winrt::guid Profile::_GenerateGuidForProfile(const hstring& name, const hstring&
return { Utils::CreateV5Uuid(namespaceGuid, gsl::as_bytes(gsl::make_span(name))) }; return { Utils::CreateV5Uuid(namespaceGuid, gsl::as_bytes(gsl::make_span(name))) };
} }
// Function Description:
// - Parses the given JSON object to get its GUID. If the json object does not
// have a `guid` set, we'll generate one, using the `name` field.
// Arguments:
// - json: the JSON object to get a GUID from, or generate a unique GUID for
// (given the `name`)
// Return Value:
// - The json's `guid`, or a guid synthesized for it.
winrt::guid Profile::GetGuidOrGenerateForJson(const Json::Value& json) noexcept
{
if (const auto guid{ JsonUtils::GetValueForKey<std::optional<GUID>>(json, GuidKey) })
{
return { guid.value() };
}
const auto name{ JsonUtils::GetValueForKey<hstring>(json, NameKey) };
const auto source{ JsonUtils::GetValueForKey<hstring>(json, SourceKey) };
return Profile::_GenerateGuidForProfile(name, source);
}
// Method Description: // Method Description:
// - Create a new serialized JsonObject from an instance of this class // - Create a new serialized JsonObject from an instance of this class
// Arguments: // Arguments:
@ -548,7 +361,6 @@ Json::Value Profile::ToJson() const
// Control Settings // Control Settings
JsonUtils::SetValueForKey(json, ConnectionTypeKey, _ConnectionType); JsonUtils::SetValueForKey(json, ConnectionTypeKey, _ConnectionType);
JsonUtils::SetValueForKey(json, CommandlineKey, _Commandline); JsonUtils::SetValueForKey(json, CommandlineKey, _Commandline);
JsonUtils::SetValueForKey(json, AcrylicTransparencyKey, _AcrylicOpacity);
JsonUtils::SetValueForKey(json, UseAcrylicKey, _UseAcrylic); JsonUtils::SetValueForKey(json, UseAcrylicKey, _UseAcrylic);
JsonUtils::SetValueForKey(json, SuppressApplicationTitleKey, _SuppressApplicationTitle); JsonUtils::SetValueForKey(json, SuppressApplicationTitleKey, _SuppressApplicationTitle);
JsonUtils::SetValueForKey(json, CloseOnExitKey, _CloseOnExit); JsonUtils::SetValueForKey(json, CloseOnExitKey, _CloseOnExit);

View file

@ -76,8 +76,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
struct Profile : ProfileT<Profile>, IInheritable<Profile> struct Profile : ProfileT<Profile>, IInheritable<Profile>
{ {
public: public:
Profile(); Profile() noexcept = default;
Profile(guid guid); Profile(guid guid) noexcept;
void CreateUnfocusedAppearance(); void CreateUnfocusedAppearance();
void DeleteUnfocusedAppearance(); void DeleteUnfocusedAppearance();
@ -87,19 +87,15 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
return Name(); return Name();
} }
static com_ptr<Profile> CloneInheritanceGraph(com_ptr<Profile> oldProfile, com_ptr<Profile> newProfile, std::unordered_map<void*, com_ptr<Profile>>& visited); static void CopyInheritanceGraphs(std::unordered_map<const Profile*, winrt::com_ptr<Profile>>& visited, const std::vector<winrt::com_ptr<Profile>>& source, std::vector<winrt::com_ptr<Profile>>& target);
static com_ptr<Profile> CopySettings(com_ptr<Profile> source); winrt::com_ptr<Profile>& CopyInheritanceGraph(std::unordered_map<const Profile*, winrt::com_ptr<Profile>>& visited) const;
static void InsertParentHelper(com_ptr<Profile> child, com_ptr<Profile> parent, std::optional<size_t> index = std::nullopt); winrt::com_ptr<Profile> CopySettings() const;
Json::Value GenerateStub() const;
static com_ptr<Profile> FromJson(const Json::Value& json); static com_ptr<Profile> FromJson(const Json::Value& json);
bool ShouldBeLayered(const Json::Value& json) const;
void LayerJson(const Json::Value& json); void LayerJson(const Json::Value& json);
static bool IsDynamicProfileObject(const Json::Value& json);
Json::Value ToJson() const; Json::Value ToJson() const;
hstring EvaluatedStartingDirectory() const; hstring EvaluatedStartingDirectory() const;
static guid GetGuidOrGenerateForJson(const Json::Value& json) noexcept;
Model::IAppearanceConfig DefaultAppearance(); Model::IAppearanceConfig DefaultAppearance();
Model::FontConfig FontInfo(); Model::FontConfig FontInfo();
@ -109,6 +105,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
WINRT_PROPERTY(bool, Deleted, false); WINRT_PROPERTY(bool, Deleted, false);
WINRT_PROPERTY(OriginTag, Origin, OriginTag::None); WINRT_PROPERTY(OriginTag, Origin, OriginTag::None);
WINRT_PROPERTY(guid, Updates);
INHERITABLE_SETTING(Model::Profile, guid, Guid, _GenerateGuidForProfile(Name(), Source())); INHERITABLE_SETTING(Model::Profile, guid, Guid, _GenerateGuidForProfile(Name(), Source()));
INHERITABLE_SETTING(Model::Profile, hstring, Name, L"Default"); INHERITABLE_SETTING(Model::Profile, hstring, Name, L"Default");
INHERITABLE_SETTING(Model::Profile, hstring, Source); INHERITABLE_SETTING(Model::Profile, hstring, Source);
@ -124,7 +121,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::Profile, bool, SuppressApplicationTitle, false); INHERITABLE_SETTING(Model::Profile, bool, SuppressApplicationTitle, false);
INHERITABLE_SETTING(Model::Profile, bool, UseAcrylic, false); INHERITABLE_SETTING(Model::Profile, bool, UseAcrylic, false);
INHERITABLE_SETTING(Model::Profile, double, AcrylicOpacity, 0.5);
INHERITABLE_SETTING(Model::Profile, Microsoft::Terminal::Control::ScrollbarState, ScrollState, Microsoft::Terminal::Control::ScrollbarState::Visible); INHERITABLE_SETTING(Model::Profile, Microsoft::Terminal::Control::ScrollbarState, ScrollState, Microsoft::Terminal::Control::ScrollbarState::Visible);
INHERITABLE_SETTING(Model::Profile, hstring, Padding, DEFAULT_PADDING); INHERITABLE_SETTING(Model::Profile, hstring, Padding, DEFAULT_PADDING);
@ -149,7 +145,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
Model::FontConfig _FontInfo{ winrt::make<FontConfig>(weak_ref<Model::Profile>(*this)) }; Model::FontConfig _FontInfo{ winrt::make<FontConfig>(weak_ref<Model::Profile>(*this)) };
static std::wstring EvaluateStartingDirectory(const std::wstring& directory); static std::wstring EvaluateStartingDirectory(const std::wstring& directory);
static guid _GenerateGuidForProfile(const hstring& name, const hstring& source) noexcept; static guid _GenerateGuidForProfile(const std::wstring_view& name, const std::wstring_view& source) noexcept;
friend class SettingsModelLocalTests::DeserializationTests; friend class SettingsModelLocalTests::DeserializationTests;
friend class SettingsModelLocalTests::ProfileTests; friend class SettingsModelLocalTests::ProfileTests;

View file

@ -50,24 +50,17 @@ namespace Microsoft.Terminal.Settings.Model
Boolean Deleted { get; }; Boolean Deleted { get; };
OriginTag Origin { get; }; OriginTag Origin { get; };
INHERITABLE_PROFILE_SETTING(Guid, Guid);
INHERITABLE_PROFILE_SETTING(String, Name); INHERITABLE_PROFILE_SETTING(String, Name);
Boolean HasGuid();
Guid Guid;
INHERITABLE_PROFILE_SETTING(String, Source); INHERITABLE_PROFILE_SETTING(String, Source);
Boolean HasConnectionType();
Guid ConnectionType;
INHERITABLE_PROFILE_SETTING(Boolean, Hidden); INHERITABLE_PROFILE_SETTING(Boolean, Hidden);
INHERITABLE_PROFILE_SETTING(Guid, ConnectionType);
INHERITABLE_PROFILE_SETTING(String, Icon); INHERITABLE_PROFILE_SETTING(String, Icon);
INHERITABLE_PROFILE_SETTING(CloseOnExitMode, CloseOnExit); INHERITABLE_PROFILE_SETTING(CloseOnExitMode, CloseOnExit);
INHERITABLE_PROFILE_SETTING(String, TabTitle); INHERITABLE_PROFILE_SETTING(String, TabTitle);
INHERITABLE_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, TabColor); INHERITABLE_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, TabColor);
INHERITABLE_PROFILE_SETTING(Boolean, SuppressApplicationTitle); INHERITABLE_PROFILE_SETTING(Boolean, SuppressApplicationTitle);
INHERITABLE_PROFILE_SETTING(Boolean, UseAcrylic); INHERITABLE_PROFILE_SETTING(Boolean, UseAcrylic);
INHERITABLE_PROFILE_SETTING(Double, AcrylicOpacity);
INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.ScrollbarState, ScrollState); INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.ScrollbarState, ScrollState);
INHERITABLE_PROFILE_SETTING(String, Padding); INHERITABLE_PROFILE_SETTING(String, Padding);
INHERITABLE_PROFILE_SETTING(String, Commandline); INHERITABLE_PROFILE_SETTING(String, Commandline);

View file

@ -201,6 +201,16 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
_IntenseIsBold = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bold); _IntenseIsBold = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bold);
_IntenseIsBright = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bright); _IntenseIsBright = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bright);
// If the user set an opacity, then just use that. Otherwise, change the
// default value based off of whether useAcrylic was set or not. If they
// want acrylic, then default to 50%. Otherwise, default to 100% (fully
// opaque)
_Opacity = appearance.HasOpacity() ?
appearance.Opacity() :
UseAcrylic() ?
.5 :
1.0;
} }
// Method Description: // Method Description:
@ -273,7 +283,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// Fill in the remaining properties from the profile // Fill in the remaining properties from the profile
_ProfileName = profile.Name(); _ProfileName = profile.Name();
_UseAcrylic = profile.UseAcrylic(); _UseAcrylic = profile.UseAcrylic();
_TintOpacity = profile.AcrylicOpacity();
_FontFace = profile.FontInfo().FontFace(); _FontFace = profile.FontInfo().FontFace();
_FontSize = profile.FontInfo().FontSize(); _FontSize = profile.FontInfo().FontSize();

View file

@ -118,7 +118,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileName); INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileName);
INHERITABLE_SETTING(Model::TerminalSettings, bool, UseAcrylic, false); INHERITABLE_SETTING(Model::TerminalSettings, bool, UseAcrylic, false);
INHERITABLE_SETTING(Model::TerminalSettings, double, TintOpacity, 0.5); INHERITABLE_SETTING(Model::TerminalSettings, double, Opacity, UseAcrylic() ? 0.5 : 1.0);
INHERITABLE_SETTING(Model::TerminalSettings, hstring, Padding, DEFAULT_PADDING); INHERITABLE_SETTING(Model::TerminalSettings, hstring, Padding, DEFAULT_PADDING);
INHERITABLE_SETTING(Model::TerminalSettings, hstring, FontFace, DEFAULT_FONT_FACE); INHERITABLE_SETTING(Model::TerminalSettings, hstring, FontFace, DEFAULT_FONT_FACE);
INHERITABLE_SETTING(Model::TerminalSettings, int32_t, FontSize, DEFAULT_FONT_SIZE); INHERITABLE_SETTING(Model::TerminalSettings, int32_t, FontSize, DEFAULT_FONT_SIZE);

View file

@ -342,6 +342,34 @@ struct ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<::winr
} }
}; };
struct IntAsFloatPercentConversionTrait : ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<double>
{
double FromJson(const Json::Value& json)
{
return ::base::saturated_cast<double>(json.asUInt()) / 100.0;
}
bool CanConvert(const Json::Value& json)
{
if (!json.isUInt())
{
return false;
}
const auto value = json.asUInt();
return value >= 0 && value <= 100;
}
Json::Value ToJson(const double& val)
{
return std::clamp(::base::saturated_cast<uint32_t>(std::round(val * 100.0)), 0u, 100u);
}
std::string TypeDescription() const
{
return "number (>= 0, <=100)";
}
};
// Possible FocusDirection values // Possible FocusDirection values
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::FocusDirection) JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::FocusDirection)
{ {

View file

@ -8,20 +8,19 @@ namespace Microsoft.Terminal.Settings.Model
enum SettingsLoadWarnings enum SettingsLoadWarnings
{ {
MissingDefaultProfile = 0, MissingDefaultProfile = 0,
DuplicateProfile = 1, DuplicateProfile,
UnknownColorScheme = 2, UnknownColorScheme,
InvalidBackgroundImage = 3, InvalidBackgroundImage,
InvalidIcon = 4, InvalidIcon,
AtLeastOneKeybindingWarning = 5, AtLeastOneKeybindingWarning,
TooManyKeysForChord = 6, TooManyKeysForChord,
MissingRequiredParameter = 7, MissingRequiredParameter,
LegacyGlobalsProperty = 8, FailedToParseCommandJson,
FailedToParseCommandJson = 9, FailedToWriteToSettings,
FailedToWriteToSettings = 10, InvalidColorSchemeInCmd,
InvalidColorSchemeInCmd = 11, InvalidSplitSize,
InvalidSplitSize = 12, FailedToParseStartupActions,
FailedToParseStartupActions = 13, FailedToParseSubCommands,
FailedToParseSubCommands = 14,
WARNINGS_SIZE // IMPORTANT: This MUST be the last value in this enum. It's an unused placeholder. WARNINGS_SIZE // IMPORTANT: This MUST be the last value in this enum. It's an unused placeholder.
}; };

View file

@ -4,7 +4,7 @@
#include "pch.h" #include "pch.h"
#include "VsDevCmdGenerator.h" #include "VsDevCmdGenerator.h"
using namespace Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model;
std::wstring VsDevCmdGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const std::wstring VsDevCmdGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const
{ {

View file

@ -16,12 +16,12 @@ Author(s):
#pragma once #pragma once
#include "BaseVisualStudioGenerator.h" #include "BaseVisualStudioGenerator.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class VsDevCmdGenerator : public BaseVisualStudioGenerator class VsDevCmdGenerator final : public BaseVisualStudioGenerator
{ {
public: public:
std::wstring_view GetNamespace() override std::wstring_view GetNamespace() const noexcept override
{ {
return std::wstring_view{ L"Windows.Terminal.VisualStudio.CommandPrompt" }; return std::wstring_view{ L"Windows.Terminal.VisualStudio.CommandPrompt" };
} }

View file

@ -5,7 +5,7 @@
#include "VsDevShellGenerator.h" #include "VsDevShellGenerator.h"
#include "VsSetupConfiguration.h" #include "VsSetupConfiguration.h"
using namespace Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model;
std::wstring VsDevShellGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const std::wstring VsDevShellGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const
{ {

View file

@ -16,12 +16,12 @@ Author(s):
#pragma once #pragma once
#include "BaseVisualStudioGenerator.h" #include "BaseVisualStudioGenerator.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class VsDevShellGenerator : public BaseVisualStudioGenerator class VsDevShellGenerator final : public BaseVisualStudioGenerator
{ {
public: public:
std::wstring_view GetNamespace() override std::wstring_view GetNamespace() const noexcept override
{ {
return std::wstring_view{ L"Windows.Terminal.VisualStudio.Powershell" }; return std::wstring_view{ L"Windows.Terminal.VisualStudio.Powershell" };
} }

View file

@ -4,7 +4,7 @@
#include "pch.h" #include "pch.h"
#include "VsSetupConfiguration.h" #include "VsSetupConfiguration.h"
using namespace Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model;
std::vector<VsSetupConfiguration::VsSetupInstance> VsSetupConfiguration::QueryInstances() std::vector<VsSetupConfiguration::VsSetupInstance> VsSetupConfiguration::QueryInstances()
{ {

View file

@ -17,7 +17,7 @@ Author(s):
#include "Setup.Configuration.h" #include "Setup.Configuration.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
/// <summary> /// <summary>
/// See https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.setup.configuration?view=visualstudiosdk-2019 /// See https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.setup.configuration?view=visualstudiosdk-2019

View file

@ -5,13 +5,11 @@
#include "WslDistroGenerator.h" #include "WslDistroGenerator.h"
#include "LegacyProfileGeneratorNamespaces.h" #include "LegacyProfileGeneratorNamespaces.h"
#include "../../types/inc/utils.hpp"
#include "../../inc/DefaultSettings.h" #include "../../inc/DefaultSettings.h"
#include "Utils.h"
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
#include "DefaultProfileUtils.h" #include "DynamicProfileUtils.h"
static constexpr std::wstring_view DockerDistributionPrefix{ L"docker-desktop" }; static constexpr std::wstring_view DockerDistributionPrefix{ L"docker-desktop" };
@ -31,21 +29,29 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
// - Alpine 1777cdf0-b2c4-5a63-a204-eb60f349ea7c // - Alpine 1777cdf0-b2c4-5a63-a204-eb60f349ea7c
// - Ubuntu-18.04 c6eaf9f4-32a7-5fdc-b5cf-066e8a4b1e40 // - Ubuntu-18.04 c6eaf9f4-32a7-5fdc-b5cf-066e8a4b1e40
std::wstring_view WslDistroGenerator::GetNamespace() std::wstring_view WslDistroGenerator::GetNamespace() const noexcept
{ {
return WslGeneratorNamespace; return WslGeneratorNamespace;
} }
static winrt::com_ptr<implementation::Profile> makeProfile(const std::wstring& distName)
{
const auto WSLDistro{ CreateDynamicProfile(distName) };
WSLDistro->Commandline(winrt::hstring{ L"wsl.exe -d " + distName });
WSLDistro->DefaultAppearance().ColorSchemeName(L"Campbell");
WSLDistro->StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY });
WSLDistro->Icon(L"ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1bc9722f}.png");
return WSLDistro;
}
// Method Description: // Method Description:
// - Enumerates all the installed WSL distros to create profiles for them. // - Enumerates all the installed WSL distros to create profiles for them.
// Arguments: // Arguments:
// - <none> // - <none>
// Return Value: // Return Value:
// - a vector with all distros for all the installed WSL distros // - a vector with all distros for all the installed WSL distros
static std::vector<Profile> legacyGenerate() static void legacyGenerate(std::vector<winrt::com_ptr<implementation::Profile>>& profiles)
{ {
std::vector<Profile> profiles;
wil::unique_handle readPipe; wil::unique_handle readPipe;
wil::unique_handle writePipe; wil::unique_handle writePipe;
SECURITY_ATTRIBUTES sa{ sizeof(sa), nullptr, true }; SECURITY_ATTRIBUTES sa{ sizeof(sa), nullptr, true };
@ -77,7 +83,7 @@ static std::vector<Profile> legacyGenerate()
break; break;
case WAIT_ABANDONED: case WAIT_ABANDONED:
case WAIT_TIMEOUT: case WAIT_TIMEOUT:
return profiles; return;
case WAIT_FAILED: case WAIT_FAILED:
THROW_LAST_ERROR(); THROW_LAST_ERROR();
default: default:
@ -90,7 +96,7 @@ static std::vector<Profile> legacyGenerate()
} }
else if (exitCode != 0) else if (exitCode != 0)
{ {
return profiles; return;
} }
DWORD bytesAvailable; DWORD bytesAvailable;
THROW_IF_WIN32_BOOL_FALSE(PeekNamedPipe(readPipe.get(), nullptr, NULL, nullptr, &bytesAvailable, nullptr)); THROW_IF_WIN32_BOOL_FALSE(PeekNamedPipe(readPipe.get(), nullptr, NULL, nullptr, &bytesAvailable, nullptr));
@ -117,7 +123,7 @@ static std::vector<Profile> legacyGenerate()
std::wstring distName; std::wstring distName;
std::getline(wlinestream, distName, L'\r'); std::getline(wlinestream, distName, L'\r');
if (distName.substr(0, std::min(distName.size(), DockerDistributionPrefix.size())) == DockerDistributionPrefix) if (til::starts_with(distName, DockerDistributionPrefix))
{ {
// Docker for Windows creates some utility distributions to handle Docker commands. // Docker for Windows creates some utility distributions to handle Docker commands.
// Pursuant to GH#3556, because they are _not_ user-facing we want to hide them. // Pursuant to GH#3556, because they are _not_ user-facing we want to hide them.
@ -131,17 +137,10 @@ static std::vector<Profile> legacyGenerate()
{ {
distName.resize(firstChar); distName.resize(firstChar);
} }
auto WSLDistro{ CreateDefaultProfile(distName) };
WSLDistro.Commandline(L"wsl.exe -d " + distName); profiles.emplace_back(makeProfile(distName));
WSLDistro.DefaultAppearance().ColorSchemeName(L"Campbell");
WSLDistro.StartingDirectory(DEFAULT_STARTING_DIRECTORY);
WSLDistro.Icon(L"ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1bc9722f}.png");
profiles.emplace_back(WSLDistro);
} }
} }
return profiles;
} }
// Function Description: // Function Description:
@ -151,9 +150,8 @@ static std::vector<Profile> legacyGenerate()
// - names: a list of distro names to turn into profiles // - names: a list of distro names to turn into profiles
// Return Value: // Return Value:
// - the list of profiles we've generated. // - the list of profiles we've generated.
static std::vector<Profile> namesToProfiles(const std::vector<std::wstring>& names) static void namesToProfiles(const std::vector<std::wstring>& names, std::vector<winrt::com_ptr<implementation::Profile>>& profiles)
{ {
std::vector<Profile> profiles;
for (const auto& distName : names) for (const auto& distName : names)
{ {
if (til::starts_with(distName, DockerDistributionPrefix)) if (til::starts_with(distName, DockerDistributionPrefix))
@ -163,15 +161,8 @@ static std::vector<Profile> namesToProfiles(const std::vector<std::wstring>& nam
continue; continue;
} }
auto WSLDistro{ CreateDefaultProfile(distName) }; profiles.emplace_back(makeProfile(distName));
WSLDistro.Commandline(L"wsl.exe -d " + distName);
WSLDistro.DefaultAppearance().ColorSchemeName(L"Campbell");
WSLDistro.StartingDirectory(DEFAULT_STARTING_DIRECTORY);
WSLDistro.Icon(L"ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1bc9722f}.png");
profiles.emplace_back(WSLDistro);
} }
return profiles;
} }
// Function Description: // Function Description:
@ -304,7 +295,7 @@ static bool getWslNames(const wil::unique_hkey& wslRootKey,
// - <none> // - <none>
// Return Value: // Return Value:
// - A list of WSL profiles. // - A list of WSL profiles.
std::vector<Profile> WslDistroGenerator::GenerateProfiles() void WslDistroGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{ {
wil::unique_hkey wslRootKey{ openWslRegKey() }; wil::unique_hkey wslRootKey{ openWslRegKey() };
if (wslRootKey) if (wslRootKey)
@ -316,10 +307,10 @@ std::vector<Profile> WslDistroGenerator::GenerateProfiles()
names.reserve(guidStrings.size()); names.reserve(guidStrings.size());
if (getWslNames(wslRootKey, guidStrings, names)) if (getWslNames(wslRootKey, guidStrings, names))
{ {
return namesToProfiles(names); return namesToProfiles(names, profiles);
} }
} }
} }
return legacyGenerate(); legacyGenerate(profiles);
} }

View file

@ -15,16 +15,15 @@ Author(s):
--*/ --*/
#pragma once #pragma once
#include "IDynamicProfileGenerator.h" #include "IDynamicProfileGenerator.h"
namespace Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
class WslDistroGenerator : public Microsoft::Terminal::Settings::Model::IDynamicProfileGenerator class WslDistroGenerator final : public IDynamicProfileGenerator
{ {
public: public:
WslDistroGenerator() = default; std::wstring_view GetNamespace() const noexcept override;
~WslDistroGenerator() = default; void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
std::wstring_view GetNamespace() override;
std::vector<winrt::Microsoft::Terminal::Settings::Model::Profile> GenerateProfiles() override;
}; };
}; };

View file

@ -101,12 +101,12 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" /> <Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <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> <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> </PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" /> <Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets'))" />
</Target> </Target>
<ItemDefinitionGroup> <ItemDefinitionGroup>

View file

@ -1,75 +1,31 @@
// This file was initially generated by %PRODUCT% %VERSION%
// It should still be usable in newer versions, but newer versions might have additional
// settings, help text, or changes that you will not see unless you clear this file
// and let us generate a new one for you.
// To view the default settings, hold "alt" while clicking on the "Settings" button.
// For documentation on these settings, see: https://aka.ms/terminal-documentation
{ {
"$schema": "https://aka.ms/terminal-profiles-schema", // "defaultProfile" is filled in by CascadiaSettings, depending on
// what dynamic profiles are present during the first launch.
"defaultProfile": "%DEFAULT_PROFILE%",
// You can add more global application settings here.
// To learn more about global settings, visit https://aka.ms/terminal-global-settings
// If enabled, selections are automatically copied to your clipboard.
"copyOnSelect": false, "copyOnSelect": false,
// If enabled, formatted data is also copied to your clipboard
"copyFormatting": false, "copyFormatting": false,
// A profile specifies a command to execute paired with information about how it should look and feel.
// Each one of them will appear in the 'New Tab' dropdown,
// and can be invoked from the commandline with `wt.exe -p xxx`
// To learn more about profiles, visit https://aka.ms/terminal-profile-settings
"profiles": "profiles":
{ {
"defaults":
{
// Put settings here that you want to apply to all profiles.
},
"list": "list":
[ [
{ {
// Make changes here to the powershell.exe profile.
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell", "name": "Windows PowerShell",
"commandline": "powershell.exe", "commandline": "powershell.exe",
"hidden": false "hidden": false
}, },
{ {
// Make changes here to the cmd.exe profile. // "name" is filled in by CascadiaSettings as a localized string.
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"name": "%COMMAND_PROMPT_LOCALIZED_NAME%",
"commandline": "cmd.exe", "commandline": "cmd.exe",
"hidden": false "hidden": false
} }
] ]
}, },
// Add custom color schemes to this array.
// To learn more about color schemes, visit https://aka.ms/terminal-color-schemes
"schemes": [],
// Add custom actions and keybindings to this array.
// To unbind a key combination from your defaults.json, set the command to "unbound".
// To learn more about actions and keybindings, visit https://aka.ms/terminal-keybindings
"actions": "actions":
[ [
// Copy and paste are bound to Ctrl+Shift+C and Ctrl+Shift+V in your defaults.json.
// These two lines additionally bind them to Ctrl+C and Ctrl+V.
// To learn more about selection, visit https://aka.ms/terminal-selection
{ "command": {"action": "copy", "singleLine": false }, "keys": "ctrl+c" }, { "command": {"action": "copy", "singleLine": false }, "keys": "ctrl+c" },
{ "command": "paste", "keys": "ctrl+v" }, { "command": "paste", "keys": "ctrl+v" },
// Press Ctrl+Shift+F to open the search box
{ "command": "find", "keys": "ctrl+shift+f" }, { "command": "find", "keys": "ctrl+shift+f" },
// Press Alt+Shift+D to open a new pane.
// - "split": "auto" makes this pane open in the direction that provides the most surface area.
// - "splitMode": "duplicate" makes the new pane use the focused pane's profile.
// To learn more about panes, visit https://aka.ms/terminal-panes
{ "command": { "action": "splitPane", "split": "auto", "splitMode": "duplicate" }, "keys": "alt+shift+d" } { "command": { "action": "splitPane", "split": "auto", "splitMode": "duplicate" }, "keys": "alt+shift+d" }
] ]
} }

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