Add support for setting tabColor on the command line (#8102)

* Add a tabColor parameter to the `new-tab` and `split-panes` command
* Add --tabColor to the command line, to allow bootstrapping with tabs
  of different colors

Add another field to NewTerminalArgs. Use this field to set
StartingTabColor in Terminal. This color gets overridden by the color
defined by the profile / VT, however can be overridden with the color
picker.

Since the color is the property of the Terminal, when defined for the
tab this color is associated only with the first pane/terminal of the
tab. Additional panes will not inherit this color (to prevent advanced
resolution, where we need to resolve between the inherited color and the
one specified for the pane).

## Validation Steps Performed
* UT for parameters parsing
* Running system with several tabs of different colors.
* Adding custom actions with colors
* Performing operations like split pane, duplicate and so on

Closes #8075
This commit is contained in:
Don-Vito 2020-11-20 06:36:18 +02:00 committed by GitHub
parent a52a1d3b8d
commit fd37e1dc9f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 146 additions and 43 deletions

View file

@ -180,6 +180,11 @@
"index": {
"type": "integer",
"description": "The index of the profile in the new tab dropdown (starting at 0)"
},
"tabColor": {
"$ref": "#/definitions/Color",
"default": null,
"description": "If provided, will set the tab's color to the given value"
}
},
"type": "object"

View file

@ -408,7 +408,7 @@ namespace SettingsModelLocalTests
// Verify the args have the expected value
VERIFY_IS_NOT_NULL(realArgs.TabColor());
// Remember that COLORREFs are actually BBGGRR order, while the string is in #RRGGBB order
VERIFY_ARE_EQUAL(static_cast<uint32_t>(til::color(0x563412)), realArgs.TabColor().Value());
VERIFY_ARE_EQUAL(til::color(0x563412), til::color(realArgs.TabColor().Value()));
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('F') };

View file

@ -4,6 +4,7 @@
#include "pch.h"
#include <WexTestClass.h>
#include "../types/inc/utils.hpp"
#include "../TerminalApp/TerminalPage.h"
#include "../TerminalApp/AppCommandlineArgs.h"
@ -335,7 +336,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
auto myCommand = myArgs.TerminalArgs().Commandline();
VERIFY_ARE_EQUAL(L"powershell.exe \"This is an arg \"", myCommand);
@ -350,7 +352,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
auto myCommand = myArgs.TerminalArgs().Commandline();
VERIFY_ARE_EQUAL(L"\" with spaces\"", myCommand);
@ -373,7 +376,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
auto myCommand = myArgs.TerminalArgs().Commandline();
VERIFY_ARE_EQUAL(L"powershell.exe \"This is an arg ; with spaces\"", myCommand);
@ -419,7 +423,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_TRUE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
}
{
@ -438,7 +443,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_TRUE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_FALSE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"cmd", myArgs.TerminalArgs().Profile());
}
@ -458,7 +464,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_TRUE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_FALSE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"c:\\Foo", myArgs.TerminalArgs().StartingDirectory());
}
@ -478,7 +485,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"powershell.exe", myArgs.TerminalArgs().Commandline());
}
@ -498,7 +506,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
auto myCommand = myArgs.TerminalArgs().Commandline();
VERIFY_ARE_EQUAL(L"powershell.exe \"This is an arg with spaces\"", myCommand);
@ -519,7 +528,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
auto myCommand = myArgs.TerminalArgs().Commandline();
VERIFY_ARE_EQUAL(L"powershell.exe \"This is an arg with spaces\" another-arg \"more spaces in this one\"", myCommand);
@ -540,7 +550,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_TRUE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_FALSE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"Windows PowerShell", myArgs.TerminalArgs().Profile());
}
@ -560,7 +571,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"wsl -d Alpine", myArgs.TerminalArgs().Commandline());
}
@ -580,11 +591,35 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_FALSE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"wsl -d Alpine", myArgs.TerminalArgs().Commandline());
VERIFY_ARE_EQUAL(L"1", myArgs.TerminalArgs().Profile());
}
{
AppCommandlineArgs appArgs{};
std::vector<const wchar_t*> rawCommands{ L"wt.exe", subcommand, L"--tabColor", L"#009999" };
const auto expectedColor = Microsoft::Console::Utils::ColorFromHexString("#009999");
_buildCommandlinesHelper(appArgs, 1u, rawCommands);
VERIFY_ARE_EQUAL(1u, appArgs._startupActions.size());
auto actionAndArgs = appArgs._startupActions.at(0);
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action());
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<NewTabArgs>();
VERIFY_IS_NOT_NULL(myArgs);
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_NOT_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_ARE_EQUAL(til::color(myArgs.TerminalArgs().TabColor().Value()), expectedColor);
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
}
}
void CommandlineTest::ParseSplitPaneIntoArgs()
@ -677,7 +712,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_FALSE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"wsl -d Alpine", myArgs.TerminalArgs().Commandline());
VERIFY_ARE_EQUAL(L"1", myArgs.TerminalArgs().Profile());
@ -704,7 +740,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_FALSE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"wsl -d Alpine", myArgs.TerminalArgs().Commandline());
VERIFY_ARE_EQUAL(L"1", myArgs.TerminalArgs().Profile());
@ -731,7 +768,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_FALSE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"wsl -d Alpine -H", myArgs.TerminalArgs().Commandline());
VERIFY_ARE_EQUAL(L"1", myArgs.TerminalArgs().Profile());
@ -779,7 +817,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_TRUE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
}
{
@ -798,7 +837,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_TRUE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_FALSE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"cmd", myArgs.TerminalArgs().Profile());
}
@ -818,7 +858,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_TRUE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_FALSE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"c:\\Foo", myArgs.TerminalArgs().StartingDirectory());
}
@ -838,7 +879,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"powershell.exe", myArgs.TerminalArgs().Commandline());
}
@ -858,7 +900,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"powershell.exe \"This is an arg with spaces\"", myArgs.TerminalArgs().Commandline());
}
@ -988,7 +1031,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_TRUE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
actionAndArgs = appArgs._startupActions.at(1);
@ -1000,7 +1044,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_FALSE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
VERIFY_ARE_EQUAL(L"slpit-pane", myArgs.TerminalArgs().Commandline());
}
@ -1090,7 +1135,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_TRUE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
}
@ -1109,7 +1155,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_TRUE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
}
{
@ -1122,7 +1169,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_TRUE(myArgs.TerminalArgs().Commandline().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().StartingDirectory().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().TabTitle().empty());
VERIFY_IS_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_NULL(myArgs.TerminalArgs().TabColor());
VERIFY_IS_NULL(myArgs.TerminalArgs().ProfileIndex());
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
}
}

