0905140955
* Refactors TerminalApp into two projects:
- TerminalAppLib, which builds a .lib, and includes all the code
- TerminalApp, which builds a dll by linking the lib
* Adds a TerminalApp.Unit.Tests project
- Includes the ability to test cppwinrt types we've authored using a SxS manifest for unpackaged winrt activation
- includes the ability to test types with XAML content using an appxmanifest
* Adds a giant doc explaining how this was all done. Really, just go read that doc, it'll really help you understand what's going on in this PR.
-------------------------
These are some previous commit messages. They may be helpful to future readers.
* Start adding unittests for json parsing, end up creating a TerminalAppLib project to make a lib. See #1042
* VS automatically did this for me
* This is a dead end
I tried including the idl-y things into the lib, but that way leads insanity
If you want to make a StaticLibrary, then suddenly the winrt toolchain forgets
that ProjectReferences can have winmd's in them, so it won't be able to
compile any types from the referenced projects. If you instead try to manually
reference the types, you'll get duplicate types up the wazoo, which of course
is insane, since we're referencing them the _one_ time
* Yea just follow #1042 on github for status
So current state:
1. If you try to add a `Reference` to all of MUX.Markup, TerminalControl and
TerminalSettings, then mdmerge will complain about all the types from
TerminalSettings being defined twice. In this magic scenario, the
dependencies of TerminalControl are used directly for some reason:
```
12> Load input metadata file ...OpenConsole\x64\Debug\TerminalSettings\Microsoft.Terminal.Settings.winmd.
12> Load input metadata file ...OpenConsole\x64\Debug\TerminalControl\Microsoft.Terminal.Settings.winmd.
12> Load input metadata file ...OpenConsole\x64\Debug\TerminalControl\Microsoft.Terminal.TerminalConnection.winmd.
12> Load input metadata file ...OpenConsole\x64\Debug\TerminalControl\Microsoft.Terminal.TerminalControl.winmd.
12> Load input metadata file ...OpenConsole\x64\Debug\Microsoft.UI.Xaml.Markup\Microsoft.UI.Xaml.Markup.winmd.
```
2. If you don't add a `Reference` TerminalControl, then it'll complain about
being unable to find the type TitleChangedEventArgs, which is defined in
TerminalControl.
3. If you don't add a `Reference` TerminalSettings, then it'll complain about
being unable to find the type KeyChord and other types from
TerminalSettings. In this scenario, it doesn't recurse on the other
dependencies from TerminalControl for whatever reason.
4. If you instead try to add all 3 as a `ProjectReference`, then it'll
complain about being unable to find TitleChangedEventArgs, as in 2.
Presumably, it;ll have troubles with the other types too, as none of the 3
are actually included in the midlrt.rsp file.
5. If you add all 3 as a `ProjectReference`, then also add TerminalControl as
a `Reference`, you'll get a `MIDL2011: [msg] unresolved type declaration
Microsoft.UI.Xaml.Markup.XamlApplication`
6. If you add all 3 as a `ProjectReference`, then also add TerminalControl AND
MUX.Markup as a `Reference`, you'll get the same result as 3.
* what if we just don't idl
This seems to compile
* This compiles but I broke the MUX resources
look at the App.xaml change. in this changelist. That's what's broken right now. Lets fix that!
* lets do this
If I leave the MUX nuget out of the project, I'll get a compile error in
App.xaml:
```
...OpenConsole\src\cascadia\TerminalApp\App.xaml(21,40): XamlCompiler error WMC0001: Unknown type 'XamlControlsResources' in XML namespace 'using:Microsoft.UI.Xaml.Controls'
```
If I add it back to the project, it works
* Some cleanup from the previous commit
* This is busted again.
Doing a clean build didn't work.
A clean rebuild of the project, paired with some removal of dead code
revealed a problem with what I have so far.
TerminalAppLib depends on the generation of two headers,
`AppKeyBindings.g.h` and `App.g.h`, as those define some of bits of the
winrt types. They're needed to be able to compile the implementations.
Presumably that's not getting generated by the lib project, because the dll
project is the one to generate that file.
So we need to move the idl's to the lib project. This created maddness,
because of course the Duplicate Type thing. The solution to that is to
actually mark the winrt DLLs that we're chaining up through us as
```
<Private>false</Private>
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
```
This will prevent them from getting double-included.
This still doesn't work however, since
```
app.cpp(40): error C2039: 'XamlMetaDataProvider': is not a member of 'winrt::TerminalApp'
error C3861: 'XamlMetaDataProvider': identifier not found
```
So we need to figure that out. The dll project is still generating the right
header, so lets look there.
* Move the xaml stuff to the lib
This compiles, but when we launch, we fail to load the tabviewcontrol
resources again. So that's not what you want. Why is it not included?
* It works again!
* Use the pri, xbf files from TerminalAppLib, not TerminalApp
* Manually make TerminalApp include a reference to TerminalAppLib's
TerminalApp.winmd. This will force the build to copy TerminalApp.winmd to
TerminalApp/, which WindowsTerminal needs to be able to ProjectReference the
TerminalApp project (it's expecting it to have a winmd)
* Remove the module.g.cpp from TerminalApp, and move to TerminalAppLib. The
dll doesn't do any codegen anymore.
* Agressively clean up these files
* Clean up unnecessary includes in the dll pch.h
* This does NOT work.
The WindowsxamlManager call crashes. I'm thinking it has to do with activation
of winrt types from a dll.
Email out to @Austin-Lamb to see if he can assist
* This gets our cppwinrt types working, but xaml islands is still broken
* Split the tests apart, so they aren't insane
* These are the magic words to make xaml islands work
* All this witchcraft is necessary to make XAML+MUX work right
* Clean this up a bit and add comments
* Create an enormous doc explaining this madness
* Unsure how this got changed.
* Trying to get the CI build to work again.
This resolves the MUX issue. We need to manually include it, because their package's target doesn't mark it as CopyLocalSatelliteAssemblies=false, Private=false.
However, the TerminalApp project is still able to magically reason that the TerminalAppLib project should be included in the MdMerge step, because it think's it's a `GetCppWinRTStaticProjectReferences` reference.
* Update cppwinrt to the latest version - this fixes the MSBuild
* I still need to re-add the KeyModifiers checks from TermControl. I think
this update broke `operator&` for that enum.
* There needs to be some cleanup obviously
* The doc should be updated as well
* Clean up changes from cppwinrt update
* Try doing this, even though it seems wrong
* Lets try this (press x to doubt)
* Clean up vcxproj file, and remove appxmanifest change from previous commit
* Update to the latest TAEF release, maybe that'll work
* Let's try a prerelease version, shall we?
* Add notes about TAEF package, comment out tests
* Format the code
* Hopefully fix the arm64 and x86 builds
also a typo
* Fix PR nits
* Fix some bad merge conflicts
* Some cleanup from the merge
* Well I was close to getting the merge right
* I believe this will fix CI
* Apply suggestions from code review
Co-Authored-By: Carlos Zamora <carlos.zamora@microsoft.com>
* These definitely need to be fixed
* Try version detecting in the test
IDK if this will build, I'm letting the CI try while I clean rebuild locally
* Try blindly updating to the newest nuget version
* Revert "Try blindly updating to the newest nuget version"
This reverts commit b72bd9eb73
.
* We're just going to see if these work in CI with this change
* Comment the tests back out. Windows Server 2019 is 10.0.17763.557
* Remove the nuget package
We don't need this package anymore now that we're hosting it
* Okay this _was_ important
714 lines
23 KiB
C++
714 lines
23 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "pch.h"
|
|
#include "Profile.h"
|
|
#include "Utils.h"
|
|
#include "../../types/inc/Utils.hpp"
|
|
#include <DefaultSettings.h>
|
|
|
|
using namespace TerminalApp;
|
|
using namespace winrt::Microsoft::Terminal::Settings;
|
|
using namespace ::Microsoft::Console;
|
|
|
|
static constexpr std::string_view NameKey{ "name" };
|
|
static constexpr std::string_view GuidKey{ "guid" };
|
|
static constexpr std::string_view ColorSchemeKey{ "colorScheme" };
|
|
static constexpr std::string_view ColorSchemeKeyOld{ "colorscheme" };
|
|
|
|
static constexpr std::string_view ForegroundKey{ "foreground" };
|
|
static constexpr std::string_view BackgroundKey{ "background" };
|
|
static constexpr std::string_view ColorTableKey{ "colorTable" };
|
|
static constexpr std::string_view TabTitleKey{ "tabTitle" };
|
|
static constexpr std::string_view HistorySizeKey{ "historySize" };
|
|
static constexpr std::string_view SnapOnInputKey{ "snapOnInput" };
|
|
static constexpr std::string_view CursorColorKey{ "cursorColor" };
|
|
static constexpr std::string_view CursorShapeKey{ "cursorShape" };
|
|
static constexpr std::string_view CursorHeightKey{ "cursorHeight" };
|
|
|
|
static constexpr std::string_view CommandlineKey{ "commandline" };
|
|
static constexpr std::string_view FontFaceKey{ "fontFace" };
|
|
static constexpr std::string_view FontSizeKey{ "fontSize" };
|
|
static constexpr std::string_view AcrylicTransparencyKey{ "acrylicOpacity" };
|
|
static constexpr std::string_view UseAcrylicKey{ "useAcrylic" };
|
|
static constexpr std::string_view ScrollbarStateKey{ "scrollbarState" };
|
|
static constexpr std::string_view CloseOnExitKey{ "closeOnExit" };
|
|
static constexpr std::string_view PaddingKey{ "padding" };
|
|
static constexpr std::string_view StartingDirectoryKey{ "startingDirectory" };
|
|
static constexpr std::string_view IconKey{ "icon" };
|
|
static constexpr std::string_view BackgroundImageKey{ "backgroundImage" };
|
|
static constexpr std::string_view BackgroundImageOpacityKey{ "backgroundImageOpacity" };
|
|
static constexpr std::string_view BackgroundimageStretchModeKey{ "backgroundImageStretchMode" };
|
|
|
|
// Possible values for Scrollbar state
|
|
static constexpr std::wstring_view AlwaysVisible{ L"visible" };
|
|
static constexpr std::wstring_view AlwaysHide{ L"hidden" };
|
|
|
|
// Possible values for Cursor Shape
|
|
static constexpr std::wstring_view CursorShapeVintage{ L"vintage" };
|
|
static constexpr std::wstring_view CursorShapeBar{ L"bar" };
|
|
static constexpr std::wstring_view CursorShapeUnderscore{ L"underscore" };
|
|
static constexpr std::wstring_view CursorShapeFilledbox{ L"filledBox" };
|
|
static constexpr std::wstring_view CursorShapeEmptybox{ L"emptyBox" };
|
|
|
|
// Possible values for Image Stretch Mode
|
|
static constexpr std::string_view ImageStretchModeNone{ "none" };
|
|
static constexpr std::string_view ImageStretchModeFill{ "fill" };
|
|
static constexpr std::string_view ImageStretchModeUniform{ "uniform" };
|
|
static constexpr std::string_view ImageStretchModeUniformTofill{ "uniformToFill" };
|
|
|
|
Profile::Profile() :
|
|
Profile(Utils::CreateGuid())
|
|
{
|
|
}
|
|
|
|
Profile::Profile(const winrt::guid& guid) :
|
|
_guid(guid),
|
|
_name{ L"Default" },
|
|
_schemeName{},
|
|
|
|
_defaultForeground{},
|
|
_defaultBackground{},
|
|
_colorTable{},
|
|
_tabTitle{},
|
|
_historySize{ DEFAULT_HISTORY_SIZE },
|
|
_snapOnInput{ true },
|
|
_cursorColor{ DEFAULT_CURSOR_COLOR },
|
|
_cursorShape{ CursorStyle::Bar },
|
|
_cursorHeight{ DEFAULT_CURSOR_HEIGHT },
|
|
|
|
_commandline{ L"cmd.exe" },
|
|
_startingDirectory{},
|
|
_fontFace{ DEFAULT_FONT_FACE },
|
|
_fontSize{ DEFAULT_FONT_SIZE },
|
|
_acrylicTransparency{ 0.5 },
|
|
_useAcrylic{ false },
|
|
_scrollbarState{},
|
|
_closeOnExit{ true },
|
|
_padding{ DEFAULT_PADDING },
|
|
_icon{},
|
|
_backgroundImage{},
|
|
_backgroundImageOpacity{},
|
|
_backgroundImageStretchMode{}
|
|
{
|
|
}
|
|
|
|
Profile::~Profile()
|
|
{
|
|
}
|
|
|
|
GUID Profile::GetGuid() const noexcept
|
|
{
|
|
return _guid;
|
|
}
|
|
|
|
// Function Description:
|
|
// - Searches a list of color schemes to find one matching the given name. Will
|
|
//return the first match in the list, if the list has multiple schemes with the same name.
|
|
// Arguments:
|
|
// - schemes: a list of schemes to search
|
|
// - schemeName: the name of the sceme to look for
|
|
// Return Value:
|
|
// - a non-ownership pointer to the matching scheme if we found one, else nullptr
|
|
const ColorScheme* _FindScheme(const std::vector<ColorScheme>& schemes,
|
|
const std::wstring& schemeName)
|
|
{
|
|
for (auto& scheme : schemes)
|
|
{
|
|
if (scheme.GetName() == schemeName)
|
|
{
|
|
return &scheme;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Create a TerminalSettings from this object. Apply our settings, as well as
|
|
// any colors from our color scheme, if we have one.
|
|
// Arguments:
|
|
// - schemes: a list of schemes to look for our color scheme in, if we have one.
|
|
// Return Value:
|
|
// - a new TerminalSettings object with our settings in it.
|
|
TerminalSettings Profile::CreateTerminalSettings(const std::vector<ColorScheme>& schemes) const
|
|
{
|
|
TerminalSettings terminalSettings{};
|
|
|
|
// Fill in the Terminal Setting's CoreSettings from the profile
|
|
for (int i = 0; i < _colorTable.size(); i++)
|
|
{
|
|
terminalSettings.SetColorTableEntry(i, _colorTable[i]);
|
|
}
|
|
terminalSettings.HistorySize(_historySize);
|
|
terminalSettings.SnapOnInput(_snapOnInput);
|
|
terminalSettings.CursorColor(_cursorColor);
|
|
terminalSettings.CursorHeight(_cursorHeight);
|
|
terminalSettings.CursorShape(_cursorShape);
|
|
|
|
// Fill in the remaining properties from the profile
|
|
terminalSettings.UseAcrylic(_useAcrylic);
|
|
terminalSettings.CloseOnExit(_closeOnExit);
|
|
terminalSettings.TintOpacity(_acrylicTransparency);
|
|
|
|
terminalSettings.FontFace(_fontFace);
|
|
terminalSettings.FontSize(_fontSize);
|
|
terminalSettings.Padding(_padding);
|
|
|
|
terminalSettings.Commandline(winrt::to_hstring(_commandline.c_str()));
|
|
|
|
if (_startingDirectory)
|
|
{
|
|
const auto evaluatedDirectory = Profile::EvaluateStartingDirectory(_startingDirectory.value());
|
|
terminalSettings.StartingDirectory(winrt::to_hstring(evaluatedDirectory.c_str()));
|
|
}
|
|
|
|
if (_schemeName)
|
|
{
|
|
const ColorScheme* const matchingScheme = _FindScheme(schemes, _schemeName.value());
|
|
if (matchingScheme)
|
|
{
|
|
matchingScheme->ApplyScheme(terminalSettings);
|
|
}
|
|
}
|
|
if (_defaultForeground)
|
|
{
|
|
terminalSettings.DefaultForeground(_defaultForeground.value());
|
|
}
|
|
if (_defaultBackground)
|
|
{
|
|
terminalSettings.DefaultBackground(_defaultBackground.value());
|
|
}
|
|
|
|
if (_scrollbarState)
|
|
{
|
|
ScrollbarState result = ParseScrollbarState(_scrollbarState.value());
|
|
terminalSettings.ScrollState(result);
|
|
}
|
|
|
|
if (_backgroundImage)
|
|
{
|
|
terminalSettings.BackgroundImage(_backgroundImage.value());
|
|
}
|
|
|
|
if (_backgroundImageOpacity)
|
|
{
|
|
terminalSettings.BackgroundImageOpacity(_backgroundImageOpacity.value());
|
|
}
|
|
|
|
if (_backgroundImageStretchMode)
|
|
{
|
|
terminalSettings.BackgroundImageStretchMode(_backgroundImageStretchMode.value());
|
|
}
|
|
|
|
return terminalSettings;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Serialize this object to a JsonObject.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - a JsonObject which is an equivalent serialization of this object.
|
|
Json::Value Profile::ToJson() const
|
|
{
|
|
Json::Value root;
|
|
|
|
///// Profile-specific settings /////
|
|
root[JsonKey(GuidKey)] = winrt::to_string(Utils::GuidToString(_guid));
|
|
root[JsonKey(NameKey)] = winrt::to_string(_name);
|
|
|
|
///// Core Settings /////
|
|
if (_defaultForeground)
|
|
{
|
|
root[JsonKey(ForegroundKey)] = Utils::ColorToHexString(_defaultForeground.value());
|
|
}
|
|
if (_defaultBackground)
|
|
{
|
|
root[JsonKey(BackgroundKey)] = Utils::ColorToHexString(_defaultBackground.value());
|
|
}
|
|
if (_schemeName)
|
|
{
|
|
const auto scheme = winrt::to_string(_schemeName.value());
|
|
root[JsonKey(ColorSchemeKey)] = scheme;
|
|
}
|
|
else
|
|
{
|
|
Json::Value tableArray{};
|
|
for (auto& color : _colorTable)
|
|
{
|
|
tableArray.append(Utils::ColorToHexString(color));
|
|
}
|
|
root[JsonKey(ColorTableKey)] = tableArray;
|
|
}
|
|
root[JsonKey(HistorySizeKey)] = _historySize;
|
|
root[JsonKey(SnapOnInputKey)] = _snapOnInput;
|
|
root[JsonKey(CursorColorKey)] = Utils::ColorToHexString(_cursorColor);
|
|
// Only add the cursor height property if we're a legacy-style cursor.
|
|
if (_cursorShape == CursorStyle::Vintage)
|
|
{
|
|
root[JsonKey(CursorHeightKey)] = _cursorHeight;
|
|
}
|
|
root[JsonKey(CursorShapeKey)] = winrt::to_string(_SerializeCursorStyle(_cursorShape));
|
|
|
|
///// Control Settings /////
|
|
root[JsonKey(CommandlineKey)] = winrt::to_string(_commandline);
|
|
root[JsonKey(FontFaceKey)] = winrt::to_string(_fontFace);
|
|
root[JsonKey(FontSizeKey)] = _fontSize;
|
|
root[JsonKey(AcrylicTransparencyKey)] = _acrylicTransparency;
|
|
root[JsonKey(UseAcrylicKey)] = _useAcrylic;
|
|
root[JsonKey(CloseOnExitKey)] = _closeOnExit;
|
|
root[JsonKey(PaddingKey)] = winrt::to_string(_padding);
|
|
|
|
if (_scrollbarState)
|
|
{
|
|
const auto scrollbarState = winrt::to_string(_scrollbarState.value());
|
|
root[JsonKey(ScrollbarStateKey)] = scrollbarState;
|
|
}
|
|
|
|
if (_icon)
|
|
{
|
|
const auto icon = winrt::to_string(_icon.value());
|
|
root[JsonKey(IconKey)] = icon;
|
|
}
|
|
|
|
if (_tabTitle)
|
|
{
|
|
root[JsonKey(TabTitleKey)] = winrt::to_string(_tabTitle.value());
|
|
}
|
|
|
|
if (_startingDirectory)
|
|
{
|
|
root[JsonKey(StartingDirectoryKey)] = winrt::to_string(_startingDirectory.value());
|
|
}
|
|
|
|
if (_backgroundImage)
|
|
{
|
|
root[JsonKey(BackgroundImageKey)] = winrt::to_string(_backgroundImage.value());
|
|
}
|
|
|
|
if (_backgroundImageOpacity)
|
|
{
|
|
root[JsonKey(BackgroundImageOpacityKey)] = _backgroundImageOpacity.value();
|
|
}
|
|
|
|
if (_backgroundImageStretchMode)
|
|
{
|
|
root[JsonKey(BackgroundimageStretchModeKey)] = SerializeImageStretchMode(_backgroundImageStretchMode.value()).data();
|
|
}
|
|
|
|
return root;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Create a new instance of this class from a serialized JsonObject.
|
|
// Arguments:
|
|
// - json: an object which should be a serialization of a Profile object.
|
|
// Return Value:
|
|
// - a new Profile instance created from the values in `json`
|
|
Profile Profile::FromJson(const Json::Value& json)
|
|
{
|
|
Profile result{};
|
|
|
|
// Profile-specific Settings
|
|
if (auto name{ json[JsonKey(NameKey)] })
|
|
{
|
|
result._name = GetWstringFromJson(name);
|
|
}
|
|
if (auto guid{ json[JsonKey(GuidKey)] })
|
|
{
|
|
result._guid = Utils::GuidFromString(GetWstringFromJson(guid));
|
|
}
|
|
|
|
// Core Settings
|
|
if (auto foreground{ json[JsonKey(ForegroundKey)] })
|
|
{
|
|
const auto color = Utils::ColorFromHexString(foreground.asString());
|
|
result._defaultForeground = color;
|
|
}
|
|
if (auto background{ json[JsonKey(BackgroundKey)] })
|
|
{
|
|
const auto color = Utils::ColorFromHexString(background.asString());
|
|
result._defaultBackground = color;
|
|
}
|
|
if (auto colorScheme{ json[JsonKey(ColorSchemeKey)] })
|
|
{
|
|
result._schemeName = GetWstringFromJson(colorScheme);
|
|
}
|
|
else if (auto colorScheme{ json[JsonKey(ColorSchemeKeyOld)] })
|
|
{
|
|
// TODO:GH#1069 deprecate old settings key
|
|
result._schemeName = GetWstringFromJson(colorScheme);
|
|
}
|
|
else if (auto colortable{ json[JsonKey(ColorTableKey)] })
|
|
{
|
|
int i = 0;
|
|
for (const auto& tableEntry : colortable)
|
|
{
|
|
if (tableEntry.isString())
|
|
{
|
|
const auto color = Utils::ColorFromHexString(tableEntry.asString());
|
|
result._colorTable[i] = color;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
if (auto historySize{ json[JsonKey(HistorySizeKey)] })
|
|
{
|
|
// TODO:MSFT:20642297 - Use a sentinel value (-1) for "Infinite scrollback"
|
|
result._historySize = historySize.asInt();
|
|
}
|
|
if (auto snapOnInput{ json[JsonKey(SnapOnInputKey)] })
|
|
{
|
|
result._snapOnInput = snapOnInput.asBool();
|
|
}
|
|
if (auto cursorColor{ json[JsonKey(CursorColorKey)] })
|
|
{
|
|
const auto color = Utils::ColorFromHexString(cursorColor.asString());
|
|
result._cursorColor = color;
|
|
}
|
|
if (auto cursorHeight{ json[JsonKey(CursorHeightKey)] })
|
|
{
|
|
result._cursorHeight = cursorHeight.asUInt();
|
|
}
|
|
if (auto cursorShape{ json[JsonKey(CursorShapeKey)] })
|
|
{
|
|
result._cursorShape = _ParseCursorShape(GetWstringFromJson(cursorShape));
|
|
}
|
|
if (auto tabTitle{ json[JsonKey(TabTitleKey)] })
|
|
{
|
|
result._tabTitle = GetWstringFromJson(tabTitle);
|
|
}
|
|
|
|
// Control Settings
|
|
if (auto commandline{ json[JsonKey(CommandlineKey)] })
|
|
{
|
|
result._commandline = GetWstringFromJson(commandline);
|
|
}
|
|
if (auto fontFace{ json[JsonKey(FontFaceKey)] })
|
|
{
|
|
result._fontFace = GetWstringFromJson(fontFace);
|
|
}
|
|
if (auto fontSize{ json[JsonKey(FontSizeKey)] })
|
|
{
|
|
result._fontSize = fontSize.asInt();
|
|
}
|
|
if (auto acrylicTransparency{ json[JsonKey(AcrylicTransparencyKey)] })
|
|
{
|
|
result._acrylicTransparency = acrylicTransparency.asFloat();
|
|
}
|
|
if (auto useAcrylic{ json[JsonKey(UseAcrylicKey)] })
|
|
{
|
|
result._useAcrylic = useAcrylic.asBool();
|
|
}
|
|
if (auto closeOnExit{ json[JsonKey(CloseOnExitKey)] })
|
|
{
|
|
result._closeOnExit = closeOnExit.asBool();
|
|
}
|
|
if (auto padding{ json[JsonKey(PaddingKey)] })
|
|
{
|
|
result._padding = GetWstringFromJson(padding);
|
|
}
|
|
if (auto scrollbarState{ json[JsonKey(ScrollbarStateKey)] })
|
|
{
|
|
result._scrollbarState = GetWstringFromJson(scrollbarState);
|
|
}
|
|
if (auto startingDirectory{ json[JsonKey(StartingDirectoryKey)] })
|
|
{
|
|
result._startingDirectory = GetWstringFromJson(startingDirectory);
|
|
}
|
|
if (auto icon{ json[JsonKey(IconKey)] })
|
|
{
|
|
result._icon = GetWstringFromJson(icon);
|
|
}
|
|
if (auto backgroundImage{ json[JsonKey(BackgroundImageKey)] })
|
|
{
|
|
result._backgroundImage = GetWstringFromJson(backgroundImage);
|
|
}
|
|
if (auto backgroundImageOpacity{ json[JsonKey(BackgroundImageOpacityKey)] })
|
|
{
|
|
result._backgroundImageOpacity = backgroundImageOpacity.asFloat();
|
|
}
|
|
if (auto backgroundImageStretchMode{ json[JsonKey(BackgroundimageStretchModeKey)] })
|
|
{
|
|
result._backgroundImageStretchMode = ParseImageStretchMode(backgroundImageStretchMode.asString());
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void Profile::SetFontFace(std::wstring fontFace) noexcept
|
|
{
|
|
_fontFace = fontFace;
|
|
}
|
|
|
|
void Profile::SetColorScheme(std::optional<std::wstring> schemeName) noexcept
|
|
{
|
|
_schemeName = schemeName;
|
|
}
|
|
|
|
void Profile::SetAcrylicOpacity(double opacity) noexcept
|
|
{
|
|
_acrylicTransparency = opacity;
|
|
}
|
|
|
|
void Profile::SetCommandline(std::wstring cmdline) noexcept
|
|
{
|
|
_commandline = cmdline;
|
|
}
|
|
|
|
void Profile::SetStartingDirectory(std::wstring startingDirectory) noexcept
|
|
{
|
|
_startingDirectory = startingDirectory;
|
|
}
|
|
|
|
void Profile::SetName(std::wstring name) noexcept
|
|
{
|
|
_name = name;
|
|
}
|
|
|
|
void Profile::SetUseAcrylic(bool useAcrylic) noexcept
|
|
{
|
|
_useAcrylic = useAcrylic;
|
|
}
|
|
|
|
void Profile::SetDefaultForeground(COLORREF defaultForeground) noexcept
|
|
{
|
|
_defaultForeground = defaultForeground;
|
|
}
|
|
|
|
void Profile::SetDefaultBackground(COLORREF defaultBackground) noexcept
|
|
{
|
|
_defaultBackground = defaultBackground;
|
|
}
|
|
|
|
bool Profile::HasIcon() const noexcept
|
|
{
|
|
return _icon.has_value();
|
|
}
|
|
|
|
// Method Description
|
|
// - Sets this profile's tab title.
|
|
// Arguments:
|
|
// - tabTitle: the tab title
|
|
void Profile::SetTabTitle(std::wstring tabTitle) noexcept
|
|
{
|
|
_tabTitle = tabTitle;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Sets this profile's icon path.
|
|
// Arguments:
|
|
// - path: the path
|
|
void Profile::SetIconPath(std::wstring_view path) noexcept
|
|
{
|
|
_icon.emplace(path);
|
|
}
|
|
|
|
// Method Description:
|
|
// - Returns this profile's icon path, if one is set. Otherwise returns the empty string.
|
|
// Return Value:
|
|
// - this profile's icon path, if one is set. Otherwise returns the empty string.
|
|
std::wstring_view Profile::GetIconPath() const noexcept
|
|
{
|
|
return HasIcon() ?
|
|
std::wstring_view{ _icon.value().c_str(), _icon.value().size() } :
|
|
std::wstring_view{ L"", 0 };
|
|
}
|
|
|
|
// Method Description:
|
|
// - Returns the name of this profile.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - the name of this profile
|
|
std::wstring_view Profile::GetName() const noexcept
|
|
{
|
|
return _name;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Returns true if profile's custom tab title is set, if one is set. Otherwise returns false.
|
|
// Return Value:
|
|
// - true if this profile's custom tab title is set. Otherwise returns false.
|
|
bool Profile::HasTabTitle() const noexcept
|
|
{
|
|
return _tabTitle.has_value();
|
|
}
|
|
|
|
// Method Description:
|
|
// - Returns the custom tab title, if one is set. Otherwise returns the empty string.
|
|
// Return Value:
|
|
// - this profile's custom tab title, if one is set. Otherwise returns the empty string.
|
|
std::wstring_view Profile::GetTabTitle() const noexcept
|
|
{
|
|
return HasTabTitle() ?
|
|
std::wstring_view{ _tabTitle.value().c_str(), _tabTitle.value().size() } :
|
|
std::wstring_view{ L"", 0 };
|
|
}
|
|
|
|
bool Profile::GetCloseOnExit() const noexcept
|
|
{
|
|
return _closeOnExit;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Helper function for expanding any environment variables in a user-supplied starting directory and validating the resulting path
|
|
// Arguments:
|
|
// - The value from the profiles.json file
|
|
// Return Value:
|
|
// - The directory string with any environment variables expanded. If the resulting path is invalid,
|
|
// - the function returns an evaluated version of %userprofile% to avoid blocking the session from starting.
|
|
std::wstring Profile::EvaluateStartingDirectory(const std::wstring& directory)
|
|
{
|
|
// First expand path
|
|
DWORD numCharsInput = ExpandEnvironmentStrings(directory.c_str(), nullptr, 0);
|
|
std::unique_ptr<wchar_t[]> evaluatedPath = std::make_unique<wchar_t[]>(numCharsInput);
|
|
THROW_LAST_ERROR_IF(0 == ExpandEnvironmentStrings(directory.c_str(), evaluatedPath.get(), numCharsInput));
|
|
|
|
// Validate that the resulting path is legitimate
|
|
const DWORD dwFileAttributes = GetFileAttributes(evaluatedPath.get());
|
|
if ((dwFileAttributes != INVALID_FILE_ATTRIBUTES) && (WI_IsFlagSet(dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)))
|
|
{
|
|
return std::wstring(evaluatedPath.get(), numCharsInput);
|
|
}
|
|
else
|
|
{
|
|
// In the event where the user supplied a path that can't be resolved, use a reasonable default (in this case, %userprofile%)
|
|
const DWORD numCharsDefault = ExpandEnvironmentStrings(DEFAULT_STARTING_DIRECTORY.c_str(), nullptr, 0);
|
|
std::unique_ptr<wchar_t[]> defaultPath = std::make_unique<wchar_t[]>(numCharsDefault);
|
|
THROW_LAST_ERROR_IF(0 == ExpandEnvironmentStrings(DEFAULT_STARTING_DIRECTORY.c_str(), defaultPath.get(), numCharsDefault));
|
|
|
|
return std::wstring(defaultPath.get(), numCharsDefault);
|
|
}
|
|
}
|
|
|
|
// Method Description:
|
|
// - Helper function for converting a user-specified scrollbar state to its corresponding enum
|
|
// Arguments:
|
|
// - The value from the profiles.json file
|
|
// Return Value:
|
|
// - The corresponding enum value which maps to the string provided by the user
|
|
ScrollbarState Profile::ParseScrollbarState(const std::wstring& scrollbarState)
|
|
{
|
|
if (scrollbarState == AlwaysVisible)
|
|
{
|
|
return ScrollbarState::Visible;
|
|
}
|
|
else if (scrollbarState == AlwaysHide)
|
|
{
|
|
return ScrollbarState::Hidden;
|
|
}
|
|
else
|
|
{
|
|
return ScrollbarState::Visible;
|
|
}
|
|
}
|
|
|
|
// Method Description:
|
|
// - Helper function for converting a user-specified image stretch mode
|
|
// to the appropriate enum value
|
|
// Arguments:
|
|
// - The value from the profiles.json file
|
|
// Return Value:
|
|
// - The corresponding enum value which maps to the string provided by the user
|
|
winrt::Windows::UI::Xaml::Media::Stretch Profile::ParseImageStretchMode(const std::string_view imageStretchMode)
|
|
{
|
|
if (imageStretchMode == ImageStretchModeNone)
|
|
{
|
|
return winrt::Windows::UI::Xaml::Media::Stretch::None;
|
|
}
|
|
else if (imageStretchMode == ImageStretchModeFill)
|
|
{
|
|
return winrt::Windows::UI::Xaml::Media::Stretch::Fill;
|
|
}
|
|
else if (imageStretchMode == ImageStretchModeUniform)
|
|
{
|
|
return winrt::Windows::UI::Xaml::Media::Stretch::Uniform;
|
|
}
|
|
else // Fall through to default behavior
|
|
{
|
|
return winrt::Windows::UI::Xaml::Media::Stretch::UniformToFill;
|
|
}
|
|
}
|
|
|
|
// Method Description:
|
|
// - Helper function for converting an ImageStretchMode to the
|
|
// correct string value.
|
|
// Arguments:
|
|
// - imageStretchMode: The enum value to convert to a string.
|
|
// Return Value:
|
|
// - The string value for the given ImageStretchMode
|
|
std::string_view Profile::SerializeImageStretchMode(const winrt::Windows::UI::Xaml::Media::Stretch imageStretchMode)
|
|
{
|
|
switch (imageStretchMode)
|
|
{
|
|
case winrt::Windows::UI::Xaml::Media::Stretch::None:
|
|
return ImageStretchModeNone;
|
|
case winrt::Windows::UI::Xaml::Media::Stretch::Fill:
|
|
return ImageStretchModeFill;
|
|
case winrt::Windows::UI::Xaml::Media::Stretch::Uniform:
|
|
return ImageStretchModeUniform;
|
|
default:
|
|
case winrt::Windows::UI::Xaml::Media::Stretch::UniformToFill:
|
|
return ImageStretchModeUniformTofill;
|
|
}
|
|
}
|
|
|
|
// Method Description:
|
|
// - Helper function for converting a user-specified cursor style corresponding
|
|
// CursorStyle enum value
|
|
// Arguments:
|
|
// - cursorShapeString: The string value from the settings file to parse
|
|
// Return Value:
|
|
// - The corresponding enum value which maps to the string provided by the user
|
|
CursorStyle Profile::_ParseCursorShape(const std::wstring& cursorShapeString)
|
|
{
|
|
if (cursorShapeString == CursorShapeVintage)
|
|
{
|
|
return CursorStyle::Vintage;
|
|
}
|
|
else if (cursorShapeString == CursorShapeBar)
|
|
{
|
|
return CursorStyle::Bar;
|
|
}
|
|
else if (cursorShapeString == CursorShapeUnderscore)
|
|
{
|
|
return CursorStyle::Underscore;
|
|
}
|
|
else if (cursorShapeString == CursorShapeFilledbox)
|
|
{
|
|
return CursorStyle::FilledBox;
|
|
}
|
|
else if (cursorShapeString == CursorShapeEmptybox)
|
|
{
|
|
return CursorStyle::EmptyBox;
|
|
}
|
|
// default behavior for invalid data
|
|
return CursorStyle::Bar;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Helper function for converting a CursorStyle to its corresponding string
|
|
// value.
|
|
// Arguments:
|
|
// - cursorShape: The enum value to convert to a string.
|
|
// Return Value:
|
|
// - The string value for the given CursorStyle
|
|
std::wstring_view Profile::_SerializeCursorStyle(const CursorStyle cursorShape)
|
|
{
|
|
switch (cursorShape)
|
|
{
|
|
case CursorStyle::Underscore:
|
|
return CursorShapeUnderscore;
|
|
case CursorStyle::FilledBox:
|
|
return CursorShapeFilledbox;
|
|
case CursorStyle::EmptyBox:
|
|
return CursorShapeEmptybox;
|
|
case CursorStyle::Vintage:
|
|
return CursorShapeVintage;
|
|
default:
|
|
case CursorStyle::Bar:
|
|
return CursorShapeBar;
|
|
}
|
|
}
|