mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-11 13:56:33 -06:00
This pull request broadly rewrites how we handle all media resources in the Terminal settings model. ## What is a media resource? A media resource is any JSON property that refers to a file on disk, including: - `icon` on profile - `backgroundImage` on profile (appearance) - `pixelShaderPath` and `pixelShaderImagePath` on profile (appearance) - `icon` on command and the new tab menu entries The last two bullet points were newly discovered during the course of this work. ## Description of Changes In every place the settings model used to store a string for a media path, it now stores an `IMediaResource`. A media resource must be _resolved_ before it's used. When resolved, it can report whether it is `Ok` (found, valid) and what the final normalized path was. This allows the settings model to apply some new behaviors. One of those new behaviors is resolving media paths _relative to the JSON file that referred to them._ This means fragments and user settings can now contain _local_ images, pixel shaders and more and refer to them by filename. Relative path support requires us to track the path from which every media resource "container" was read[^2]. For "big" objects like Profile, we track it directly in the object and for each layer. This means that fragments **updating** a profile pass their relative base path into the mix. For some of the entries such as those in `newTabMenu`, we just wing it (#19191). For everything that is recursively owned by a parent that has a path (say each Command inside an ActionMap), we pass it in from the parent during media resolution. During resolution, we now track _exactly which layer_ an icon, background image, or pixel shader path came from and read the "base path" from only that layer. The base path is not inherited. Another new behavior is in the handling of web and other URLs. Canonical and a few other WSL distributors had to resort to web URLs for icons because we did not support loading them from the package. Julia tried to use `ms-appx://JuliaPackageNameHere/path/to/icon` for the same reason. Neither was intended, and of the two the second _should_ have worked but never could[^1]. For both `http(s?)` URLs and `ms-appx://` URLs which specify a package name, we now strip everything except the filename. As an example... If my fragment specifies `https://example.net/assets/foo.ico`, and my fragment was loaded from `C:\Fragments`, Terminal will look *only* at `C:\Fragments\foo.ico`. This works today for Julia (they put their icon in the fragment folder hoping that one day we would support this.) It will require some work from existing WSL distributors. I'm told that this is similar to how XML schema documents work. Now, icons are special. They support _Emoji_ and _Segoe Icons_. This PR adds an early pass to avoid resolving anything that looks like an emoji. This PR intentionally expands the heuristic definition of an emoji. It used to only cover 1-2 code unit emoji, which prevented the use of any emoji more complicated than "man in business suite levitating." An icon path will now be considered an emoji or symbol icon if it is composed of a single grapheme cluster (as measured by ICU.) This is not perfect, as it errs on the side of allowing too many things... but each of those things is technically a single grapheme cluster and is a perfectly legal FontIcon ;) Profile icons are _even more special_ than icons. They have an additional fallback behavior which we had to preserve. When a profile icon fails validation, or is expressly set to `null`, we fall back to the EXE specified in the command line. Because we do this fallback during resolution, _and the icon may be inherited by any higher profile,_ we can only resolve it against the commandline at the same level as the failed or nulled icon. Therefore, if you specify `icon: null` in your `defaults` profile, it will only ever resolve to `cmd.exe` for any profile that inherits it (unless you change `defaults.commandline`). This change expands support for the magic keywords `desktopWallpaper` and `none` to all media paths (yes, even `pixelShaderPath`... but also, `pixelShaderImagePath`!) It also expands support for _environment variables_ to all of those places. Yes, we had like forty different handlers for different types of string path. They are now uniform. ## Resource Validation Media resources which are not found are "rejected". If a rejected resource lives in _user_ settings, we will generate a warning and display it. In the future, we could detect this in the Settings UI and display a warning inline. ## Surprises I learned that `Windows.Foundation.Uri` parses file paths into `file://` URIs, but does not offer you a way to get the original file path back out. If you pass `C:\hello world`, _`Uri.Path`_ will return `/C:/hello%20world`. I kid you not. As a workaround, we bail out of URL handling if the `:` is too close to the start (indicating an absolute file path). ## Testing I added a narow test hook in the media resource resolver, which is removed completely by link-time code generation. It is a real joy. The test cases are all new and hopefully comprehensive. Closes #19075 Closes #16295 Closes #10359 (except it doesn't support fonts) Supersedes #16949 somewhat (`WT_SETTINGS_DIR`) Refs #18679 Refs #19215 (future work) Refs #19201 (future work) Refs #19191 (future work) [^1]: Handling a `ms-appx` path requires us to _add their package to our dependency graph_ for the entire duration during which the resource will be used. For us, that could be any time (like opening the command palette for the first time!) [^2]: We don't bother tracking where the defaults came from, because we control everything about them.
476 lines
21 KiB
C++
476 lines
21 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "pch.h"
|
|
#include "TerminalSettings.h"
|
|
#include "../../types/inc/colorTable.hpp"
|
|
|
|
#include "AppearanceConfig.h"
|
|
|
|
#include "TerminalSettings.g.cpp"
|
|
#include "TerminalSettingsCreateResult.g.cpp"
|
|
|
|
using namespace winrt::Microsoft::Terminal::Control;
|
|
using namespace Microsoft::Console::Utils;
|
|
|
|
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|
{
|
|
static std::tuple<Windows::UI::Xaml::HorizontalAlignment, Windows::UI::Xaml::VerticalAlignment> ConvertConvergedAlignment(ConvergedAlignment alignment)
|
|
{
|
|
// extract horizontal alignment
|
|
Windows::UI::Xaml::HorizontalAlignment horizAlign;
|
|
switch (alignment & static_cast<ConvergedAlignment>(0x0F))
|
|
{
|
|
case ConvergedAlignment::Horizontal_Left:
|
|
horizAlign = Windows::UI::Xaml::HorizontalAlignment::Left;
|
|
break;
|
|
case ConvergedAlignment::Horizontal_Right:
|
|
horizAlign = Windows::UI::Xaml::HorizontalAlignment::Right;
|
|
break;
|
|
case ConvergedAlignment::Horizontal_Center:
|
|
default:
|
|
horizAlign = Windows::UI::Xaml::HorizontalAlignment::Center;
|
|
break;
|
|
}
|
|
|
|
// extract vertical alignment
|
|
Windows::UI::Xaml::VerticalAlignment vertAlign;
|
|
switch (alignment & static_cast<ConvergedAlignment>(0xF0))
|
|
{
|
|
case ConvergedAlignment::Vertical_Top:
|
|
vertAlign = Windows::UI::Xaml::VerticalAlignment::Top;
|
|
break;
|
|
case ConvergedAlignment::Vertical_Bottom:
|
|
vertAlign = Windows::UI::Xaml::VerticalAlignment::Bottom;
|
|
break;
|
|
case ConvergedAlignment::Vertical_Center:
|
|
default:
|
|
vertAlign = Windows::UI::Xaml::VerticalAlignment::Center;
|
|
break;
|
|
}
|
|
|
|
return { horizAlign, vertAlign };
|
|
}
|
|
|
|
winrt::com_ptr<implementation::TerminalSettings> TerminalSettings::_CreateWithProfileCommon(const Model::CascadiaSettings& appSettings, const Model::Profile& profile)
|
|
{
|
|
auto settings{ winrt::make_self<TerminalSettings>() };
|
|
|
|
const auto globals = appSettings.GlobalSettings();
|
|
settings->_ApplyProfileSettings(profile);
|
|
settings->_ApplyGlobalSettings(globals);
|
|
settings->_ApplyAppearanceSettings(profile.DefaultAppearance(), globals.ColorSchemes(), globals.CurrentTheme());
|
|
|
|
return settings;
|
|
}
|
|
|
|
Model::TerminalSettings TerminalSettings::CreateForPreview(const Model::CascadiaSettings& appSettings, const Model::Profile& profile)
|
|
{
|
|
const auto settings = _CreateWithProfileCommon(appSettings, profile);
|
|
settings->UseBackgroundImageForWindow(false);
|
|
return *settings;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Create a TerminalSettingsCreateResult for the provided profile guid. We'll
|
|
// use the guid to look up the profile that should be used to
|
|
// create these TerminalSettings. Then, we'll apply settings contained in the
|
|
// global and profile settings to the instance.
|
|
// Arguments:
|
|
// - appSettings: the set of settings being used to construct the new terminal
|
|
// - profileGuid: the unique identifier (guid) of the profile
|
|
// - keybindings: the keybinding handler
|
|
// Return Value:
|
|
// - A TerminalSettingsCreateResult, which contains a pair of TerminalSettings objects,
|
|
// one for when the terminal is focused and the other for when the terminal is unfocused
|
|
Model::TerminalSettingsCreateResult TerminalSettings::CreateWithProfile(const Model::CascadiaSettings& appSettings, const Model::Profile& profile, const IKeyBindings& keybindings)
|
|
{
|
|
const auto settings = _CreateWithProfileCommon(appSettings, profile);
|
|
settings->_KeyBindings = keybindings;
|
|
|
|
Model::TerminalSettings child{ nullptr };
|
|
if (const auto& unfocusedAppearance{ profile.UnfocusedAppearance() })
|
|
{
|
|
const auto globals = appSettings.GlobalSettings();
|
|
auto childImpl = settings->CreateChild();
|
|
childImpl->_ApplyAppearanceSettings(unfocusedAppearance, globals.ColorSchemes(), globals.CurrentTheme());
|
|
child = *childImpl;
|
|
}
|
|
|
|
return winrt::make<TerminalSettingsCreateResult>(*settings, child);
|
|
}
|
|
|
|
// Method Description:
|
|
// - Create a TerminalSettings object for the provided newTerminalArgs. We'll
|
|
// use the newTerminalArgs to look up the profile that should be used to
|
|
// create these TerminalSettings. Then, we'll apply settings contained in the
|
|
// newTerminalArgs to the profile's settings, to enable customization on top
|
|
// of the profile's default values.
|
|
// Arguments:
|
|
// - appSettings: the set of settings being used to construct the new terminal
|
|
// - newTerminalArgs: An object that may contain a profile name or GUID to
|
|
// actually use. If the Profile value is not a guid, we'll treat it as a name,
|
|
// and attempt to look the profile up by name instead.
|
|
// * Additionally, we'll use other values (such as Commandline,
|
|
// StartingDirectory) in this object to override the settings directly from
|
|
// the profile.
|
|
// - keybindings: the keybinding handler
|
|
// Return Value:
|
|
// - A TerminalSettingsCreateResult object, which contains a pair of TerminalSettings
|
|
// objects. One for when the terminal is focused and one for when the terminal is unfocused.
|
|
Model::TerminalSettingsCreateResult TerminalSettings::CreateWithNewTerminalArgs(const CascadiaSettings& appSettings,
|
|
const NewTerminalArgs& newTerminalArgs,
|
|
const IKeyBindings& keybindings)
|
|
{
|
|
const auto profile = appSettings.GetProfileForArgs(newTerminalArgs);
|
|
auto settingsPair{ CreateWithProfile(appSettings, profile, keybindings) };
|
|
auto defaultSettings = settingsPair.DefaultSettings();
|
|
|
|
if (newTerminalArgs)
|
|
{
|
|
if (const auto id = newTerminalArgs.SessionId(); id != winrt::guid{})
|
|
{
|
|
defaultSettings.SessionId(id);
|
|
}
|
|
|
|
// Override commandline, starting directory if they exist in newTerminalArgs
|
|
if (!newTerminalArgs.Commandline().empty())
|
|
{
|
|
if (!newTerminalArgs.AppendCommandLine())
|
|
{
|
|
defaultSettings.Commandline(newTerminalArgs.Commandline());
|
|
}
|
|
else
|
|
{
|
|
defaultSettings.Commandline(defaultSettings.Commandline() + L" " + newTerminalArgs.Commandline());
|
|
}
|
|
}
|
|
if (!newTerminalArgs.StartingDirectory().empty())
|
|
{
|
|
defaultSettings.StartingDirectory(newTerminalArgs.StartingDirectory());
|
|
}
|
|
if (!newTerminalArgs.TabTitle().empty())
|
|
{
|
|
defaultSettings.StartingTitle(newTerminalArgs.TabTitle());
|
|
}
|
|
else
|
|
{
|
|
// There was no title, and no profile from which to infer the title.
|
|
// Per GH#6776, promote the first component of the command line to the title.
|
|
// This will ensure that the tab we spawn has a name (since it didn't get one from its profile!)
|
|
if (newTerminalArgs.Profile().empty() && !newTerminalArgs.Commandline().empty())
|
|
{
|
|
const std::wstring_view commandLine{ newTerminalArgs.Commandline() };
|
|
const auto start{ til::at(commandLine, 0) == L'"' ? 1 : 0 };
|
|
const auto terminator{ commandLine.find_first_of(start ? L'"' : L' ', start) }; // look past the first character if it starts with "
|
|
// We have to take a copy here; winrt::param::hstring requires a null-terminated string
|
|
const std::wstring firstComponent{ commandLine.substr(start, terminator - start) };
|
|
defaultSettings.StartingTitle(firstComponent);
|
|
}
|
|
}
|
|
if (newTerminalArgs.TabColor())
|
|
{
|
|
defaultSettings.StartingTabColor(winrt::Windows::Foundation::IReference<winrt::Microsoft::Terminal::Core::Color>{ static_cast<winrt::Microsoft::Terminal::Core::Color>(til::color{ newTerminalArgs.TabColor().Value() }) });
|
|
}
|
|
if (newTerminalArgs.SuppressApplicationTitle())
|
|
{
|
|
defaultSettings.SuppressApplicationTitle(newTerminalArgs.SuppressApplicationTitle().Value());
|
|
}
|
|
if (!newTerminalArgs.ColorScheme().empty())
|
|
{
|
|
const auto schemes = appSettings.GlobalSettings().ColorSchemes();
|
|
if (const auto& scheme = schemes.TryLookup(newTerminalArgs.ColorScheme()))
|
|
{
|
|
defaultSettings.ApplyColorScheme(scheme);
|
|
}
|
|
}
|
|
// Elevate on NewTerminalArgs is an optional value, so the default
|
|
// value (null) doesn't override a profile's value. Note that
|
|
// elevate:false in an already elevated terminal does nothing - the
|
|
// profile will still be launched elevated.
|
|
if (newTerminalArgs.Elevate())
|
|
{
|
|
defaultSettings.Elevate(newTerminalArgs.Elevate().Value());
|
|
}
|
|
|
|
if (newTerminalArgs.ReloadEnvironmentVariables())
|
|
{
|
|
defaultSettings.ReloadEnvironmentVariables(newTerminalArgs.ReloadEnvironmentVariables().Value());
|
|
}
|
|
}
|
|
|
|
return settingsPair;
|
|
}
|
|
|
|
void TerminalSettings::_ApplyAppearanceSettings(const IAppearanceConfig& appearance,
|
|
const Windows::Foundation::Collections::IMapView<winrt::hstring, ColorScheme>& schemes,
|
|
const winrt::Microsoft::Terminal::Settings::Model::Theme currentTheme)
|
|
{
|
|
_CursorShape = appearance.CursorShape();
|
|
_CursorHeight = appearance.CursorHeight();
|
|
|
|
auto requestedTheme = currentTheme.RequestedTheme();
|
|
if (requestedTheme == winrt::Windows::UI::Xaml::ElementTheme::Default)
|
|
{
|
|
requestedTheme = Model::Theme::IsSystemInDarkTheme() ?
|
|
winrt::Windows::UI::Xaml::ElementTheme::Dark :
|
|
winrt::Windows::UI::Xaml::ElementTheme::Light;
|
|
}
|
|
|
|
switch (requestedTheme)
|
|
{
|
|
case winrt::Windows::UI::Xaml::ElementTheme::Light:
|
|
if (const auto scheme = schemes.TryLookup(appearance.LightColorSchemeName()))
|
|
{
|
|
ApplyColorScheme(scheme);
|
|
}
|
|
break;
|
|
case winrt::Windows::UI::Xaml::ElementTheme::Dark:
|
|
if (const auto scheme = schemes.TryLookup(appearance.DarkColorSchemeName()))
|
|
{
|
|
ApplyColorScheme(scheme);
|
|
}
|
|
break;
|
|
case winrt::Windows::UI::Xaml::ElementTheme::Default:
|
|
// This shouldn't happen!
|
|
break;
|
|
}
|
|
|
|
if (appearance.Foreground())
|
|
{
|
|
_DefaultForeground = til::color{ appearance.Foreground().Value() };
|
|
}
|
|
if (appearance.Background())
|
|
{
|
|
_DefaultBackground = til::color{ appearance.Background().Value() };
|
|
}
|
|
if (appearance.SelectionBackground())
|
|
{
|
|
_SelectionBackground = til::color{ appearance.SelectionBackground().Value() };
|
|
}
|
|
if (appearance.CursorColor())
|
|
{
|
|
_CursorColor = til::color{ appearance.CursorColor().Value() };
|
|
}
|
|
|
|
if (const auto backgroundImage{ appearance.BackgroundImagePath() })
|
|
{
|
|
_BackgroundImage = backgroundImage.Resolved();
|
|
}
|
|
|
|
if (const auto pixelShader{ appearance.PixelShaderPath() })
|
|
{
|
|
_PixelShaderPath = pixelShader.Resolved();
|
|
}
|
|
|
|
if (const auto pixelShaderImage{ appearance.PixelShaderImagePath() })
|
|
{
|
|
_PixelShaderImagePath = pixelShaderImage.Resolved();
|
|
}
|
|
|
|
_BackgroundImageOpacity = appearance.BackgroundImageOpacity();
|
|
_BackgroundImageStretchMode = appearance.BackgroundImageStretchMode();
|
|
std::tie(_BackgroundImageHorizontalAlignment, _BackgroundImageVerticalAlignment) = ConvertConvergedAlignment(appearance.BackgroundImageAlignment());
|
|
|
|
_RetroTerminalEffect = appearance.RetroTerminalEffect();
|
|
|
|
_IntenseIsBold = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bold);
|
|
_IntenseIsBright = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bright);
|
|
|
|
_AdjustIndistinguishableColors = appearance.AdjustIndistinguishableColors();
|
|
_Opacity = appearance.Opacity();
|
|
_UseAcrylic = appearance.UseAcrylic();
|
|
}
|
|
|
|
// Method Description:
|
|
// - Apply Profile settings, as well as any colors from our color scheme, if we have one.
|
|
// Arguments:
|
|
// - profile: the profile settings we're applying
|
|
// - schemes: a map of schemes to look for our color scheme in, if we have one.
|
|
// Return Value:
|
|
// - <none>
|
|
void TerminalSettings::_ApplyProfileSettings(const Profile& profile)
|
|
{
|
|
// Fill in the Terminal Setting's CoreSettings from the profile
|
|
_HistorySize = profile.HistorySize();
|
|
_SnapOnInput = profile.SnapOnInput();
|
|
_AltGrAliasing = profile.AltGrAliasing();
|
|
_AnswerbackMessage = profile.AnswerbackMessage();
|
|
|
|
// Fill in the remaining properties from the profile
|
|
_ProfileName = profile.Name();
|
|
|
|
const auto fontInfo = profile.FontInfo();
|
|
_FontFace = fontInfo.FontFace();
|
|
_FontSize = fontInfo.FontSize();
|
|
_FontWeight = fontInfo.FontWeight();
|
|
_FontFeatures = fontInfo.FontFeatures();
|
|
_FontAxes = fontInfo.FontAxes();
|
|
_EnableBuiltinGlyphs = fontInfo.EnableBuiltinGlyphs();
|
|
_EnableColorGlyphs = fontInfo.EnableColorGlyphs();
|
|
_CellWidth = fontInfo.CellWidth();
|
|
_CellHeight = fontInfo.CellHeight();
|
|
_Padding = profile.Padding();
|
|
|
|
_Commandline = profile.Commandline();
|
|
|
|
_StartingDirectory = profile.EvaluatedStartingDirectory();
|
|
|
|
// GH#2373: Use the tabTitle as the starting title if it exists; otherwise,
|
|
// use the profile name
|
|
_StartingTitle = !profile.TabTitle().empty() ? profile.TabTitle() : profile.Name();
|
|
|
|
if (profile.SuppressApplicationTitle())
|
|
{
|
|
_SuppressApplicationTitle = profile.SuppressApplicationTitle();
|
|
}
|
|
|
|
_ScrollState = profile.ScrollState();
|
|
|
|
_AntialiasingMode = profile.AntialiasingMode();
|
|
|
|
if (profile.TabColor())
|
|
{
|
|
const til::color colorRef{ profile.TabColor().Value() };
|
|
_TabColor = static_cast<winrt::Microsoft::Terminal::Core::Color>(colorRef);
|
|
}
|
|
|
|
const auto profileEnvVars = profile.EnvironmentVariables();
|
|
if (profileEnvVars == nullptr)
|
|
{
|
|
_EnvironmentVariables = std::nullopt;
|
|
}
|
|
else
|
|
{
|
|
_EnvironmentVariables = winrt::single_threaded_map<winrt::hstring, winrt::hstring>();
|
|
for (const auto& [key, value] : profileEnvVars)
|
|
{
|
|
_EnvironmentVariables.value().Insert(key, value);
|
|
}
|
|
}
|
|
|
|
_Elevate = profile.Elevate();
|
|
_AutoMarkPrompts = Feature_ScrollbarMarks::IsEnabled() && profile.AutoMarkPrompts();
|
|
_ShowMarks = Feature_ScrollbarMarks::IsEnabled() && profile.ShowMarks();
|
|
|
|
_RightClickContextMenu = profile.RightClickContextMenu();
|
|
_RepositionCursorWithMouse = profile.RepositionCursorWithMouse();
|
|
_ReloadEnvironmentVariables = profile.ReloadEnvironmentVariables();
|
|
_RainbowSuggestions = profile.RainbowSuggestions();
|
|
_ForceVTInput = profile.ForceVTInput();
|
|
_AllowVtChecksumReport = profile.AllowVtChecksumReport();
|
|
_AllowVtClipboardWrite = profile.AllowVtClipboardWrite();
|
|
_PathTranslationStyle = profile.PathTranslationStyle();
|
|
}
|
|
|
|
// Method Description:
|
|
// - Applies appropriate settings from the globals into the TerminalSettings object.
|
|
// Arguments:
|
|
// - globalSettings: the global property values we're applying.
|
|
// Return Value:
|
|
// - <none>
|
|
void TerminalSettings::_ApplyGlobalSettings(const Model::GlobalAppSettings& globalSettings) noexcept
|
|
{
|
|
_InitialRows = globalSettings.InitialRows();
|
|
_InitialCols = globalSettings.InitialCols();
|
|
|
|
_WordDelimiters = globalSettings.WordDelimiters();
|
|
_CopyOnSelect = globalSettings.CopyOnSelect();
|
|
_CopyFormatting = globalSettings.CopyFormatting();
|
|
_FocusFollowMouse = globalSettings.FocusFollowMouse();
|
|
_ScrollToZoom = globalSettings.ScrollToZoom();
|
|
_ScrollToChangeOpacity = globalSettings.ScrollToChangeOpacity();
|
|
_GraphicsAPI = globalSettings.GraphicsAPI();
|
|
_DisablePartialInvalidation = globalSettings.DisablePartialInvalidation();
|
|
_SoftwareRendering = globalSettings.SoftwareRendering();
|
|
_TextMeasurement = globalSettings.TextMeasurement();
|
|
_DefaultInputScope = globalSettings.DefaultInputScope();
|
|
_UseBackgroundImageForWindow = globalSettings.UseBackgroundImageForWindow();
|
|
_TrimBlockSelection = globalSettings.TrimBlockSelection();
|
|
_DetectURLs = globalSettings.DetectURLs();
|
|
_EnableUnfocusedAcrylic = globalSettings.EnableUnfocusedAcrylic();
|
|
}
|
|
|
|
// Method Description:
|
|
// - Apply a given ColorScheme's values to the TerminalSettings object.
|
|
// Sets the foreground, background, and color table of the settings object.
|
|
// Arguments:
|
|
// - scheme: the ColorScheme we are applying to the TerminalSettings object
|
|
// Return Value:
|
|
// - <none>
|
|
void TerminalSettings::ApplyColorScheme(const Model::ColorScheme& scheme)
|
|
{
|
|
// If the scheme was nullptr, then just clear out the current color
|
|
// settings.
|
|
if (scheme == nullptr)
|
|
{
|
|
ClearAppliedColorScheme();
|
|
ClearDefaultForeground();
|
|
ClearDefaultBackground();
|
|
ClearSelectionBackground();
|
|
ClearCursorColor();
|
|
_ColorTable = std::nullopt;
|
|
}
|
|
else
|
|
{
|
|
AppliedColorScheme(scheme);
|
|
_DefaultForeground = til::color{ scheme.Foreground() };
|
|
_DefaultBackground = til::color{ scheme.Background() };
|
|
_SelectionBackground = til::color{ scheme.SelectionBackground() };
|
|
_CursorColor = til::color{ scheme.CursorColor() };
|
|
|
|
const auto table = scheme.Table();
|
|
std::array<winrt::Microsoft::Terminal::Core::Color, COLOR_TABLE_SIZE> colorTable{};
|
|
std::transform(table.cbegin(), table.cend(), colorTable.begin(), [](auto&& color) {
|
|
return static_cast<winrt::Microsoft::Terminal::Core::Color>(til::color{ color });
|
|
});
|
|
ColorTable(colorTable);
|
|
}
|
|
}
|
|
|
|
winrt::Microsoft::Terminal::Core::Color TerminalSettings::GetColorTableEntry(int32_t index) noexcept
|
|
{
|
|
return ColorTable().at(index);
|
|
}
|
|
|
|
void TerminalSettings::ColorTable(std::array<winrt::Microsoft::Terminal::Core::Color, 16> colors)
|
|
{
|
|
_ColorTable = colors;
|
|
}
|
|
|
|
std::array<winrt::Microsoft::Terminal::Core::Color, COLOR_TABLE_SIZE> TerminalSettings::ColorTable()
|
|
{
|
|
auto span = _getColorTableImpl();
|
|
std::array<winrt::Microsoft::Terminal::Core::Color, COLOR_TABLE_SIZE> colorTable{};
|
|
if (span.size() > 0)
|
|
{
|
|
std::copy(span.begin(), span.end(), colorTable.begin());
|
|
}
|
|
else
|
|
{
|
|
const auto campbellSpan = CampbellColorTable();
|
|
std::transform(campbellSpan.begin(), campbellSpan.end(), colorTable.begin(), [](auto&& color) {
|
|
return static_cast<winrt::Microsoft::Terminal::Core::Color>(til::color{ color });
|
|
});
|
|
}
|
|
return colorTable;
|
|
}
|
|
|
|
std::span<winrt::Microsoft::Terminal::Core::Color> TerminalSettings::_getColorTableImpl()
|
|
{
|
|
if (_ColorTable.has_value())
|
|
{
|
|
return std::span{ *_ColorTable };
|
|
}
|
|
for (auto&& parent : _parents)
|
|
{
|
|
auto parentSpan = parent->_getColorTableImpl();
|
|
if (parentSpan.size() > 0)
|
|
{
|
|
return parentSpan;
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
}
|