View file

@ -350,23 +350,20 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleSetTabColor(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
std::optional<til::color> tabColor;
Windows::Foundation::IReference<Windows::UI::Color> tabColor;
if (const auto& realArgs = args.ActionArgs().try_as<SetTabColorArgs>())
{
if (realArgs.TabColor() != nullptr)
{
tabColor = realArgs.TabColor().Value();
}
tabColor = realArgs.TabColor();
}
if (auto focusedTab = _GetFocusedTab())
{
if (auto activeTab = _GetTerminalTabImpl(focusedTab))
{
if (tabColor.has_value())
if (tabColor)
{
activeTab->SetRuntimeTabColor(tabColor.value());
activeTab->SetRuntimeTabColor(tabColor.Value());
}
else
{

View file

@ -4,6 +4,7 @@
#include "pch.h"
#include "AppLogic.h"
#include "AppCommandlineArgs.h"
#include "../types/inc/utils.hpp"
#include <LibraryResources.h>
using namespace winrt::TerminalApp;
@ -355,6 +356,10 @@ void AppCommandlineArgs::_addNewTerminalArgs(AppCommandlineArgs::NewTerminalSubc
_startingTitle,
RS_A(L"CmdTitleArgDesc"));
subcommand.tabColorOption = subcommand.subcommand->add_option("--tabColor",
_startingTabColor,
RS_A(L"CmdTabColorArgDesc"));
// Using positionals_at_end allows us to support "wt new-tab -d wsl -d Ubuntu"
// without CLI11 thinking that we've specified -d twice.
// There's an alternate construction where we make all subcommands "prefix commands",
@ -416,6 +421,12 @@ NewTerminalArgs AppCommandlineArgs::_getNewTerminalArgs(AppCommandlineArgs::NewT
args.TabTitle(winrt::to_hstring(_startingTitle));
}
if (*subcommand.tabColorOption)
{
const auto tabColor = Microsoft::Console::Utils::ColorFromHexString(_startingTabColor);
args.TabColor(static_cast<winrt::Windows::UI::Color>(tabColor));
}
return args;
}
@ -450,6 +461,7 @@ void AppCommandlineArgs::_resetStateToDefault()
_profileName.clear();
_startingDirectory.clear();
_startingTitle.clear();
_startingTabColor.clear();
_commandline.clear();
_splitVertical = false;

View file

@ -54,6 +54,7 @@ private:
CLI::Option* profileNameOption;
CLI::Option* startingDirectoryOption;
CLI::Option* titleOption;
CLI::Option* tabColorOption;
};
struct NewPaneSubcommand : public NewTerminalSubcommand
@ -74,6 +75,7 @@ private:
std::string _profileName;
std::string _startingDirectory;
std::string _startingTitle;
std::string _startingTabColor;
// _commandline will contain the command line with which we'll be spawning a new terminal
std::vector<std::string> _commandline;

View file

@ -295,6 +295,9 @@
<value>Open the terminal with the provided title instead of the profile's set "title"</value>
<comment>{Locked="\"title\""}</comment>
</data>
<data name="CmdTabColorArgDesc" xml:space="preserve">
<value>Open the tab with the specified color, in #rrggbb format</value>
</data>
<data name="CmdVersionDesc" xml:space="preserve">
<value>Display the application version</value>
</data>

View file

@ -61,6 +61,10 @@ namespace winrt::TerminalApp::implementation
{
settings.StartingTitle(newTerminalArgs.TabTitle());
}
if (newTerminalArgs.TabColor())
{
settings.StartingTabColor(static_cast<uint32_t>(til::color(newTerminalArgs.TabColor().Value())));
}
}
return { profileGuid, settings };

View file

@ -70,6 +70,16 @@ namespace winrt::TerminalApp::implementation
GETSET_PROPERTY(Windows::Foundation::IReference<uint32_t>, TabColor, nullptr);
// When set, StartingTabColor allows to create a terminal with a "sticky" tab color.
// This color is prioritized above the TabColor (that is usually initialized based on profile settings).
// Due to this prioritization, the tab color will be preserved upon settings reload
// (even if the profile's tab color gets altered or removed).
// This property is expected to be passed only once upon terminal creation.
// TODO: to ensure that this property is not populated during settings reload,
// we should consider moving this property to a separate interface,
// passed to the terminal only upon creation.
GETSET_PROPERTY(Windows::Foundation::IReference<uint32_t>, StartingTabColor, nullptr);
// ------------------------ End of Core Settings -----------------------
GETSET_PROPERTY(hstring, ProfileName);

View file

@ -35,6 +35,7 @@ namespace Microsoft.Terminal.TerminalControl
Boolean ForceVTInput;
Windows.Foundation.IReference<UInt32> TabColor;
Windows.Foundation.IReference<UInt32> StartingTabColor;
};
}

View file

@ -166,9 +166,15 @@ void Terminal::UpdateSettings(ICoreSettings settings)
{
_tabColor = til::color(settings.TabColor().Value() | 0xff000000);
}
if (!_startingTabColor && settings.StartingTabColor())
{
_startingTabColor = til::color(settings.StartingTabColor().Value() | 0xff000000);
}
if (_pfnTabColorChanged)
{
_pfnTabColorChanged(_tabColor);
_pfnTabColorChanged(GetTabColor());
}
// TODO:MSFT:21327402 - if HistorySize has changed, resize the buffer so we
@ -1171,9 +1177,12 @@ void Terminal::ClearPatternTree() noexcept
_InvalidatePatternTree(oldTree);
}
// Method Description:
// - Returns the tab color
// If the starting color exits, it's value is preferred
const std::optional<til::color> Terminal::GetTabColor() const noexcept
{
return _tabColor;
return _startingTabColor.has_value() ? _startingTabColor : _tabColor;
}
BlinkingState& Terminal::GetBlinkingState() const noexcept

View file

@ -235,6 +235,7 @@ private:
std::optional<std::wstring> _title;
std::wstring _startingTitle;
std::optional<til::color> _tabColor;
std::optional<til::color> _startingTabColor;
std::array<COLORREF, XTERM_COLOR_TABLE_SIZE> _colorTable;
COLORREF _defaultFg;

View file

@ -56,6 +56,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
ss << fmt::format(L"title: {}, ", _TabTitle);
}
if (_TabColor)
{
const til::color tabColor{ _TabColor.Value() };
ss << fmt::format(L"tabColor: {}, ", tabColor.ToHexString(true));
}
auto s = ss.str();
if (s.empty())
{
@ -300,10 +307,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// "Reset tab color"
if (_TabColor)
{
til::color c{ _TabColor.Value() };
til::color tabColor{ _TabColor.Value() };
return winrt::hstring{
fmt::format(std::wstring_view(RS_(L"SetTabColorCommandKey")),
c.ToHexString(true))
tabColor.ToHexString(true))
};
}

View file

@ -60,12 +60,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
GETSET_PROPERTY(winrt::hstring, Commandline, L"");
GETSET_PROPERTY(winrt::hstring, StartingDirectory, L"");
GETSET_PROPERTY(winrt::hstring, TabTitle, L"");
GETSET_PROPERTY(Windows::Foundation::IReference<Windows::UI::Color>, TabColor, nullptr);
GETSET_PROPERTY(Windows::Foundation::IReference<int32_t>, ProfileIndex, nullptr);
GETSET_PROPERTY(winrt::hstring, Profile, L"");
static constexpr std::string_view CommandlineKey{ "commandline" };
static constexpr std::string_view StartingDirectoryKey{ "startingDirectory" };
static constexpr std::string_view TabTitleKey{ "tabTitle" };
static constexpr std::string_view TabColorKey{ "tabColor" };
static constexpr std::string_view ProfileIndexKey{ "index" };
static constexpr std::string_view ProfileKey{ "profile" };
@ -77,6 +79,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
return other.Commandline() == _Commandline &&
other.StartingDirectory() == _StartingDirectory &&
other.TabTitle() == _TabTitle &&
other.TabColor() == _TabColor &&
other.ProfileIndex() == _ProfileIndex &&
other.Profile() == _Profile;
};
@ -89,6 +92,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
JsonUtils::GetValueForKey(json, TabTitleKey, args->_TabTitle);
JsonUtils::GetValueForKey(json, ProfileIndexKey, args->_ProfileIndex);
JsonUtils::GetValueForKey(json, ProfileKey, args->_Profile);
JsonUtils::GetValueForKey(json, TabColorKey, args->_TabColor);
return *args;
}
Model::NewTerminalArgs Copy() const
@ -97,6 +101,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
copy->_Commandline = _Commandline;
copy->_StartingDirectory = _StartingDirectory;
copy->_TabTitle = _TabTitle;
copy->_TabColor = _TabColor;
copy->_ProfileIndex = _ProfileIndex;
copy->_Profile = _Profile;
return *copy;
@ -493,7 +498,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
struct SetTabColorArgs : public SetTabColorArgsT<SetTabColorArgs>
{
SetTabColorArgs() = default;
GETSET_PROPERTY(Windows::Foundation::IReference<uint32_t>, TabColor, nullptr);
GETSET_PROPERTY(Windows::Foundation::IReference<Windows::UI::Color>, TabColor, nullptr);
static constexpr std::string_view ColorKey{ "color" };
@ -513,10 +518,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
// LOAD BEARING: Not using make_self here _will_ break you in the future!
auto args = winrt::make_self<SetTabColorArgs>();
if (const auto temp{ JsonUtils::GetValueForKey<std::optional<til::color>>(json, ColorKey) })
{
args->_TabColor = static_cast<uint32_t>(*temp);
}
JsonUtils::GetValueForKey(json, ColorKey, args->_TabColor);
return { *args, {} };
}
IActionArgs Copy() const

View file

@ -54,6 +54,7 @@ namespace Microsoft.Terminal.Settings.Model
String Commandline;
String StartingDirectory;
String TabTitle;
Windows.Foundation.IReference<Windows.UI.Color> TabColor;
String Profile; // Either a GUID or a profile's name if the GUID isn't a match
// ProfileIndex can be null (for "use the default"), so this needs to be
// a IReference, so it's nullable
@ -130,7 +131,7 @@ namespace Microsoft.Terminal.Settings.Model
[default_interface] runtimeclass SetTabColorArgs : IActionArgs
{
Windows.Foundation.IReference<UInt32> TabColor { get; };
Windows.Foundation.IReference<Windows.UI.Color> TabColor { get; };
};
[default_interface] runtimeclass RenameTabArgs : IActionArgs

View file

@ -62,6 +62,7 @@ namespace TerminalCoreUnitTests
void ForceVTInput(bool) {}
GETSET_PROPERTY(winrt::Windows::Foundation::IReference<uint32_t>, TabColor, nullptr);
GETSET_PROPERTY(winrt::Windows::Foundation::IReference<uint32_t>, StartingTabColor, nullptr);
private:
int32_t _historySize;