Compare commits

..

4 Commits

Author SHA1 Message Date
Dustin L. Howett
3dca4263d5 Migrate spelling-0.0.21 changes from main 2020-07-13 16:59:33 -07:00
Dustin L. Howett
462006ba51 Migrate spelling-0.0.19 changes from main 2020-07-13 16:59:33 -07:00
Michael Niksa
5b6d2e0708 change interface to not use Clusters. Just build a string and a clustermap vector. 2020-07-14 15:40:59 -07:00
Michael Niksa
ffe0e024b3 Go at the buffer a bit more directly and get some perf. 2020-07-14 15:40:55 -07:00
161 changed files with 2750 additions and 4033 deletions

View File

@@ -8,7 +8,7 @@
<!--<add key="Static Package Dependencies" value="dep\packages" />-->
<!-- Use our own NuGet Feed -->
<add key="TerminalDependencies" value="https://pkgs.dev.azure.com/ms/terminal/_packaging/TerminalDependencies/nuget/v3/index.json" />
<add key="Windows Terminal NuGet Feed" value="https://terminalnuget.blob.core.windows.net/feed/index.json" />
<!-- Internal NuGet feeds that may not be accessible outside Microsoft corporate network -->
<!--<add key="TAEF - internal" value="https://microsoft.pkgs.visualstudio.com/DefaultCollection/_packaging/Taef/nuget/v3/index.json" />

View File

@@ -5,7 +5,7 @@
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
<XesBaseYearForStoreVersion>2020</XesBaseYearForStoreVersion>
<VersionMajor>1</VersionMajor>
<VersionMinor>3</VersionMinor>
<VersionMinor>2</VersionMinor>
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
</PropertyGroup>
</Project>

View File

@@ -63,7 +63,6 @@
"openTabColorPicker",
"renameTab",
"commandPalette",
"wt",
"unbound"
],
"type": "string"
@@ -281,23 +280,6 @@
}
]
},
"WtAction": {
"description": "Arguments corresponding to a wt Action",
"allOf": [
{ "$ref": "#/definitions/ShortcutAction" },
{
"properties": {
"action": { "type": "string", "pattern": "wt" },
"commandline": {
"type": "string",
"default": "",
"description": "a `wt` commandline to run in the current window"
}
}
}
],
"required": [ "commandline" ]
},
"Keybinding": {
"additionalProperties": false,
"properties": {
@@ -314,7 +296,6 @@
{ "$ref": "#/definitions/SplitPaneAction" },
{ "$ref": "#/definitions/OpenSettingsAction" },
{ "$ref": "#/definitions/SetTabColorAction" },
{ "$ref": "#/definitions/WtAction" },
{ "type": "null" }
]
},

Binary file not shown.

Binary file not shown.

View File

@@ -17,5 +17,5 @@ Please consult the [license](https://raw.githubusercontent.com/microsoft/cascadi
### Fonts Included
* Cascadia Code, Cascadia Mono (2007.15)
* from microsoft/cascadia-code@2a54363b2c867f7ae811b9a034c0024cef67de96
* Cascadia Code, Cascadia Mono (2007.01)
* from microsoft/cascadia-code@311cc603f30635da704b6a7d13050e245e61667b

View File

@@ -108,7 +108,12 @@ TextAttribute ATTR_ROW::GetAttrByColumn(const size_t column,
{
THROW_HR_IF(E_INVALIDARG, column >= _cchRowWidth);
const auto runPos = FindAttrIndex(column, pApplies);
return _list.at(runPos).GetAttributes();
return GetAttrByIndex(runPos);
}
TextAttribute ATTR_ROW::GetAttrByIndex(const size_t index) const
{
return _list.at(index).GetAttributes();
}
// Routine Description:
@@ -223,7 +228,7 @@ void ATTR_ROW::ReplaceAttrs(const TextAttribute& toBeReplacedAttr, const TextAtt
// Return Value:
// - STATUS_NO_MEMORY if there wasn't enough memory to insert the runs
// otherwise STATUS_SUCCESS if we were successful.
[[nodiscard]] HRESULT ATTR_ROW::InsertAttrRuns(const gsl::span<const TextAttributeRun> newAttrs,
[[nodiscard]] HRESULT ATTR_ROW::InsertAttrRuns(const std::basic_string_view<TextAttributeRun> newAttrs,
const size_t iStart,
const size_t iEnd,
const size_t cBufferWidth)
@@ -250,7 +255,7 @@ void ATTR_ROW::ReplaceAttrs(const TextAttribute& toBeReplacedAttr, const TextAtt
if (newAttrs.size() == 1)
{
// Get the new color attribute we're trying to apply
const TextAttribute NewAttr = til::at(newAttrs, 0).GetAttributes();
const TextAttribute NewAttr = newAttrs.at(0).GetAttributes();
// If the existing run was only 1 element...
// ...and the new color is the same as the old, we don't have to do anything and can exit quick.
@@ -372,7 +377,7 @@ void ATTR_ROW::ReplaceAttrs(const TextAttribute& toBeReplacedAttr, const TextAtt
if (iStart == 0 && iEnd == iLastBufferCol)
{
// Just dump what we're given over what we have and call it a day.
_list.assign(newAttrs.begin(), newAttrs.end());
_list.assign(newAttrs.cbegin(), newAttrs.cend());
return S_OK;
}

View File

@@ -36,6 +36,8 @@ public:
TextAttribute GetAttrByColumn(const size_t column,
size_t* const pApplies) const;
TextAttribute GetAttrByIndex(const size_t index) const;
size_t GetNumberOfRuns() const noexcept;
size_t FindAttrIndex(const size_t index,
@@ -46,7 +48,7 @@ public:
void Resize(const size_t newWidth);
[[nodiscard]] HRESULT InsertAttrRuns(const gsl::span<const TextAttributeRun> newAttrs,
[[nodiscard]] HRESULT InsertAttrRuns(const std::basic_string_view<TextAttributeRun> newAttrs,
const size_t iStart,
const size_t iEnd,
const size_t cBufferWidth);

View File

@@ -112,9 +112,9 @@ OutputCellIterator::OutputCellIterator(const std::wstring_view utf16Text, const
// - This is an iterator over legacy colors only. The text is not modified.
// Arguments:
// - legacyAttrs - One legacy color item per cell
OutputCellIterator::OutputCellIterator(const gsl::span<const WORD> legacyAttrs) noexcept :
OutputCellIterator::OutputCellIterator(const std::basic_string_view<WORD> legacyAttrs) noexcept :
_mode(Mode::LegacyAttr),
_currentView(s_GenerateViewLegacyAttr(til::at(legacyAttrs, 0))),
_currentView(s_GenerateViewLegacyAttr(legacyAttrs.at(0))),
_run(legacyAttrs),
_attr(InvalidTextAttribute),
_distance(0),
@@ -127,9 +127,9 @@ OutputCellIterator::OutputCellIterator(const gsl::span<const WORD> legacyAttrs)
// - This is an iterator over legacy cell data. We will use the unicode text and the legacy color attribute.
// Arguments:
// - charInfos - Multiple cell with unicode text and legacy color data.
OutputCellIterator::OutputCellIterator(const gsl::span<const CHAR_INFO> charInfos) noexcept :
OutputCellIterator::OutputCellIterator(const std::basic_string_view<CHAR_INFO> charInfos) noexcept :
_mode(Mode::CharInfo),
_currentView(s_GenerateView(til::at(charInfos, 0))),
_currentView(s_GenerateView(charInfos.at(0))),
_run(charInfos),
_attr(InvalidTextAttribute),
_distance(0),
@@ -142,9 +142,9 @@ OutputCellIterator::OutputCellIterator(const gsl::span<const CHAR_INFO> charInfo
// - This is an iterator over existing OutputCells with full text and color data.
// Arguments:
// - cells - Multiple cells in a run
OutputCellIterator::OutputCellIterator(const gsl::span<const OutputCell> cells) :
OutputCellIterator::OutputCellIterator(const std::basic_string_view<OutputCell> cells) :
_mode(Mode::Cell),
_currentView(s_GenerateView(til::at(cells, 0))),
_currentView(s_GenerateView(cells.at(0))),
_run(cells),
_attr(InvalidTextAttribute),
_distance(0),
@@ -180,15 +180,15 @@ OutputCellIterator::operator bool() const noexcept
}
case Mode::Cell:
{
return _pos < std::get<gsl::span<const OutputCell>>(_run).size();
return _pos < std::get<std::basic_string_view<OutputCell>>(_run).length();
}
case Mode::CharInfo:
{
return _pos < std::get<gsl::span<const CHAR_INFO>>(_run).size();
return _pos < std::get<std::basic_string_view<CHAR_INFO>>(_run).length();
}
case Mode::LegacyAttr:
{
return _pos < std::get<gsl::span<const WORD>>(_run).size();
return _pos < std::get<std::basic_string_view<WORD>>(_run).length();
}
default:
FAIL_FAST_HR(E_NOTIMPL);
@@ -265,7 +265,7 @@ OutputCellIterator& OutputCellIterator::operator++()
_pos++;
if (operator bool())
{
_currentView = s_GenerateView(til::at(std::get<gsl::span<const OutputCell>>(_run), _pos));
_currentView = s_GenerateView(std::get<std::basic_string_view<OutputCell>>(_run).at(_pos));
}
break;
}
@@ -275,7 +275,7 @@ OutputCellIterator& OutputCellIterator::operator++()
_pos++;
if (operator bool())
{
_currentView = s_GenerateView(til::at(std::get<gsl::span<const CHAR_INFO>>(_run), _pos));
_currentView = s_GenerateView(std::get<std::basic_string_view<CHAR_INFO>>(_run).at(_pos));
}
break;
}
@@ -285,7 +285,7 @@ OutputCellIterator& OutputCellIterator::operator++()
_pos++;
if (operator bool())
{
_currentView = s_GenerateViewLegacyAttr(til::at(std::get<gsl::span<const WORD>>(_run), _pos));
_currentView = s_GenerateViewLegacyAttr(std::get<std::basic_string_view<WORD>>(_run).at(_pos));
}
break;
}

View File

@@ -39,9 +39,9 @@ public:
OutputCellIterator(const CHAR_INFO& charInfo, const size_t fillLimit = 0) noexcept;
OutputCellIterator(const std::wstring_view utf16Text);
OutputCellIterator(const std::wstring_view utf16Text, const TextAttribute attribute);
OutputCellIterator(const gsl::span<const WORD> legacyAttributes) noexcept;
OutputCellIterator(const gsl::span<const CHAR_INFO> charInfos) noexcept;
OutputCellIterator(const gsl::span<const OutputCell> cells);
OutputCellIterator(const std::basic_string_view<WORD> legacyAttributes) noexcept;
OutputCellIterator(const std::basic_string_view<CHAR_INFO> charInfos) noexcept;
OutputCellIterator(const std::basic_string_view<OutputCell> cells);
~OutputCellIterator() = default;
OutputCellIterator& operator=(const OutputCellIterator& it) = default;
@@ -86,13 +86,13 @@ private:
};
Mode _mode;
gsl::span<const WORD> _legacyAttrs;
std::basic_string_view<WORD> _legacyAttrs;
std::variant<
std::wstring_view,
gsl::span<const WORD>,
gsl::span<const CHAR_INFO>,
gsl::span<const OutputCell>,
std::basic_string_view<WORD>,
std::basic_string_view<CHAR_INFO>,
std::basic_string_view<OutputCell>,
std::monostate>
_run;

View File

@@ -50,7 +50,7 @@ gsl::span<OutputCell> OutputCellRect::GetRow(const size_t row)
// - Read-only iterator of OutputCells
OutputCellIterator OutputCellRect::GetRowIter(const size_t row) const
{
const gsl::span<const OutputCell> view(_FindRowOffset(row), _cols);
const std::basic_string_view<OutputCell> view(_FindRowOffset(row), _cols);
return OutputCellIterator(view);
}

View File

@@ -160,98 +160,66 @@ OutputCellIterator ROW::WriteCells(OutputCellIterator it, const size_t index, co
// If we're given a right-side column limit, use it. Otherwise, the write limit is the final column index available in the char row.
const auto finalColumnInRow = limitRight.value_or(_charRow.size() - 1);
if (it)
while (it && currentIndex <= finalColumnInRow)
{
// Accumulate usages of the same color so we can spend less time in InsertAttrRuns rewriting it.
auto currentColor = it->TextAttr();
size_t colorUses = 0;
size_t colorStarts = index;
while (it && currentIndex <= finalColumnInRow)
// Fill the color if the behavior isn't set to keeping the current color.
if (it->TextAttrBehavior() != TextAttributeBehavior::Current)
{
// Fill the color if the behavior isn't set to keeping the current color.
if (it->TextAttrBehavior() != TextAttributeBehavior::Current)
const TextAttributeRun attrRun{ 1, it->TextAttr() };
LOG_IF_FAILED(_attrRow.InsertAttrRuns({ &attrRun, 1 },
currentIndex,
currentIndex,
_charRow.size()));
}
// Fill the text if the behavior isn't set to saying there's only a color stored in this iterator.
if (it->TextAttrBehavior() != TextAttributeBehavior::StoredOnly)
{
const bool fillingLastColumn = currentIndex == finalColumnInRow;
// TODO: MSFT: 19452170 - We need to ensure when writing any trailing byte that the one to the left
// is a matching leading byte. Likewise, if we're writing a leading byte, we need to make sure we still have space in this loop
// for the trailing byte coming up before writing it.
// If we're trying to fill the first cell with a trailing byte, pad it out instead by clearing it.
// Don't increment iterator. We'll advance the index and try again with this value on the next round through the loop.
if (currentIndex == 0 && it->DbcsAttr().IsTrailing())
{
// If the color of this cell is the same as the run we're currently on,
// just increment the counter.
if (currentColor == it->TextAttr())
{
++colorUses;
}
else
{
// Otherwise, commit this color into the run and save off the new one.
const TextAttributeRun run{ colorUses, currentColor };
// Now commit the new color runs into the attr row.
LOG_IF_FAILED(_attrRow.InsertAttrRuns({ &run, 1 },
colorStarts,
currentIndex - 1,
_charRow.size()));
currentColor = it->TextAttr();
colorUses = 1;
colorStarts = currentIndex;
}
_charRow.ClearCell(currentIndex);
}
// Fill the text if the behavior isn't set to saying there's only a color stored in this iterator.
if (it->TextAttrBehavior() != TextAttributeBehavior::StoredOnly)
// If we're trying to fill the last cell with a leading byte, pad it out instead by clearing it.
// Don't increment iterator. We'll exit because we couldn't write a lead at the end of a line.
else if (fillingLastColumn && it->DbcsAttr().IsLeading())
{
const bool fillingLastColumn = currentIndex == finalColumnInRow;
// TODO: MSFT: 19452170 - We need to ensure when writing any trailing byte that the one to the left
// is a matching leading byte. Likewise, if we're writing a leading byte, we need to make sure we still have space in this loop
// for the trailing byte coming up before writing it.
// If we're trying to fill the first cell with a trailing byte, pad it out instead by clearing it.
// Don't increment iterator. We'll advance the index and try again with this value on the next round through the loop.
if (currentIndex == 0 && it->DbcsAttr().IsTrailing())
{
_charRow.ClearCell(currentIndex);
}
// If we're trying to fill the last cell with a leading byte, pad it out instead by clearing it.
// Don't increment iterator. We'll exit because we couldn't write a lead at the end of a line.
else if (fillingLastColumn && it->DbcsAttr().IsLeading())
{
_charRow.ClearCell(currentIndex);
_charRow.SetDoubleBytePadded(true);
}
// Otherwise, copy the data given and increment the iterator.
else
{
_charRow.DbcsAttrAt(currentIndex) = it->DbcsAttr();
_charRow.GlyphAt(currentIndex) = it->Chars();
++it;
}
// If we're asked to (un)set the wrap status and we just filled the last column with some text...
// NOTE:
// - wrap = std::nullopt --> don't change the wrap value
// - wrap = true --> we're filling cells as a steam, consider this a wrap
// - wrap = false --> we're filling cells as a block, unwrap
if (wrap.has_value() && fillingLastColumn)
{
// set wrap status on the row to parameter's value.
_charRow.SetWrapForced(wrap.value());
}
_charRow.ClearCell(currentIndex);
_charRow.SetDoubleBytePadded(true);
}
// Otherwise, copy the data given and increment the iterator.
else
{
_charRow.DbcsAttrAt(currentIndex) = it->DbcsAttr();
_charRow.GlyphAt(currentIndex) = it->Chars();
++it;
}
// Move to the next cell for the next time through the loop.
++currentIndex;
// If we're asked to (un)set the wrap status and we just filled the last column with some text...
// NOTE:
// - wrap = std::nullopt --> don't change the wrap value
// - wrap = true --> we're filling cells as a steam, consider this a wrap
// - wrap = false --> we're filling cells as a block, unwrap
if (wrap.has_value() && fillingLastColumn)
{
// set wrap status on the row to parameter's value.
_charRow.SetWrapForced(wrap.value());
}
}
else
{
++it;
}
// Now commit the final color into the attr row
if (colorUses)
{
const TextAttributeRun run{ colorUses, currentColor };
LOG_IF_FAILED(_attrRow.InsertAttrRuns({ &run, 1 },
colorStarts,
currentIndex - 1,
_charRow.size()));
}
// Move to the next cell for the next time through the loop.
++currentIndex;
}
return it;

View File

@@ -90,7 +90,7 @@ bool TextAttribute::IsLegacy() const noexcept
// - reverseScreenMode: true if the screen mode is reversed.
// Return Value:
// - the foreground and background colors that should be displayed.
std::pair<COLORREF, COLORREF> TextAttribute::CalculateRgbColors(const gsl::span<const COLORREF> colorTable,
std::pair<COLORREF, COLORREF> TextAttribute::CalculateRgbColors(const std::basic_string_view<COLORREF> colorTable,
const COLORREF defaultFgColor,
const COLORREF defaultBgColor,
const bool reverseScreenMode) const noexcept
@@ -270,7 +270,7 @@ void TextAttribute::SetFaint(bool isFaint) noexcept
WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::Faint, isFaint);
}
void TextAttribute::SetItalic(bool isItalic) noexcept
void TextAttribute::SetItalics(bool isItalic) noexcept
{
WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::Italics, isItalic);
}
@@ -290,13 +290,13 @@ void TextAttribute::SetCrossedOut(bool isCrossedOut) noexcept
WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::CrossedOut, isCrossedOut);
}
void TextAttribute::SetUnderlined(bool isUnderlined) noexcept
void TextAttribute::SetUnderline(bool isUnderlined) noexcept
{
// TODO:GH#2915 Treat underline separately from LVB_UNDERSCORE
WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_UNDERSCORE, isUnderlined);
}
void TextAttribute::SetOverlined(bool isOverlined) noexcept
void TextAttribute::SetOverline(bool isOverlined) noexcept
{
WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_GRID_HORIZONTAL, isOverlined);
}

View File

@@ -63,7 +63,7 @@ public:
static TextAttribute StripErroneousVT16VersionsOfLegacyDefaults(const TextAttribute& attribute) noexcept;
WORD GetLegacyAttributes() const noexcept;
std::pair<COLORREF, COLORREF> CalculateRgbColors(const gsl::span<const COLORREF> colorTable,
std::pair<COLORREF, COLORREF> CalculateRgbColors(const std::basic_string_view<COLORREF> colorTable,
const COLORREF defaultFgColor,
const COLORREF defaultBgColor,
const bool reverseScreenMode = false) const noexcept;
@@ -100,12 +100,12 @@ public:
void SetBold(bool isBold) noexcept;
void SetFaint(bool isFaint) noexcept;
void SetItalic(bool isItalic) noexcept;
void SetItalics(bool isItalic) noexcept;
void SetBlinking(bool isBlinking) noexcept;
void SetInvisible(bool isInvisible) noexcept;
void SetCrossedOut(bool isCrossedOut) noexcept;
void SetUnderlined(bool isUnderlined) noexcept;
void SetOverlined(bool isOverlined) noexcept;
void SetUnderline(bool isUnderlined) noexcept;
void SetOverline(bool isOverlined) noexcept;
void SetReverseVideo(bool isReversed) noexcept;
ExtendedAttributes GetExtendedAttributes() const noexcept;
@@ -218,12 +218,11 @@ namespace WEX
static WEX::Common::NoThrowString ToString(const TextAttribute& attr)
{
return WEX::Common::NoThrowString().Format(
L"{FG:%s,BG:%s,bold:%d,wLegacy:(0x%04x),ext:(0x%02x)}",
L"{FG:%s,BG:%s,bold:%d,wLegacy:(0x%04x)}",
VerifyOutputTraits<TextColor>::ToString(attr._foreground).GetBuffer(),
VerifyOutputTraits<TextColor>::ToString(attr._background).GetBuffer(),
attr.IsBold(),
attr._wAttrLegacy,
static_cast<DWORD>(attr._extendedAttrs));
attr._wAttrLegacy);
}
};
}

View File

@@ -138,7 +138,7 @@ void TextColor::SetDefault() noexcept
// - brighten: if true, we'll brighten a dark color table index.
// Return Value:
// - a COLORREF containing the real value of this TextColor.
COLORREF TextColor::GetColor(gsl::span<const COLORREF> colorTable,
COLORREF TextColor::GetColor(std::basic_string_view<COLORREF> colorTable,
const COLORREF defaultColor,
bool brighten) const noexcept
{
@@ -158,9 +158,9 @@ COLORREF TextColor::GetColor(gsl::span<const COLORREF> colorTable,
// If we find a match, return instead the bright version of this color
for (size_t i = 0; i < 8; i++)
{
if (til::at(colorTable, i) == defaultColor)
if (colorTable.at(i) == defaultColor)
{
return til::at(colorTable, i + 8);
return colorTable.at(i + 8);
}
}
}
@@ -173,11 +173,11 @@ COLORREF TextColor::GetColor(gsl::span<const COLORREF> colorTable,
}
else if (IsIndex16() && brighten)
{
return til::at(colorTable, _index | 8);
return colorTable.at(_index | 8);
}
else
{
return til::at(colorTable, _index);
return colorTable.at(_index);
}
}

View File

@@ -88,7 +88,7 @@ public:
void SetIndex(const BYTE index, const bool isIndex256) noexcept;
void SetDefault() noexcept;
COLORREF GetColor(gsl::span<const COLORREF> colorTable,
COLORREF GetColor(std::basic_string_view<COLORREF> colorTable,
const COLORREF defaultColor,
const bool brighten = false) const noexcept;

View File

@@ -787,7 +787,7 @@ const Cursor& TextBuffer::GetCursor() const noexcept
return _currentAttributes;
}
void TextBuffer::SetCurrentAttributes(const TextAttribute& currentAttributes) noexcept
void TextBuffer::SetCurrentAttributes(const TextAttribute currentAttributes) noexcept
{
_currentAttributes = currentAttributes;
}

View File

@@ -118,7 +118,7 @@ public:
[[nodiscard]] TextAttribute GetCurrentAttributes() const noexcept;
void SetCurrentAttributes(const TextAttribute& currentAttributes) noexcept;
void SetCurrentAttributes(const TextAttribute currentAttributes) noexcept;
void Reset();

View File

@@ -27,7 +27,7 @@ class TextAttributeTests
COLORREF _colorTable[COLOR_TABLE_SIZE];
COLORREF _defaultFg = RGB(1, 2, 3);
COLORREF _defaultBg = RGB(4, 5, 6);
gsl::span<const COLORREF> _GetTableView();
std::basic_string_view<COLORREF> _GetTableView();
};
bool TextAttributeTests::ClassSetup()
@@ -51,9 +51,9 @@ bool TextAttributeTests::ClassSetup()
return true;
}
gsl::span<const COLORREF> TextAttributeTests::_GetTableView()
std::basic_string_view<COLORREF> TextAttributeTests::_GetTableView()
{
return gsl::span<const COLORREF>(&_colorTable[0], COLOR_TABLE_SIZE);
return std::basic_string_view<COLORREF>(&_colorTable[0], COLOR_TABLE_SIZE);
}
void TextAttributeTests::TestRoundtripLegacy()

View File

@@ -27,7 +27,7 @@ class TextColorTests
COLORREF _colorTable[COLOR_TABLE_SIZE];
COLORREF _defaultFg = RGB(1, 2, 3);
COLORREF _defaultBg = RGB(4, 5, 6);
gsl::span<const COLORREF> _GetTableView();
std::basic_string_view<COLORREF> _GetTableView();
};
bool TextColorTests::ClassSetup()
@@ -51,9 +51,9 @@ bool TextColorTests::ClassSetup()
return true;
}
gsl::span<const COLORREF> TextColorTests::_GetTableView()
std::basic_string_view<COLORREF> TextColorTests::_GetTableView()
{
return gsl::span<const COLORREF>(&_colorTable[0], COLOR_TABLE_SIZE);
return std::basic_string_view<COLORREF>(&_colorTable[0], COLOR_TABLE_SIZE);
}
void TextColorTests::TestDefaultColor()

View File

@@ -147,8 +147,10 @@ namespace TerminalAppLocalTests
{ "name": "command0", "command": { "action": "splitPane", "split": null } },
{ "name": "command1", "command": { "action": "splitPane", "split": "vertical" } },
{ "name": "command2", "command": { "action": "splitPane", "split": "horizontal" } },
{ "name": "command3", "command": { "action": "splitPane", "split": "none" } },
{ "name": "command4", "command": { "action": "splitPane" } },
{ "name": "command5", "command": { "action": "splitPane", "split": "auto" } }
{ "name": "command5", "command": { "action": "splitPane", "split": "auto" } },
{ "name": "command6", "command": { "action": "splitPane", "split": "foo" } }
])" };
const auto commands0Json = VerifyParseSucceeded(commands0String);
@@ -157,7 +159,7 @@ namespace TerminalAppLocalTests
VERIFY_ARE_EQUAL(0u, commands.size());
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
VERIFY_ARE_EQUAL(5u, commands.size());
VERIFY_ARE_EQUAL(7u, commands.size());
{
auto command = commands.at(L"command0");
@@ -189,6 +191,16 @@ namespace TerminalAppLocalTests
// Verify the args have the expected value
VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Horizontal, realArgs.SplitStyle());
}
{
auto command = commands.at(L"command3");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.Action());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.Action().Action());
const auto& realArgs = command.Action().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
}
{
auto command = commands.at(L"command4");
VERIFY_IS_NOT_NULL(command);
@@ -209,6 +221,16 @@ namespace TerminalAppLocalTests
// Verify the args have the expected value
VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
}
{
auto command = commands.at(L"command6");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.Action());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.Action().Action());
const auto& realArgs = command.Action().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
}
}
void CommandTests::TestResourceKeyName()
{

View File

@@ -4,9 +4,7 @@
#include "pch.h"
#include <WexTestClass.h>
#include "../TerminalApp/TerminalPage.h"
#include "../TerminalApp/AppCommandlineArgs.h"
#include "../TerminalApp/ActionArgs.h"
using namespace WEX::Logging;
using namespace WEX::Common;
@@ -54,10 +52,6 @@ namespace TerminalAppLocalTests
TEST_METHOD(CheckTypos);
TEST_METHOD(TestSimpleExecuteCommandlineAction);
TEST_METHOD(TestMultipleCommandExecuteCommandlineAction);
TEST_METHOD(TestInvalidExecuteCommandlineAction);
private:
void _buildCommandlinesHelper(AppCommandlineArgs& appArgs,
const size_t expectedSubcommands,
@@ -1073,66 +1067,4 @@ namespace TerminalAppLocalTests
VERIFY_ARE_EQUAL(L"C:\\", myArgs.TerminalArgs().StartingDirectory());
}
}
void CommandlineTest::TestSimpleExecuteCommandlineAction()
{
auto args = winrt::make_self<implementation::ExecuteCommandlineArgs>();
args->Commandline(L"new-tab");
auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(*args);
VERIFY_ARE_EQUAL(1u, actions.size());
auto actionAndArgs = actions.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_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
}
void CommandlineTest::TestMultipleCommandExecuteCommandlineAction()
{
auto args = winrt::make_self<implementation::ExecuteCommandlineArgs>();
args->Commandline(L"new-tab ; split-pane");
auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(*args);
VERIFY_ARE_EQUAL(2u, actions.size());
{
auto actionAndArgs = actions.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_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
}
{
auto actionAndArgs = actions.at(1);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
auto myArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
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_TRUE(myArgs.TerminalArgs().ProfileIndex() == nullptr);
VERIFY_IS_TRUE(myArgs.TerminalArgs().Profile().empty());
}
}
void CommandlineTest::TestInvalidExecuteCommandlineAction()
{
auto args = winrt::make_self<implementation::ExecuteCommandlineArgs>();
// -H and -V cannot be combined.
args->Commandline(L"split-pane -H -V");
auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(*args);
VERIFY_ARE_EQUAL(0u, actions.size());
}
}

View File

@@ -323,8 +323,10 @@ namespace TerminalAppLocalTests
{ "keys": ["ctrl+c"], "command": { "action": "splitPane", "split": null } },
{ "keys": ["ctrl+d"], "command": { "action": "splitPane", "split": "vertical" } },
{ "keys": ["ctrl+e"], "command": { "action": "splitPane", "split": "horizontal" } },
{ "keys": ["ctrl+f"], "command": { "action": "splitPane", "split": "none" } },
{ "keys": ["ctrl+g"], "command": { "action": "splitPane" } },
{ "keys": ["ctrl+h"], "command": { "action": "splitPane", "split": "auto" } }
{ "keys": ["ctrl+h"], "command": { "action": "splitPane", "split": "auto" } },
{ "keys": ["ctrl+i"], "command": { "action": "splitPane", "split": "foo" } }
])" };
const auto bindings0Json = VerifyParseSucceeded(bindings0String);
@@ -333,7 +335,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(appKeyBindings);
VERIFY_ARE_EQUAL(0u, appKeyBindings->_keyShortcuts.size());
appKeyBindings->LayerJson(bindings0Json);
VERIFY_ARE_EQUAL(5u, appKeyBindings->_keyShortcuts.size());
VERIFY_ARE_EQUAL(7u, appKeyBindings->_keyShortcuts.size());
{
KeyChord kc{ true, false, false, static_cast<int32_t>('C') };
@@ -362,6 +364,15 @@ namespace TerminalAppLocalTests
// Verify the args have the expected value
VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Horizontal, realArgs.SplitStyle());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('F') };
auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('G') };
auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc);
@@ -380,6 +391,15 @@ namespace TerminalAppLocalTests
// Verify the args have the expected value
VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('I') };
auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
}
}
void KeyBindingsTests::TestSetTabColorArgs()
@@ -387,6 +407,7 @@ namespace TerminalAppLocalTests
const std::string bindings0String{ R"([
{ "keys": ["ctrl+c"], "command": { "action": "setTabColor", "color": null } },
{ "keys": ["ctrl+d"], "command": { "action": "setTabColor", "color": "#123456" } },
{ "keys": ["ctrl+e"], "command": { "action": "setTabColor", "color": "thisStringObviouslyWontWork" } },
{ "keys": ["ctrl+f"], "command": "setTabColor" },
])" };
@@ -396,7 +417,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(appKeyBindings);
VERIFY_ARE_EQUAL(0u, appKeyBindings->_keyShortcuts.size());
appKeyBindings->LayerJson(bindings0Json);
VERIFY_ARE_EQUAL(3u, appKeyBindings->_keyShortcuts.size());
VERIFY_ARE_EQUAL(4u, appKeyBindings->_keyShortcuts.size());
{
KeyChord kc{ true, false, false, static_cast<int32_t>('C') };
@@ -418,6 +439,15 @@ namespace TerminalAppLocalTests
// 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());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('E') };
auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SetTabColor, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SetTabColorArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_IS_NULL(realArgs.TabColor());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('F') };
auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc);

View File

@@ -76,8 +76,6 @@ namespace TerminalAppLocalTests
TEST_METHOD(ValidateKeybindingsWarnings);
TEST_METHOD(ValidateExecuteCommandlineWarning);
TEST_METHOD(ValidateLegacyGlobalsWarning);
TEST_METHOD(TestTrailingCommas);
@@ -1433,6 +1431,10 @@ namespace TerminalAppLocalTests
{
"name": "profile3",
"closeOnExit": null
},
{
"name": "profile4",
"closeOnExit": { "clearly": "not a string" }
}
]
})" };
@@ -1447,6 +1449,7 @@ namespace TerminalAppLocalTests
// Unknown modes parse as "Graceful"
VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings._profiles[3].GetCloseOnExitMode());
VERIFY_ARE_EQUAL(CloseOnExitMode::Graceful, settings._profiles[4].GetCloseOnExitMode());
}
void SettingsTests::TestCloseOnExitCompatibilityShim()
{
@@ -2256,57 +2259,6 @@ namespace TerminalAppLocalTests
VERIFY_ARE_EQUAL(::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.at(3));
}
void SettingsTests::ValidateExecuteCommandlineWarning()
{
Log::Comment(L"This test is affected by GH#6949, so we're just skipping it for now.");
Log::Result(WEX::Logging::TestResults::Skipped);
return;
// const std::string badSettings{ R"(
// {
// "defaultProfile": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
// "profiles": [
// {
// "name" : "profile0",
// "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}"
// },
// {
// "name" : "profile1",
// "guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}"
// }
// ],
// "keybindings": [
// { "name":null, "command": { "action": "wt" }, "keys": [ "ctrl+a" ] },
// { "name":null, "command": { "action": "wt", "commandline":"" }, "keys": [ "ctrl+b" ] },
// { "name":null, "command": { "action": "wt", "commandline":null }, "keys": [ "ctrl+c" ] }
// ]
// })" };
// const auto settingsObject = VerifyParseSucceeded(badSettings);
// auto settings = CascadiaSettings::FromJson(settingsObject);
// VERIFY_ARE_EQUAL(0u, settings->_globals._keybindings->_keyShortcuts.size());
// for (const auto& warning : settings->_globals._keybindingsWarnings)
// {
// Log::Comment(NoThrowString().Format(
// L"warning:%d", warning));
// }
// VERIFY_ARE_EQUAL(3u, settings->_globals._keybindingsWarnings.size());
// VERIFY_ARE_EQUAL(::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_globals._keybindingsWarnings.at(0));
// VERIFY_ARE_EQUAL(::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_globals._keybindingsWarnings.at(1));
// VERIFY_ARE_EQUAL(::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_globals._keybindingsWarnings.at(2));
// settings->_ValidateKeybindings();
// VERIFY_ARE_EQUAL(4u, settings->_warnings.size());
// VERIFY_ARE_EQUAL(::TerminalApp::SettingsLoadWarnings::AtLeastOneKeybindingWarning, settings->_warnings.at(0));
// VERIFY_ARE_EQUAL(::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.at(1));
// VERIFY_ARE_EQUAL(::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.at(2));
// VERIFY_ARE_EQUAL(::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.at(3));
}
void SettingsTests::ValidateLegacyGlobalsWarning()
{
const std::string badSettings{ R"(

View File

@@ -24,25 +24,6 @@ static constexpr bool _IsMouseMessage(UINT uMsg)
uMsg == WM_MOUSEMOVE || uMsg == WM_MOUSEWHEEL;
}
// Helper static function to ensure that all ambiguous-width glyphs are reported as narrow.
// See microsoft/terminal#2066 for more info.
static bool _IsGlyphWideForceNarrowFallback(const std::wstring_view /* glyph */) noexcept
{
return false; // glyph is not wide.
}
static bool _EnsureStaticInitialization()
{
// use C++11 magic statics to make sure we only do this once.
static bool initialized = []() {
// *** THIS IS A SINGLETON ***
SetGlyphWidthFallback(_IsGlyphWideForceNarrowFallback);
return true;
}();
return initialized;
}
LRESULT CALLBACK HwndTerminal::HwndTerminalWndProc(
HWND hwnd,
UINT uMsg,
@@ -91,7 +72,7 @@ try
{
const auto bufferData = terminal->_terminal->RetrieveSelectedTextFromBuffer(false);
LOG_IF_FAILED(terminal->_CopyTextToSystemClipboard(bufferData, true));
TerminalClearSelection(terminal);
terminal->_terminal->ClearSelection();
}
CATCH_LOG();
}
@@ -100,11 +81,6 @@ try
terminal->_PasteTextFromClipboard();
}
return 0;
case WM_DESTROY:
// Release Terminal's hwnd so Teardown doesn't try to destroy it again
terminal->_hwnd.release();
terminal->Teardown();
return 0;
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
@@ -138,16 +114,14 @@ static bool RegisterTermClass(HINSTANCE hInstance) noexcept
}
HwndTerminal::HwndTerminal(HWND parentHwnd) :
_desiredFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, { 0, 14 }, CP_UTF8 },
_actualFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, { 0, 14 }, CP_UTF8, false },
_desiredFont{ L"Consolas", 0, 10, { 0, 14 }, CP_UTF8 },
_actualFont{ L"Consolas", 0, 10, { 0, 14 }, CP_UTF8, false },
_uiaProvider{ nullptr },
_uiaProviderInitialized{ false },
_currentDpi{ USER_DEFAULT_SCREEN_DPI },
_pfnWriteCallback{ nullptr },
_multiClickTime{ 500 } // this will be overwritten by the windows system double-click time
{
_EnsureStaticInitialization();
HINSTANCE hInstance = wil::GetModuleInstanceHandle();
if (RegisterTermClass(hInstance))
@@ -174,11 +148,6 @@ HwndTerminal::HwndTerminal(HWND parentHwnd) :
}
}
HwndTerminal::~HwndTerminal()
{
Teardown();
}
HRESULT HwndTerminal::Initialize()
{
_terminal = std::make_unique<::Microsoft::Terminal::Core::Terminal>();
@@ -193,6 +162,9 @@ HRESULT HwndTerminal::Initialize()
RETURN_IF_FAILED(dxEngine->Enable());
_renderer->AddRenderEngine(dxEngine.get());
const auto pfn = std::bind(&::Microsoft::Console::Render::Renderer::IsGlyphWideByFont, _renderer.get(), std::placeholders::_1);
SetGlyphWidthFallback(pfn);
_UpdateFont(USER_DEFAULT_SCREEN_DPI);
RECT windowRect;
GetWindowRect(_hwnd.get(), &windowRect);
@@ -209,8 +181,8 @@ HRESULT HwndTerminal::Initialize()
_terminal->SetBackgroundCallback([](auto) {});
_terminal->Create(COORD{ 80, 25 }, 1000, *_renderer);
_terminal->SetDefaultBackground(RGB(12, 12, 12));
_terminal->SetDefaultForeground(RGB(204, 204, 204));
_terminal->SetDefaultBackground(RGB(5, 27, 80));
_terminal->SetDefaultForeground(RGB(255, 255, 255));
_terminal->SetWriteInputCallback([=](std::wstring & input) noexcept { _WriteTextToConnection(input); });
localPointerToThread->EnablePainting();
@@ -219,33 +191,6 @@ HRESULT HwndTerminal::Initialize()
return S_OK;
}
void HwndTerminal::Teardown() noexcept
try
{
// As a rule, detach resources from the Terminal before shutting them down.
// This ensures that teardown is reentrant.
// Shut down the renderer (and therefore the thread) before we implode
if (auto localRenderEngine{ std::exchange(_renderEngine, nullptr) })
{
if (auto localRenderer{ std::exchange(_renderer, nullptr) })
{
localRenderer->TriggerTeardown();
// renderer is destroyed
}
// renderEngine is destroyed
}
if (auto localHwnd{ _hwnd.release() })
{
// If we're being called through WM_DESTROY, we won't get here (hwnd is already released)
// If we're not, we may end up in Teardown _again_... but by the time we do, all other
// resources have been released and will not be released again.
DestroyWindow(localHwnd);
}
}
CATCH_LOG();
void HwndTerminal::RegisterScrollCallback(std::function<void(int, int, int)> callback)
{
_terminal->SetScrollPositionChangedCallback(callback);
@@ -522,21 +467,11 @@ try
}
CATCH_RETURN();
void HwndTerminal::_ClearSelection() noexcept
try
{
auto lock{ _terminal->LockForWriting() };
_terminal->ClearSelection();
_renderer->TriggerSelection();
}
CATCH_LOG();
void _stdcall TerminalClearSelection(void* terminal)
{
auto publicTerminal = static_cast<HwndTerminal*>(terminal);
publicTerminal->_ClearSelection();
const auto publicTerminal = static_cast<const HwndTerminal*>(terminal);
publicTerminal->_terminal->ClearSelection();
}
bool _stdcall TerminalIsSelectionActive(void* terminal)
{
const auto publicTerminal = static_cast<const HwndTerminal*>(terminal);
@@ -547,10 +482,9 @@ bool _stdcall TerminalIsSelectionActive(void* terminal)
// Returns the selected text in the terminal.
const wchar_t* _stdcall TerminalGetSelection(void* terminal)
{
auto publicTerminal = static_cast<HwndTerminal*>(terminal);
const auto publicTerminal = static_cast<const HwndTerminal*>(terminal);
const auto bufferData = publicTerminal->_terminal->RetrieveSelectedTextFromBuffer(false);
publicTerminal->_ClearSelection();
// convert text: vector<string> --> string
std::wstring selectedText;
@@ -560,6 +494,8 @@ const wchar_t* _stdcall TerminalGetSelection(void* terminal)
}
auto returnText = wil::make_cotaskmem_string_nothrow(selectedText.c_str());
TerminalClearSelection(terminal);
return returnText.release();
}
@@ -638,7 +574,7 @@ try
{
if (_terminal->IsSelectionActive())
{
_ClearSelection();
_terminal->ClearSelection();
if (ch == UNICODE_ESC)
{
// ESC should clear any selection before it triggers input.
@@ -696,7 +632,7 @@ void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR font
publicTerminal->_terminal->SetCursorStyle(theme.CursorStyle);
publicTerminal->_desiredFont = { fontFamily, 0, DEFAULT_FONT_WEIGHT, { 0, fontSize }, CP_UTF8 };
publicTerminal->_desiredFont = { fontFamily, 0, 10, { 0, fontSize }, CP_UTF8 };
publicTerminal->_UpdateFont(newDpi);
// When the font changes the terminal dimensions need to be recalculated since the available row and column

View File

@@ -51,10 +51,9 @@ public:
HwndTerminal(HwndTerminal&&) = default;
HwndTerminal& operator=(const HwndTerminal&) = default;
HwndTerminal& operator=(HwndTerminal&&) = default;
~HwndTerminal();
~HwndTerminal() = default;
HRESULT Initialize();
void Teardown() noexcept;
void SendOutput(std::wstring_view data);
HRESULT Refresh(const SIZE windowSize, _Out_ COORD* dimensions);
void RegisterScrollCallback(std::function<void(int, int, int)> callback);
@@ -113,8 +112,6 @@ private:
HRESULT _MoveSelection(LPARAM lParam) noexcept;
IRawElementProviderSimple* _GetUiaProvider() noexcept;
void _ClearSelection() noexcept;
bool _CanSendVTMouseInput() const noexcept;
bool _SendMouseEvent(UINT uMsg, WPARAM wParam, LPARAM lParam) noexcept;

View File

@@ -2,9 +2,6 @@
#include "ActionArgs.h"
#include "ActionAndArgs.h"
#include "ActionAndArgs.g.cpp"
#include "JsonUtils.h"
#include <LibraryResources.h>
static constexpr std::string_view CopyTextKey{ "copy" };
@@ -38,7 +35,6 @@ static constexpr std::string_view ToggleAlwaysOnTopKey{ "toggleAlwaysOnTop" };
static constexpr std::string_view SetTabColorKey{ "setTabColor" };
static constexpr std::string_view OpenTabColorPickerKey{ "openTabColorPicker" };
static constexpr std::string_view RenameTabKey{ "renameTab" };
static constexpr std::string_view ExecuteCommandlineKey{ "wt" };
static constexpr std::string_view ToggleCommandPaletteKey{ "commandPalette" };
static constexpr std::string_view ActionKey{ "action" };
@@ -48,8 +44,6 @@ static constexpr std::string_view UnboundKey{ "unbound" };
namespace winrt::TerminalApp::implementation
{
using namespace ::TerminalApp;
// Specifically use a map here over an unordered_map. We want to be able to
// iterate over these entries in-order when we're serializing the keybindings.
// HERE BE DRAGONS:
@@ -90,7 +84,6 @@ namespace winrt::TerminalApp::implementation
{ UnboundKey, ShortcutAction::Invalid },
{ FindKey, ShortcutAction::Find },
{ RenameTabKey, ShortcutAction::RenameTab },
{ ExecuteCommandlineKey, ShortcutAction::ExecuteCommandline },
{ ToggleCommandPaletteKey, ShortcutAction::ToggleCommandPalette },
};
@@ -123,8 +116,6 @@ namespace winrt::TerminalApp::implementation
{ ShortcutAction::RenameTab, winrt::TerminalApp::implementation::RenameTabArgs::FromJson },
{ ShortcutAction::ExecuteCommandline, winrt::TerminalApp::implementation::ExecuteCommandlineArgs::FromJson },
{ ShortcutAction::Invalid, nullptr },
};
@@ -192,9 +183,11 @@ namespace winrt::TerminalApp::implementation
}
else if (json.isObject())
{
if (const auto actionString{ JsonUtils::GetValueForKey<std::optional<std::string>>(json, ActionKey) })
const auto actionVal = json[JsonKey(ActionKey)];
if (actionVal.isString())
{
action = GetActionFromString(*actionString);
auto actionString = actionVal.asString();
action = GetActionFromString(actionString);
argsVal = json;
}
}
@@ -272,7 +265,6 @@ namespace winrt::TerminalApp::implementation
{ ShortcutAction::SetTabColor, RS_(L"ResetTabColorCommandKey") },
{ ShortcutAction::OpenTabColorPicker, RS_(L"OpenTabColorPickerCommandKey") },
{ ShortcutAction::RenameTab, RS_(L"ResetTabNameCommandKey") },
{ ShortcutAction::ExecuteCommandline, RS_(L"ExecuteCommandlineCommandKey") },
{ ShortcutAction::ToggleCommandPalette, RS_(L"ToggleCommandPaletteCommandKey") },
};
}();
@@ -289,4 +281,5 @@ namespace winrt::TerminalApp::implementation
const auto found = GeneratedActionNames.find(_Action);
return found != GeneratedActionNames.end() ? found->second : L"";
}
}

View File

@@ -17,7 +17,6 @@
#include "OpenSettingsArgs.g.cpp"
#include "SetTabColorArgs.g.cpp"
#include "RenameTabArgs.g.cpp"
#include "ExecuteCommandlineArgs.g.cpp"
#include <LibraryResources.h>
@@ -259,17 +258,4 @@ namespace winrt::TerminalApp::implementation
return RS_(L"ResetTabNameCommandKey");
}
winrt::hstring ExecuteCommandlineArgs::GenerateName() const
{
// "Run commandline "{_Commandline}" in this window"
if (!_Commandline.empty())
{
return winrt::hstring{
fmt::format(std::wstring_view(RS_(L"ExecuteCommandlineCommandKey")),
_Commandline.c_str())
};
}
return L"";
}
}

View File

@@ -17,15 +17,12 @@
#include "OpenSettingsArgs.g.h"
#include "SetTabColorArgs.g.h"
#include "RenameTabArgs.g.h"
#include "ExecuteCommandlineArgs.g.h"
#include "../../cascadia/inc/cppwinrt_utils.h"
#include "Utils.h"
#include "JsonUtils.h"
#include "TerminalWarnings.h"
#include "TerminalSettingsSerializationHelpers.h"
// Notes on defining ActionArgs and ActionEventArgs:
// * All properties specific to an action should be defined as an ActionArgs
// class that implements IActionArgs
@@ -34,7 +31,6 @@
namespace winrt::TerminalApp::implementation
{
using namespace ::TerminalApp;
using FromJsonResult = std::tuple<winrt::TerminalApp::IActionArgs, std::vector<::TerminalApp::SettingsLoadWarnings>>;
struct ActionEventArgs : public ActionEventArgsT<ActionEventArgs>
@@ -77,11 +73,26 @@ namespace winrt::TerminalApp::implementation
{
// LOAD BEARING: Not using make_self here _will_ break you in the future!
auto args = winrt::make_self<NewTerminalArgs>();
JsonUtils::GetValueForKey(json, CommandlineKey, args->_Commandline);
JsonUtils::GetValueForKey(json, StartingDirectoryKey, args->_StartingDirectory);
JsonUtils::GetValueForKey(json, TabTitleKey, args->_TabTitle);
JsonUtils::GetValueForKey(json, ProfileIndexKey, args->_ProfileIndex);
JsonUtils::GetValueForKey(json, ProfileKey, args->_Profile);
if (auto commandline{ json[JsonKey(CommandlineKey)] })
{
args->_Commandline = winrt::to_hstring(commandline.asString());
}
if (auto startingDirectory{ json[JsonKey(StartingDirectoryKey)] })
{
args->_StartingDirectory = winrt::to_hstring(startingDirectory.asString());
}
if (auto tabTitle{ json[JsonKey(TabTitleKey)] })
{
args->_TabTitle = winrt::to_hstring(tabTitle.asString());
}
if (auto index{ json[JsonKey(ProfileIndexKey)] })
{
args->_ProfileIndex = index.asInt();
}
if (auto profile{ json[JsonKey(ProfileKey)] })
{
args->_Profile = winrt::to_hstring(profile.asString());
}
return *args;
}
};
@@ -109,7 +120,10 @@ namespace winrt::TerminalApp::implementation
{
// LOAD BEARING: Not using make_self here _will_ break you in the future!
auto args = winrt::make_self<CopyTextArgs>();
JsonUtils::GetValueForKey(json, SingleLineKey, args->_SingleLine);
if (auto singleLine{ json[JsonKey(SingleLineKey)] })
{
args->_SingleLine = singleLine.asBool();
}
return { *args, {} };
}
};
@@ -163,11 +177,49 @@ namespace winrt::TerminalApp::implementation
{
// LOAD BEARING: Not using make_self here _will_ break you in the future!
auto args = winrt::make_self<SwitchToTabArgs>();
JsonUtils::GetValueForKey(json, TabIndexKey, args->_TabIndex);
if (auto tabIndex{ json[JsonKey(TabIndexKey)] })
{
args->_TabIndex = tabIndex.asUInt();
}
return { *args, {} };
}
};
// Possible Direction values
// TODO:GH#2550/#3475 - move these to a centralized deserializing place
static constexpr std::string_view LeftString{ "left" };
static constexpr std::string_view RightString{ "right" };
static constexpr std::string_view UpString{ "up" };
static constexpr std::string_view DownString{ "down" };
// Function Description:
// - Helper function for parsing a Direction from a string
// Arguments:
// - directionString: the string to attempt to parse
// Return Value:
// - The encoded Direction value, or Direction::None if it was an invalid string
static TerminalApp::Direction ParseDirection(const std::string& directionString)
{
if (directionString == LeftString)
{
return TerminalApp::Direction::Left;
}
else if (directionString == RightString)
{
return TerminalApp::Direction::Right;
}
else if (directionString == UpString)
{
return TerminalApp::Direction::Up;
}
else if (directionString == DownString)
{
return TerminalApp::Direction::Down;
}
// default behavior for invalid data
return TerminalApp::Direction::None;
};
struct ResizePaneArgs : public ResizePaneArgsT<ResizePaneArgs>
{
ResizePaneArgs() = default;
@@ -191,7 +243,10 @@ namespace winrt::TerminalApp::implementation
{
// LOAD BEARING: Not using make_self here _will_ break you in the future!
auto args = winrt::make_self<ResizePaneArgs>();
JsonUtils::GetValueForKey(json, DirectionKey, args->_Direction);
if (auto directionString{ json[JsonKey(DirectionKey)] })
{
args->_Direction = ParseDirection(directionString.asString());
}
if (args->_Direction == TerminalApp::Direction::None)
{
return { nullptr, { ::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter } };
@@ -226,7 +281,10 @@ namespace winrt::TerminalApp::implementation
{
// LOAD BEARING: Not using make_self here _will_ break you in the future!
auto args = winrt::make_self<MoveFocusArgs>();
JsonUtils::GetValueForKey(json, DirectionKey, args->_Direction);
if (auto directionString{ json[JsonKey(DirectionKey)] })
{
args->_Direction = ParseDirection(directionString.asString());
}
if (args->_Direction == TerminalApp::Direction::None)
{
return { nullptr, { ::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter } };
@@ -261,11 +319,48 @@ namespace winrt::TerminalApp::implementation
{
// LOAD BEARING: Not using make_self here _will_ break you in the future!
auto args = winrt::make_self<AdjustFontSizeArgs>();
JsonUtils::GetValueForKey(json, AdjustFontSizeDelta, args->_Delta);
if (auto jsonDelta{ json[JsonKey(AdjustFontSizeDelta)] })
{
args->_Delta = jsonDelta.asInt();
}
return { *args, {} };
}
};
// Possible SplitState values
// TODO:GH#2550/#3475 - move these to a centralized deserializing place
static constexpr std::string_view VerticalKey{ "vertical" };
static constexpr std::string_view HorizontalKey{ "horizontal" };
static constexpr std::string_view AutomaticKey{ "auto" };
static TerminalApp::SplitState ParseSplitState(const std::string& stateString)
{
if (stateString == VerticalKey)
{
return TerminalApp::SplitState::Vertical;
}
else if (stateString == HorizontalKey)
{
return TerminalApp::SplitState::Horizontal;
}
else if (stateString == AutomaticKey)
{
return TerminalApp::SplitState::Automatic;
}
// default behavior for invalid data
return TerminalApp::SplitState::Automatic;
};
// Possible SplitType values
static constexpr std::string_view DuplicateKey{ "duplicate" };
static TerminalApp::SplitType ParseSplitModeState(const std::string& stateString)
{
if (stateString == DuplicateKey)
{
return TerminalApp::SplitType::Duplicate;
}
return TerminalApp::SplitType::Manual;
}
struct SplitPaneArgs : public SplitPaneArgsT<SplitPaneArgs>
{
SplitPaneArgs() = default;
@@ -296,12 +391,48 @@ namespace winrt::TerminalApp::implementation
// LOAD BEARING: Not using make_self here _will_ break you in the future!
auto args = winrt::make_self<SplitPaneArgs>();
args->_TerminalArgs = NewTerminalArgs::FromJson(json);
JsonUtils::GetValueForKey(json, SplitKey, args->_SplitStyle);
JsonUtils::GetValueForKey(json, SplitModeKey, args->_SplitMode);
if (auto jsonStyle{ json[JsonKey(SplitKey)] })
{
args->_SplitStyle = ParseSplitState(jsonStyle.asString());
}
if (auto jsonStyle{ json[JsonKey(SplitModeKey)] })
{
args->_SplitMode = ParseSplitModeState(jsonStyle.asString());
}
return { *args, {} };
}
};
// Possible SettingsTarget values
// TODO:GH#2550/#3475 - move these to a centralized deserializing place
static constexpr std::string_view SettingsFileString{ "settingsFile" };
static constexpr std::string_view DefaultsFileString{ "defaultsFile" };
static constexpr std::string_view AllFilesString{ "allFiles" };
// Function Description:
// - Helper function for parsing a SettingsTarget from a string
// Arguments:
// - targetString: the string to attempt to parse
// Return Value:
// - The encoded SettingsTarget value, or SettingsTarget::SettingsFile if it was an invalid string
static TerminalApp::SettingsTarget ParseSettingsTarget(const std::string& targetString)
{
if (targetString == SettingsFileString)
{
return TerminalApp::SettingsTarget::SettingsFile;
}
else if (targetString == DefaultsFileString)
{
return TerminalApp::SettingsTarget::DefaultsFile;
}
else if (targetString == AllFilesString)
{
return TerminalApp::SettingsTarget::AllFiles;
}
// default behavior for invalid data
return TerminalApp::SettingsTarget::SettingsFile;
};
struct OpenSettingsArgs : public OpenSettingsArgsT<OpenSettingsArgs>
{
OpenSettingsArgs() = default;
@@ -325,7 +456,10 @@ namespace winrt::TerminalApp::implementation
{
// LOAD BEARING: Not using make_self here _will_ break you in the future!
auto args = winrt::make_self<OpenSettingsArgs>();
JsonUtils::GetValueForKey(json, TargetKey, args->_Target);
if (auto targetString{ json[JsonKey(TargetKey)] })
{
args->_Target = ParseSettingsTarget(targetString.asString());
}
return { *args, {} };
}
};
@@ -353,10 +487,16 @@ namespace winrt::TerminalApp::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) })
std::optional<til::color> temp;
try
{
args->_TabColor = static_cast<uint32_t>(*temp);
::TerminalApp::JsonUtils::GetOptionalColor(json, ColorKey, temp);
if (temp.has_value())
{
args->_TabColor = static_cast<uint32_t>(temp.value());
}
}
CATCH_LOG();
return { *args, {} };
}
};
@@ -384,43 +524,13 @@ namespace winrt::TerminalApp::implementation
{
// LOAD BEARING: Not using make_self here _will_ break you in the future!
auto args = winrt::make_self<RenameTabArgs>();
JsonUtils::GetValueForKey(json, TitleKey, args->_Title);
return { *args, {} };
}
};
struct ExecuteCommandlineArgs : public ExecuteCommandlineArgsT<ExecuteCommandlineArgs>
{
ExecuteCommandlineArgs() = default;
GETSET_PROPERTY(winrt::hstring, Commandline, L"");
static constexpr std::string_view CommandlineKey{ "commandline" };
public:
hstring GenerateName() const;
bool Equals(const IActionArgs& other)
{
auto otherAsUs = other.try_as<ExecuteCommandlineArgs>();
if (otherAsUs)
if (auto title{ json[JsonKey(TitleKey)] })
{
return otherAsUs->_Commandline == _Commandline;
}
return false;
};
static FromJsonResult FromJson(const Json::Value& json)
{
// LOAD BEARING: Not using make_self here _will_ break you in the future!
auto args = winrt::make_self<ExecuteCommandlineArgs>();
JsonUtils::GetValueForKey(json, CommandlineKey, args->_Commandline);
if (args->_Commandline.empty())
{
return { nullptr, { ::TerminalApp::SettingsLoadWarnings::MissingRequiredParameter } };
args->_Title = winrt::to_hstring(title.asString());
}
return { *args, {} };
}
};
}
namespace winrt::TerminalApp::factory_implementation

View File

@@ -115,9 +115,4 @@ namespace TerminalApp
{
String Title { get; };
};
[default_interface] runtimeclass ExecuteCommandlineArgs : IActionArgs
{
String Commandline;
};
}

View File

@@ -11,7 +11,6 @@ using namespace winrt::Windows::ApplicationModel::DataTransfer;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Text;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::System;
using namespace winrt::Microsoft::Terminal;
using namespace winrt::Microsoft::Terminal::Settings;
@@ -335,20 +334,4 @@ namespace winrt::TerminalApp::implementation
}
args.Handled(true);
}
void TerminalPage::_HandleExecuteCommandline(const IInspectable& /*sender*/,
const TerminalApp::ActionEventArgs& actionArgs)
{
if (const auto& realArgs = actionArgs.ActionArgs().try_as<TerminalApp::ExecuteCommandlineArgs>())
{
auto actions = winrt::single_threaded_vector<winrt::TerminalApp::ActionAndArgs>(std::move(
TerminalPage::ConvertExecuteCommandlineToActions(realArgs)));
if (_startupActions.Size() != 0)
{
actionArgs.Handled(true);
_ProcessStartupActions(actions, false);
}
}
}
}

View File

@@ -599,7 +599,7 @@ void AppCommandlineArgs::_addCommandsForArg(std::vector<Commandline>& commands,
// - <none>
// Return Value:
// - the deque of actions we've buffered as a result of parsing commands.
std::vector<winrt::TerminalApp::ActionAndArgs>& AppCommandlineArgs::GetStartupActions()
std::deque<winrt::TerminalApp::ActionAndArgs>& AppCommandlineArgs::GetStartupActions()
{
return _startupActions;
}
@@ -658,8 +658,7 @@ void AppCommandlineArgs::ValidateStartupCommands()
auto newTerminalArgs = winrt::make_self<implementation::NewTerminalArgs>();
args->TerminalArgs(*newTerminalArgs);
newTabAction->Args(*args);
// push the arg onto the front
_startupActions.insert(_startupActions.begin(), 1, *newTabAction);
_startupActions.push_front(*newTabAction);
}
}
@@ -667,52 +666,3 @@ std::optional<winrt::TerminalApp::LaunchMode> AppCommandlineArgs::GetLaunchMode(
{
return _launchMode;
}
// Method Description:
// - Attempts to parse an array of commandline args into a list of
// commands to execute, and then parses these commands. As commands are
// successfully parsed, they will generate ShortcutActions for us to be
// able to execute. If we fail to parse any commands, we'll return the
// error code from the failure to parse that command, and stop processing
// additional commands.
// - The first arg in args should be the program name "wt" (or some variant). It
// will be ignored during parsing.
// Arguments:
// - args: an array of strings to process as a commandline. These args can contain spaces
// Return Value:
// - 0 if the commandline was successfully parsed
int AppCommandlineArgs::ParseArgs(winrt::array_view<const winrt::hstring>& args)
{
auto commands = ::TerminalApp::AppCommandlineArgs::BuildCommands(args);
for (auto& cmdBlob : commands)
{
// On one hand, it seems like we should be able to have one
// AppCommandlineArgs for parsing all of them, and collect the
// results one at a time.
//
// On the other hand, re-using a CLI::App seems to leave state from
// previous parsings around, so we could get mysterious behavior
// where one command affects the values of the next.
//
// From https://cliutils.github.io/CLI11/book/chapters/options.html:
// > If that option is not given, CLI11 will not touch the initial
// > value. This allows you to set up defaults by simply setting
// > your value beforehand.
//
// So we pretty much need the to either manually reset the state
// each command, or build new ones.
const auto result = ParseCommand(cmdBlob);
// If this succeeded, result will be 0. Otherwise, the caller should
// exit(result), to exit the program.
if (result != 0)
{
return result;
}
}
// If all the args were successfully parsed, we'll have some commands
// built in _appArgs, which we'll use when the application starts up.
return 0;
}

View File

@@ -28,15 +28,13 @@ public:
AppCommandlineArgs();
~AppCommandlineArgs() = default;
int ParseCommand(const Commandline& command);
int ParseArgs(winrt::array_view<const winrt::hstring>& args);
static std::vector<Commandline> BuildCommands(const std::vector<const wchar_t*>& args);
static std::vector<Commandline> BuildCommands(winrt::array_view<const winrt::hstring>& args);
void ValidateStartupCommands();
std::vector<winrt::TerminalApp::ActionAndArgs>& GetStartupActions();
std::deque<winrt::TerminalApp::ActionAndArgs>& GetStartupActions();
const std::string& GetExitMessage();
bool ShouldExitEarly() const noexcept;
@@ -92,7 +90,7 @@ private:
std::optional<winrt::TerminalApp::LaunchMode> _launchMode{ std::nullopt };
// Are you adding more args here? Make sure to reset them in _resetStateToDefault
std::vector<winrt::TerminalApp::ActionAndArgs> _startupActions;
std::deque<winrt::TerminalApp::ActionAndArgs> _startupActions;
std::string _exitMessage;
bool _shouldExitEarly{ false };

View File

@@ -256,7 +256,7 @@ namespace winrt::TerminalApp::implementation
});
_root->Create();
_ApplyTheme(_settings->GlobalSettings().Theme()->ApplicationTheme());
_ApplyTheme(_settings->GlobalSettings().Theme());
_ApplyStartupTaskStateChange();
TraceLoggingWrite(
@@ -310,7 +310,7 @@ namespace winrt::TerminalApp::implementation
// details here, but it does have the desired effect.
// It's not enough to set the theme on the dialog alone.
auto themingLambda{ [this](const Windows::Foundation::IInspectable& sender, const RoutedEventArgs&) {
auto theme{ _settings->GlobalSettings().Theme()->ApplicationTheme() };
auto theme{ _settings->GlobalSettings().Theme() };
auto element{ sender.try_as<winrt::Windows::UI::Xaml::FrameworkElement>() };
while (element)
{
@@ -474,7 +474,7 @@ namespace winrt::TerminalApp::implementation
// - <none>
// Return Value:
// - a point containing the requested dimensions in pixels.
winrt::Windows::Foundation::Size AppLogic::GetLaunchDimensions(uint32_t dpi)
winrt::Windows::Foundation::Point AppLogic::GetLaunchDimensions(uint32_t dpi)
{
if (!_loadedInitialSettings)
{
@@ -504,7 +504,7 @@ namespace winrt::TerminalApp::implementation
// of the height calculation here.
auto titlebar = TitlebarControl{ static_cast<uint64_t>(0) };
titlebar.Measure({ SHRT_MAX, SHRT_MAX });
proposedSize.Height += (titlebar.DesiredSize().Height) * scale;
proposedSize.Y += (titlebar.DesiredSize().Height) * scale;
}
else if (_settings->GlobalSettings().AlwaysShowTabs())
{
@@ -519,7 +519,7 @@ namespace winrt::TerminalApp::implementation
// For whatever reason, there's about 6px of unaccounted-for space
// in the application. I couldn't tell you where these 6px are
// coming from, but they need to be included in this math.
proposedSize.Width += (tabControl.DesiredSize().Height + 6) * scale;
proposedSize.Y += (tabControl.DesiredSize().Height + 6) * scale;
}
return proposedSize;
@@ -586,7 +586,7 @@ namespace winrt::TerminalApp::implementation
LoadSettings();
}
return _settings->GlobalSettings().Theme()->ApplicationTheme();
return _settings->GlobalSettings().Theme();
}
bool AppLogic::GetShowTabsInTitlebar()
@@ -767,7 +767,7 @@ namespace winrt::TerminalApp::implementation
co_await winrt::resume_foreground(_root->Dispatcher());
// Refresh the UI theme
_ApplyTheme(_settings->GlobalSettings().Theme()->ApplicationTheme());
_ApplyTheme(_settings->GlobalSettings().Theme());
}
fire_and_forget AppLogic::_ApplyStartupTaskStateChange()
@@ -974,7 +974,7 @@ namespace winrt::TerminalApp::implementation
// or 0. (see AppLogic::_ParseArgs)
int32_t AppLogic::SetStartupCommandline(array_view<const winrt::hstring> args)
{
const auto result = _appArgs.ParseArgs(args);
const auto result = _ParseArgs(args);
if (result == 0)
{
_appArgs.ValidateStartupCommands();
@@ -984,6 +984,53 @@ namespace winrt::TerminalApp::implementation
return result;
}
// Method Description:
// - Attempts to parse an array of commandline args into a list of
// commands to execute, and then parses these commands. As commands are
// successfully parsed, they will generate ShortcutActions for us to be
// able to execute. If we fail to parse any commands, we'll return the
// error code from the failure to parse that command, and stop processing
// additional commands.
// Arguments:
// - args: an array of strings to process as a commandline. These args can contain spaces
// Return Value:
// - 0 if the commandline was successfully parsed
int AppLogic::_ParseArgs(winrt::array_view<const hstring>& args)
{
auto commands = ::TerminalApp::AppCommandlineArgs::BuildCommands(args);
for (auto& cmdBlob : commands)
{
// On one hand, it seems like we should be able to have one
// AppCommandlineArgs for parsing all of them, and collect the
// results one at a time.
//
// On the other hand, re-using a CLI::App seems to leave state from
// previous parsings around, so we could get mysterious behavior
// where one command affects the values of the next.
//
// From https://cliutils.github.io/CLI11/book/chapters/options.html:
// > If that option is not given, CLI11 will not touch the initial
// > value. This allows you to set up defaults by simply setting
// > your value beforehand.
//
// So we pretty much need the to either manually reset the state
// each command, or build new ones.
const auto result = _appArgs.ParseCommand(cmdBlob);
// If this succeeded, result will be 0. Otherwise, the caller should
// exit(result), to exit the program.
if (result != 0)
{
return result;
}
}
// If all the args were successfully parsed, we'll have some commands
// built in _appArgs, which we'll use when the application starts up.
return 0;
}
// Method Description:
// - If there were any errors parsing the commandline that was used to
// initialize the terminal, this will return a string containing that
@@ -1089,11 +1136,6 @@ namespace winrt::TerminalApp::implementation
return _root ? _root->AlwaysOnTop() : false;
}
Windows::UI::Color AppLogic::TitlebarColor()
{
return _root->TitlebarColor();
}
// -------------------------------- WinRT Events ---------------------------------
// Winrt events need a method for adding a callback to the event and removing the callback.
// These macros will define them both for you.

View File

@@ -37,9 +37,7 @@ namespace winrt::TerminalApp::implementation
bool Fullscreen() const;
bool AlwaysOnTop() const;
Windows::UI::Color TitlebarColor();
Windows::Foundation::Size GetLaunchDimensions(uint32_t dpi);
Windows::Foundation::Point GetLaunchDimensions(uint32_t dpi);
winrt::Windows::Foundation::Point GetLaunchInitialPositions(int32_t defaultInitialX, int32_t defaultInitialY);
winrt::Windows::UI::Xaml::ElementTheme GetRequestedTheme();
LaunchMode GetLaunchMode();
@@ -112,7 +110,6 @@ namespace winrt::TerminalApp::implementation
FORWARDED_TYPED_EVENT(FocusModeChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, FocusModeChanged);
FORWARDED_TYPED_EVENT(FullscreenChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, FullscreenChanged);
FORWARDED_TYPED_EVENT(AlwaysOnTopChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, AlwaysOnTopChanged);
FORWARDED_TYPED_EVENT(TitlebarColorChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::RoutedEventArgs, _root, TitlebarColorChanged);
};
}

View File

@@ -45,10 +45,7 @@ namespace TerminalApp
Boolean Fullscreen { get; };
Boolean AlwaysOnTop { get; };
Windows.UI.Color TitlebarColor { get; };
Windows.Foundation.Size GetLaunchDimensions(UInt32 dpi);
Windows.Foundation.Point GetLaunchDimensions(UInt32 dpi);
Windows.Foundation.Point GetLaunchInitialPositions(Int32 defaultInitialX, Int32 defaultInitialY);
Windows.UI.Xaml.ElementTheme GetRequestedTheme();
LaunchMode GetLaunchMode();
@@ -68,7 +65,5 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> FocusModeChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> FullscreenChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> AlwaysOnTopChanged;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.RoutedEventArgs> TitlebarColorChanged;
}
}

View File

@@ -93,7 +93,7 @@ const Profile* CascadiaSettings::FindProfile(GUID profileGuid) const noexcept
// - <none>
// Return Value:
// - an iterable collection of all of our Profiles.
gsl::span<const Profile> CascadiaSettings::GetProfiles() const noexcept
std::basic_string_view<Profile> CascadiaSettings::GetProfiles() const noexcept
{
return { &_profiles[0], _profiles.size() };
}

View File

@@ -59,7 +59,7 @@ public:
GlobalAppSettings& GlobalSettings();
gsl::span<const Profile> GetProfiles() const noexcept;
std::basic_string_view<Profile> GetProfiles() const noexcept;
winrt::TerminalApp::AppKeyBindings GetKeybindings() const noexcept;
@@ -89,9 +89,7 @@ private:
void _LayerOrCreateProfile(const Json::Value& profileJson);
Profile* _FindMatchingProfile(const Json::Value& profileJson);
void _LayerOrCreateColorScheme(const Json::Value& schemeJson);
void _LayerOrCreateTheme(const Json::Value& themeJson);
ColorScheme* _FindMatchingColorScheme(const Json::Value& schemeJson);
Theme* _FindMatchingTheme(const Json::Value& themeJson);
void _ParseJsonString(std::string_view fileData, const bool isDefaultSettings);
static const Json::Value& _GetProfilesJsonObject(const Json::Value& json);
static const Json::Value& _GetDisabledProfileSourcesJsonObject(const Json::Value& json);

View File

@@ -35,7 +35,6 @@ static constexpr std::string_view DefaultSettingsKey{ "defaults" };
static constexpr std::string_view ProfilesListKey{ "list" };
static constexpr std::string_view KeybindingsKey{ "keybindings" };
static constexpr std::string_view SchemesKey{ "schemes" };
static constexpr std::string_view ThemesKey{ "themes" };
static constexpr std::string_view DisabledProfileSourcesKey{ "disabledProfileSources" };
@@ -250,9 +249,9 @@ void CascadiaSettings::_LoadDynamicProfiles()
const auto disabledProfileSources = CascadiaSettings::_GetDisabledProfileSourcesJsonObject(_userSettings);
if (disabledProfileSources.isArray())
{
for (const auto& json : disabledProfileSources)
for (const auto& ns : disabledProfileSources)
{
ignoredNamespaces.emplace(JsonUtils::GetValue<std::wstring>(json));
ignoredNamespaces.emplace(GetWstringFromJson(ns));
}
}
@@ -518,17 +517,6 @@ void CascadiaSettings::LayerJson(const Json::Value& json)
}
}
if (auto themes{ json[ThemesKey.data()] })
{
for (auto themeJson : themes)
{
if (themeJson.isObject())
{
_LayerOrCreateTheme(themeJson);
}
}
}
for (auto profileJson : _GetProfilesJsonObject(json))
{
if (profileJson.isObject())
@@ -670,20 +658,6 @@ void CascadiaSettings::_LayerOrCreateColorScheme(const Json::Value& schemeJson)
}
}
void CascadiaSettings::_LayerOrCreateTheme(const Json::Value& themeJson)
{
// Layer the json on top of an existing profile, if we have one:
auto pTheme = _FindMatchingTheme(themeJson);
if (pTheme)
{
pTheme->LayerJson(themeJson);
}
else
{
_globals.AddTheme(Theme::FromJson(themeJson));
}
}
// Method Description:
// - Finds a color scheme from our list of color schemes that matches the given
// json object. Uses ColorScheme::GetNameFromJson to find the name and then
@@ -713,25 +687,6 @@ ColorScheme* CascadiaSettings::_FindMatchingColorScheme(const Json::Value& schem
return nullptr;
}
Theme* CascadiaSettings::_FindMatchingTheme(const Json::Value& themeJson)
{
if (auto nameOpt = Theme::GetNameFromJson(themeJson))
{
winrt::hstring name {nameOpt.value()};
auto& themes = _globals.GetThemes();
auto iterator = themes.find(name);
if (iterator != themes.end())
{
// HERE BE DRAGONS: Returning a pointer to a type in the vector is
// maybe not the _safest_ thing, but we have a mind to make Profile
// and ColorScheme winrt types in the future, so this will be safer
// then.
return &iterator->second;
}
}
return nullptr;
}
// Function Description:
// - Returns true if we're running in a packaged context.
// If we are, we want to change our settings path slightly.

View File

@@ -105,9 +105,9 @@ ColorScheme ColorScheme::FromJson(const Json::Value& json)
// - 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))
if (const auto name{ json[JsonKey(NameKey)] })
{
const auto nameFromJson = GetWstringFromJson(name);
return nameFromJson == _schemeName;
}
return false;
@@ -125,16 +125,39 @@ bool ColorScheme::ShouldBeLayered(const Json::Value& json) const
// <none>
void ColorScheme::LayerJson(const Json::Value& json)
{
JsonUtils::GetValueForKey(json, NameKey, _schemeName);
JsonUtils::GetValueForKey(json, ForegroundKey, _defaultForeground);
JsonUtils::GetValueForKey(json, BackgroundKey, _defaultBackground);
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _selectionBackground);
JsonUtils::GetValueForKey(json, CursorColorKey, _cursorColor);
if (auto name{ json[JsonKey(NameKey)] })
{
_schemeName = winrt::to_hstring(name.asString());
}
if (auto fgString{ json[JsonKey(ForegroundKey)] })
{
const auto color = Utils::ColorFromHexString(fgString.asString());
_defaultForeground = color;
}
if (auto bgString{ json[JsonKey(BackgroundKey)] })
{
const auto color = Utils::ColorFromHexString(bgString.asString());
_defaultBackground = color;
}
if (auto sbString{ json[JsonKey(SelectionBackgroundKey)] })
{
const auto color = Utils::ColorFromHexString(sbString.asString());
_selectionBackground = color;
}
if (auto sbString{ json[JsonKey(CursorColorKey)] })
{
const auto color = Utils::ColorFromHexString(sbString.asString());
_cursorColor = color;
}
int i = 0;
for (const auto& current : TableColors)
{
JsonUtils::GetValueForKey(json, current, _table.at(i));
if (auto str{ json[JsonKey(current)] })
{
const auto color = Utils::ColorFromHexString(str.asString());
_table.at(i) = color;
}
i++;
}
}
@@ -177,7 +200,11 @@ til::color ColorScheme::GetCursorColor() const noexcept
// - 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)
std::optional<std::wstring> TerminalApp::ColorScheme::GetNameFromJson(const Json::Value& json)
{
return JsonUtils::GetValueForKey<std::optional<std::wstring>>(json, NameKey);
if (const auto name{ json[JsonKey(NameKey)] })
{
return GetWstringFromJson(name);
}
return std::nullopt;
}

View File

@@ -7,12 +7,10 @@
#include "Utils.h"
#include "ActionAndArgs.h"
#include "JsonUtils.h"
#include <LibraryResources.h>
using namespace winrt::Microsoft::Terminal::Settings;
using namespace winrt::TerminalApp;
using namespace ::TerminalApp;
static constexpr std::string_view NameKey{ "name" };
static constexpr std::string_view IconPathKey{ "iconPath" };
@@ -37,17 +35,25 @@ namespace winrt::TerminalApp::implementation
{
if (name.isObject())
{
if (const auto resourceKey{ JsonUtils::GetValueForKey<std::optional<std::wstring>>(name, "key") })
try
{
if (HasLibraryResourceWithName(*resourceKey))
if (const auto keyJson{ name[JsonKey("key")] })
{
return GetLibraryResourceString(*resourceKey);
// Make sure the key is present before we try
// loading it. Otherwise we'll crash
const auto resourceKey = GetWstringFromJson(keyJson);
if (HasLibraryResourceWithName(resourceKey))
{
return GetLibraryResourceString(resourceKey);
}
}
}
CATCH_LOG();
}
else if (name.isString())
{
return JsonUtils::GetValue<winrt::hstring>(name);
auto nameStr = name.asString();
return winrt::to_hstring(nameStr);
}
}

View File

@@ -271,17 +271,16 @@ namespace winrt::TerminalApp::implementation
};
// Method Description:
// - Produce a list of filtered actions to reflect the current contents of
// - Update our list of filtered actions to reflect the current contents of
// the input box. For more details on which commands will be displayed,
// see `_getWeight`.
// Arguments:
// - A collection that will receive the filtered actions
// - <none>
// Return Value:
// - <none>
std::vector<winrt::TerminalApp::Command> CommandPalette::_collectFilteredActions()
void CommandPalette::_updateFilteredActions()
{
std::vector<winrt::TerminalApp::Command> actions;
_filteredActions.Clear();
auto searchText = _searchBox().Text();
const bool addAll = searchText.empty();
@@ -304,10 +303,10 @@ namespace winrt::TerminalApp::implementation
for (auto action : sortedCommands)
{
actions.push_back(action);
_filteredActions.Append(action);
}
return actions;
return;
}
// Here, there was some filter text.
@@ -344,56 +343,7 @@ namespace winrt::TerminalApp::implementation
{
auto top = heap.top();
heap.pop();
actions.push_back(top.command);
}
return actions;
}
// Method Description:
// - Update our list of filtered actions to reflect the current contents of
// the input box. For more details on which commands will be displayed,
// see `_getWeight`.
// Arguments:
// - <none>
// Return Value:
// - <none>
void CommandPalette::_updateFilteredActions()
{
auto actions = _collectFilteredActions();
// Make _filteredActions look identical to actions, using only Insert and Remove.
// This allows WinUI to nicely animate the ListView as it changes.
for (uint32_t i = 0; i < _filteredActions.Size() && i < actions.size(); i++)
{
for (uint32_t j = i; j < _filteredActions.Size(); j++)
{
if (_filteredActions.GetAt(j) == actions[i])
{
for (uint32_t k = i; k < j; k++)
{
_filteredActions.RemoveAt(i);
}
break;
}
}
if (_filteredActions.GetAt(i) != actions[i])
{
_filteredActions.InsertAt(i, actions[i]);
}
}
// Remove any extra trailing items from the destination
while (_filteredActions.Size() > actions.size())
{
_filteredActions.RemoveAtEnd();
}
// Add any extra trailing items from the source
while (_filteredActions.Size() < actions.size())
{
_filteredActions.Append(actions[_filteredActions.Size()]);
_filteredActions.Append(top.command);
}
}

View File

@@ -37,7 +37,6 @@ namespace winrt::TerminalApp::implementation
void _selectNextItem(const bool moveDown);
void _updateFilteredActions();
std::vector<winrt::TerminalApp::Command> _collectFilteredActions();
static int _getWeight(const winrt::hstring& searchText, const winrt::hstring& name);
void _close();

View File

@@ -195,10 +195,9 @@ the MIT License. See LICENSE in the project root for license information. -->
<Grid HorizontalAlignment="Stretch" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16"/> <!-- icon -->
<ColumnDefinition Width="Auto"/> <!-- command label -->
<ColumnDefinition Width="*"/> <!-- key chord -->
<ColumnDefinition Width="16"/> <!-- gutter for scrollbar -->
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- TODO GH#6644: Add Icon to command palette entries, in column 0 -->

View File

@@ -7,11 +7,11 @@
#include "../../inc/DefaultSettings.h"
#include "Utils.h"
#include "JsonUtils.h"
#include "TerminalSettingsSerializationHelpers.h"
using namespace TerminalApp;
using namespace winrt::Microsoft::Terminal::Settings;
using namespace winrt::TerminalApp;
using namespace winrt::Windows::Data::Json;
using namespace winrt::Windows::UI::Xaml;
using namespace ::Microsoft::Console;
using namespace winrt::Microsoft::UI::Xaml::Controls;
@@ -44,6 +44,21 @@ static constexpr std::string_view ForceFullRepaintRenderingKey{ "experimental.re
static constexpr std::string_view SoftwareRenderingKey{ "experimental.rendering.software" };
static constexpr std::string_view ForceVTInputKey{ "experimental.input.forceVT" };
// Launch mode values
static constexpr std::wstring_view DefaultLaunchModeValue{ L"default" };
static constexpr std::wstring_view MaximizedLaunchModeValue{ L"maximized" };
static constexpr std::wstring_view FullscreenLaunchModeValue{ L"fullscreen" };
// Tab Width Mode values
static constexpr std::wstring_view EqualTabWidthModeValue{ L"equal" };
static constexpr std::wstring_view TitleLengthTabWidthModeValue{ L"titleLength" };
static constexpr std::wstring_view TitleLengthCompactModeValue{ L"compact" };
// Theme values
static constexpr std::wstring_view LightThemeValue{ L"light" };
static constexpr std::wstring_view DarkThemeValue{ L"dark" };
static constexpr std::wstring_view SystemThemeValue{ L"system" };
#ifdef _DEBUG
static constexpr bool debugFeaturesDefault{ true };
#else
@@ -77,16 +92,6 @@ const std::unordered_map<std::wstring, ColorScheme>& GlobalAppSettings::GetColor
return _colorSchemes;
}
std::unordered_map<winrt::hstring, ::TerminalApp::Theme>& GlobalAppSettings::GetThemes() noexcept
{
return _themes;
}
const std::unordered_map<winrt::hstring, ::TerminalApp::Theme>& GlobalAppSettings::GetThemes() const noexcept
{
return _themes;
}
void GlobalAppSettings::DefaultProfile(const GUID defaultProfile) noexcept
{
_unparsedDefaultProfile.reset();
@@ -144,51 +149,66 @@ GlobalAppSettings GlobalAppSettings::FromJson(const Json::Value& json)
void GlobalAppSettings::LayerJson(const Json::Value& json)
{
JsonUtils::GetValueForKey(json, DefaultProfileKey, _unparsedDefaultProfile);
if (auto defaultProfile{ json[JsonKey(DefaultProfileKey)] })
{
_unparsedDefaultProfile.emplace(GetWstringFromJson(defaultProfile));
}
JsonUtils::GetValueForKey(json, AlwaysShowTabsKey, _AlwaysShowTabs);
JsonUtils::GetBool(json, AlwaysShowTabsKey, _AlwaysShowTabs);
JsonUtils::GetValueForKey(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs);
JsonUtils::GetBool(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs);
JsonUtils::GetValueForKey(json, InitialRowsKey, _InitialRows);
JsonUtils::GetInt(json, InitialRowsKey, _InitialRows);
JsonUtils::GetValueForKey(json, InitialColsKey, _InitialCols);
JsonUtils::GetInt(json, InitialColsKey, _InitialCols);
JsonUtils::GetValueForKey(json, InitialPositionKey, _InitialPosition);
if (auto initialPosition{ json[JsonKey(InitialPositionKey)] })
{
_ParseInitialPosition(initialPosition.asString(), _InitialPosition);
}
JsonUtils::GetValueForKey(json, ShowTitleInTitlebarKey, _ShowTitleInTitlebar);
JsonUtils::GetBool(json, ShowTitleInTitlebarKey, _ShowTitleInTitlebar);
JsonUtils::GetValueForKey(json, ShowTabsInTitlebarKey, _ShowTabsInTitlebar);
JsonUtils::GetBool(json, ShowTabsInTitlebarKey, _ShowTabsInTitlebar);
JsonUtils::GetValueForKey(json, WordDelimitersKey, _WordDelimiters);
JsonUtils::GetWstring(json, WordDelimitersKey, _WordDelimiters);
JsonUtils::GetValueForKey(json, CopyOnSelectKey, _CopyOnSelect);
JsonUtils::GetBool(json, CopyOnSelectKey, _CopyOnSelect);
JsonUtils::GetValueForKey(json, CopyFormattingKey, _CopyFormatting);
JsonUtils::GetBool(json, CopyFormattingKey, _CopyFormatting);
JsonUtils::GetValueForKey(json, WarnAboutLargePasteKey, _WarnAboutLargePaste);
JsonUtils::GetBool(json, WarnAboutLargePasteKey, _WarnAboutLargePaste);
JsonUtils::GetValueForKey(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste);
JsonUtils::GetBool(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste);
JsonUtils::GetValueForKey(json, LaunchModeKey, _LaunchMode);
if (auto launchMode{ json[JsonKey(LaunchModeKey)] })
{
_LaunchMode = _ParseLaunchMode(GetWstringFromJson(launchMode));
}
JsonUtils::GetValueForKey(json, ThemeKey, _ThemeName);
if (auto theme{ json[JsonKey(ThemeKey)] })
{
_Theme = _ParseTheme(GetWstringFromJson(theme));
}
JsonUtils::GetValueForKey(json, TabWidthModeKey, _TabWidthMode);
if (auto tabWidthMode{ json[JsonKey(TabWidthModeKey)] })
{
_TabWidthMode = _ParseTabWidthMode(GetWstringFromJson(tabWidthMode));
}
JsonUtils::GetValueForKey(json, SnapToGridOnResizeKey, _SnapToGridOnResize);
JsonUtils::GetBool(json, SnapToGridOnResizeKey, _SnapToGridOnResize);
// GetValueForKey will only override the current value if the key exists
JsonUtils::GetValueForKey(json, DebugFeaturesKey, _DebugFeaturesEnabled);
JsonUtils::GetBool(json, ForceFullRepaintRenderingKey, _ForceFullRepaintRendering);
JsonUtils::GetValueForKey(json, ForceFullRepaintRenderingKey, _ForceFullRepaintRendering);
JsonUtils::GetBool(json, SoftwareRenderingKey, _SoftwareRendering);
JsonUtils::GetBool(json, ForceVTInputKey, _ForceVTInput);
JsonUtils::GetValueForKey(json, SoftwareRenderingKey, _SoftwareRendering);
JsonUtils::GetValueForKey(json, ForceVTInputKey, _ForceVTInput);
// GetBool will only override the current value if the key exists
JsonUtils::GetBool(json, DebugFeaturesKey, _DebugFeaturesEnabled);
JsonUtils::GetValueForKey(json, EnableStartupTaskKey, _StartOnUserLogin);
JsonUtils::GetBool(json, EnableStartupTaskKey, _StartOnUserLogin);
JsonUtils::GetValueForKey(json, AlwaysOnTopKey, _AlwaysOnTop);
JsonUtils::GetBool(json, AlwaysOnTopKey, _AlwaysOnTop);
// This is a helper lambda to get the keybindings and commands out of both
// and array of objects. We'll use this twice, once on the legacy
@@ -209,12 +229,123 @@ void GlobalAppSettings::LayerJson(const Json::Value& json)
warnings = winrt::TerminalApp::implementation::Command::LayerJson(_commands, bindings);
// It's possible that the user provided commands have some warnings
// in them, similar to the keybindings.
_keybindingsWarnings.insert(_keybindingsWarnings.end(), warnings.begin(), warnings.end());
}
};
parseBindings(LegacyKeybindingsKey);
parseBindings(BindingsKey);
}
// Method Description:
// - Helper function for converting a user-specified cursor style corresponding
// CursorStyle enum value
// Arguments:
// - themeString: The string value from the settings file to parse
// Return Value:
// - The corresponding enum value which maps to the string provided by the user
ElementTheme GlobalAppSettings::_ParseTheme(const std::wstring& themeString) noexcept
{
if (themeString == LightThemeValue)
{
return ElementTheme::Light;
}
else if (themeString == DarkThemeValue)
{
return ElementTheme::Dark;
}
// default behavior for invalid data or SystemThemeValue
return ElementTheme::Default;
}
// Method Description:
// - Helper function for converting the initial position string into
// 2 coordinate values. We allow users to only provide one coordinate,
// thus, we use comma as the separator:
// (100, 100): standard input string
// (, 100), (100, ): if a value is missing, we set this value as a default
// (,): both x and y are set to default
// (abc, 100): if a value is not valid, we treat it as default
// (100, 100, 100): we only read the first two values, this is equivalent to (100, 100)
// Arguments:
// - initialPosition: the initial position string from json
// ret: reference to a struct whose optionals will be populated
// Return Value:
// - None
void GlobalAppSettings::_ParseInitialPosition(const std::string& initialPosition,
LaunchPosition& ret) noexcept
{
static constexpr char singleCharDelim = ',';
std::stringstream tokenStream(initialPosition);
std::string token;
uint8_t initialPosIndex = 0;
// Get initial position values till we run out of delimiter separated values in the stream
// or we hit max number of allowable values (= 2)
// Non-numeral values or empty string will be caught as exception and we do not assign them
for (; std::getline(tokenStream, token, singleCharDelim) && (initialPosIndex < 2); initialPosIndex++)
{
try
{
int32_t position = std::stoi(token);
if (initialPosIndex == 0)
{
ret.x.emplace(position);
}
if (initialPosIndex == 1)
{
ret.y.emplace(position);
}
}
catch (...)
{
// Do nothing
}
}
}
// Method Description:
// - Helper function for converting the user-specified launch mode
// to a LaunchMode enum value
// Arguments:
// - launchModeString: The string value from the settings file to parse
// Return Value:
// - The corresponding enum value which maps to the string provided by the user
LaunchMode GlobalAppSettings::_ParseLaunchMode(const std::wstring& launchModeString) noexcept
{
if (launchModeString == MaximizedLaunchModeValue)
{
return LaunchMode::MaximizedMode;
}
else if (launchModeString == FullscreenLaunchModeValue)
{
return LaunchMode::FullscreenMode;
}
return LaunchMode::DefaultMode;
}
// Method Description:
// - Helper function for converting the user-specified tab width
// to a TabViewWidthMode enum value
// Arguments:
// - tabWidthModeString: The string value from the settings file to parse
// Return Value:
// - The corresponding enum value which maps to the string provided by the user
TabViewWidthMode GlobalAppSettings::_ParseTabWidthMode(const std::wstring& tabWidthModeString) noexcept
{
if (tabWidthModeString == TitleLengthTabWidthModeValue)
{
return TabViewWidthMode::SizeToContent;
}
else if (tabWidthModeString == TitleLengthCompactModeValue)
{
return TabViewWidthMode::Compact;
}
// default behavior for invalid data or EqualTabWidthValue
return TabViewWidthMode::Equal;
}
// Method Description:
// - Adds the given colorscheme to our map of schemes, using its name as the key.
// Arguments:
@@ -227,12 +358,6 @@ void GlobalAppSettings::AddColorScheme(ColorScheme scheme)
_colorSchemes[name] = std::move(scheme);
}
void GlobalAppSettings::AddTheme(::TerminalApp::Theme theme)
{
auto name{ theme.Name() };
_themes[name] = std::move(theme);
}
// Method Description:
// - Return the warnings that we've collected during parsing the JSON for the
// keybindings. It's possible that the user provided keybindings have some
@@ -251,17 +376,3 @@ const std::unordered_map<winrt::hstring, winrt::TerminalApp::Command>& GlobalApp
{
return _commands;
}
const ::TerminalApp::Theme* GlobalAppSettings::Theme() const
{
auto iterator = _themes.find(_ThemeName);
if (iterator != _themes.end())
{
// HERE BE DRAGONS: Returning a pointer to a type in the vector is
// maybe not the _safest_ thing, but we have a mind to make Profile
// and ColorScheme winrt types in the future, so this will be safer
// then.
return &iterator->second;
}
return nullptr;
}

View File

@@ -16,9 +16,7 @@ Author(s):
#pragma once
#include "AppKeyBindings.h"
#include "ColorScheme.h"
#include "Theme.h"
#include "Command.h"
#include "SettingsTypes.h"
// fwdecl unittest classes
namespace TerminalAppLocalTests
@@ -30,6 +28,12 @@ namespace TerminalAppLocalTests
namespace TerminalApp
{
class GlobalAppSettings;
struct LaunchPosition
{
std::optional<int> x;
std::optional<int> y;
};
};
class TerminalApp::GlobalAppSettings final
@@ -42,10 +46,6 @@ public:
const std::unordered_map<std::wstring, ColorScheme>& GetColorSchemes() const noexcept;
void AddColorScheme(ColorScheme scheme);
std::unordered_map<winrt::hstring, Theme>& GetThemes() noexcept;
const std::unordered_map<winrt::hstring, Theme>& GetThemes() const noexcept;
void AddTheme(Theme theme);
winrt::TerminalApp::AppKeyBindings GetKeybindings() const noexcept;
static GlobalAppSettings FromJson(const Json::Value& json);
@@ -63,14 +63,12 @@ public:
GUID DefaultProfile() const;
std::wstring UnparsedDefaultProfile() const;
const ::TerminalApp::Theme* Theme() const;
GETSET_PROPERTY(int32_t, InitialRows); // default value set in constructor
GETSET_PROPERTY(int32_t, InitialCols); // default value set in constructor
GETSET_PROPERTY(bool, AlwaysShowTabs, true);
GETSET_PROPERTY(bool, ShowTitleInTitlebar, true);
GETSET_PROPERTY(bool, ConfirmCloseAllTabs, true);
// GETSET_PROPERTY(winrt::Windows::UI::Xaml::ElementTheme, Theme, winrt::Windows::UI::Xaml::ElementTheme::Default);
GETSET_PROPERTY(winrt::Windows::UI::Xaml::ElementTheme, Theme, winrt::Windows::UI::Xaml::ElementTheme::Default);
GETSET_PROPERTY(winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode::Equal);
GETSET_PROPERTY(bool, ShowTabsInTitlebar, true);
GETSET_PROPERTY(std::wstring, WordDelimiters); // default value set in constructor
@@ -87,7 +85,6 @@ public:
GETSET_PROPERTY(bool, DebugFeaturesEnabled); // default value set in constructor
GETSET_PROPERTY(bool, StartOnUserLogin, false);
GETSET_PROPERTY(bool, AlwaysOnTop, false);
GETSET_PROPERTY(winrt::hstring, ThemeName);
private:
std::optional<std::wstring> _unparsedDefaultProfile;
@@ -97,9 +94,17 @@ private:
std::vector<::TerminalApp::SettingsLoadWarnings> _keybindingsWarnings;
std::unordered_map<std::wstring, ColorScheme> _colorSchemes;
std::unordered_map<winrt::hstring, ::TerminalApp::Theme> _themes;
std::unordered_map<winrt::hstring, winrt::TerminalApp::Command> _commands;
static winrt::Windows::UI::Xaml::ElementTheme _ParseTheme(const std::wstring& themeString) noexcept;
static winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode _ParseTabWidthMode(const std::wstring& tabWidthModeString) noexcept;
static void _ParseInitialPosition(const std::string& initialPosition,
LaunchPosition& ret) noexcept;
static winrt::TerminalApp::LaunchMode _ParseLaunchMode(const std::wstring& launchModeString) noexcept;
friend class TerminalAppLocalTests::SettingsTests;
friend class TerminalAppLocalTests::ColorSchemeTests;
};

View File

@@ -0,0 +1,125 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Utils.h"
#include "JsonUtils.h"
#include "../../types/inc/Utils.hpp"
void TerminalApp::JsonUtils::GetOptionalColor(const Json::Value& json,
std::string_view key,
std::optional<til::color>& target)
{
const auto conversionFn = [](const Json::Value& value) -> til::color {
return ::Microsoft::Console::Utils::ColorFromHexString(value.asString());
};
GetOptionalValue(json,
key,
target,
conversionFn);
}
void TerminalApp::JsonUtils::GetOptionalString(const Json::Value& json,
std::string_view key,
std::optional<std::wstring>& target)
{
const auto conversionFn = [](const Json::Value& value) -> std::wstring {
return GetWstringFromJson(value);
};
GetOptionalValue(json,
key,
target,
conversionFn);
}
void TerminalApp::JsonUtils::GetOptionalGuid(const Json::Value& json,
std::string_view key,
std::optional<GUID>& target)
{
const auto conversionFn = [](const Json::Value& value) -> GUID {
return ::Microsoft::Console::Utils::GuidFromString(GetWstringFromJson(value));
};
GetOptionalValue(json,
key,
target,
conversionFn);
}
void TerminalApp::JsonUtils::GetOptionalDouble(const Json::Value& json,
std::string_view key,
std::optional<double>& target)
{
const auto conversionFn = [](const Json::Value& value) -> double {
return value.asFloat();
};
const auto validationFn = [](const Json::Value& value) -> bool {
return value.isNumeric();
};
GetOptionalValue(json,
key,
target,
conversionFn,
validationFn);
}
void TerminalApp::JsonUtils::GetInt(const Json::Value& json,
std::string_view key,
int& target)
{
const auto conversionFn = [](const Json::Value& value) -> int {
return value.asInt();
};
const auto validationFn = [](const Json::Value& value) -> bool {
return value.isInt();
};
GetValue(json, key, target, conversionFn, validationFn);
}
void TerminalApp::JsonUtils::GetUInt(const Json::Value& json,
std::string_view key,
uint32_t& target)
{
const auto conversionFn = [](const Json::Value& value) -> uint32_t {
return value.asUInt();
};
const auto validationFn = [](const Json::Value& value) -> bool {
return value.isUInt();
};
GetValue(json, key, target, conversionFn, validationFn);
}
void TerminalApp::JsonUtils::GetDouble(const Json::Value& json,
std::string_view key,
double& target)
{
const auto conversionFn = [](const Json::Value& value) -> double {
return value.asFloat();
};
const auto validationFn = [](const Json::Value& value) -> bool {
return value.isNumeric();
};
GetValue(json, key, target, conversionFn, validationFn);
}
void TerminalApp::JsonUtils::GetBool(const Json::Value& json,
std::string_view key,
bool& target)
{
const auto conversionFn = [](const Json::Value& value) -> bool {
return value.asBool();
};
const auto validationFn = [](const Json::Value& value) -> bool {
return value.isBool();
};
GetValue(json, key, target, conversionFn, validationFn);
}
void TerminalApp::JsonUtils::GetWstring(const Json::Value& json,
std::string_view key,
std::wstring& target)
{
const auto conversionFn = [](const Json::Value& value) -> std::wstring {
return GetWstringFromJson(value);
};
GetValue(json, key, target, conversionFn, nullptr);
}

View File

@@ -9,483 +9,136 @@ Abstract:
- Helpers for the TerminalApp project
Author(s):
- Mike Griese - August 2019
- Dustin Howett - January 2020
--*/
#pragma once
#include <json.h>
#include "../types/inc/utils.hpp"
namespace winrt
{
// If we don't use winrt, nobody will include the ConversionTraits for winrt stuff.
// If nobody includes it, these forward declarations will suffice.
struct guid;
struct hstring;
namespace Windows::Foundation
{
template<typename T>
struct IReference;
}
}
namespace TerminalApp::JsonUtils
{
namespace Detail
{
// Function Description:
// - Returns a string_view to a Json::Value's internal string storage,
// hopefully without copying it.
__declspec(noinline) inline const std::string_view GetStringView(const Json::Value& json)
{
const char* begin{ nullptr };
const char* end{ nullptr };
json.getString(&begin, &end);
const std::string_view zeroCopyString{ begin, gsl::narrow_cast<size_t>(end - begin) };
return zeroCopyString;
}
void GetOptionalColor(const Json::Value& json,
std::string_view key,
std::optional<til::color>& target);
template<typename T>
struct DeduceOptional
{
using Type = typename std::decay<T>::type;
static constexpr bool IsOptional = false;
};
void GetOptionalString(const Json::Value& json,
std::string_view key,
std::optional<std::wstring>& target);
template<typename TOpt>
struct DeduceOptional<std::optional<TOpt>>
{
using Type = typename std::decay<TOpt>::type;
static constexpr bool IsOptional = true;
};
void GetOptionalGuid(const Json::Value& json,
std::string_view key,
std::optional<GUID>& target);
template<typename TOpt>
struct DeduceOptional<::winrt::Windows::Foundation::IReference<TOpt>>
{
using Type = typename std::decay<TOpt>::type;
static constexpr bool IsOptional = true;
};
}
// These exceptions cannot use localized messages, as we do not have
// guaranteed access to the resource loader.
class TypeMismatchException : public std::runtime_error
{
public:
TypeMismatchException() :
runtime_error("unexpected data type") {}
};
class KeyedException : public std::runtime_error
{
public:
KeyedException(const std::string_view key, std::exception_ptr exception) :
runtime_error(fmt::format("error parsing \"{0}\"", key).c_str()),
_key{ key },
_innerException{ std::move(exception) } {}
std::string GetKey() const
{
return _key;
}
[[noreturn]] void RethrowInner() const
{
std::rethrow_exception(_innerException);
}
private:
std::string _key;
std::exception_ptr _innerException;
};
class UnexpectedValueException : public std::runtime_error
{
public:
UnexpectedValueException(const std::string_view value) :
runtime_error(fmt::format("unexpected value \"{0}\"", value).c_str()),
_value{ value } {}
std::string GetValue() const
{
return _value;
}
private:
std::string _value;
};
template<typename T>
struct ConversionTrait
{
// Forward-declare these so the linker can pick up specializations from elsewhere!
T FromJson(const Json::Value&);
bool CanConvert(const Json::Value& json);
};
template<>
struct ConversionTrait<std::string>
{
std::string FromJson(const Json::Value& json)
{
return json.asString();
}
bool CanConvert(const Json::Value& json)
{
return json.isString();
}
};
template<>
struct ConversionTrait<std::wstring>
{
std::wstring FromJson(const Json::Value& json)
{
return til::u8u16(Detail::GetStringView(json));
}
bool CanConvert(const Json::Value& json)
{
return json.isString();
}
};
#ifdef WINRT_BASE_H
template<>
struct ConversionTrait<winrt::hstring> : public ConversionTrait<std::wstring>
{
// Leverage the wstring converter's validation
winrt::hstring FromJson(const Json::Value& json)
{
return winrt::hstring{ til::u8u16(Detail::GetStringView(json)) };
}
};
#endif
template<>
struct ConversionTrait<bool>
{
bool FromJson(const Json::Value& json)
{
return json.asBool();
}
bool CanConvert(const Json::Value& json)
{
return json.isBool();
}
};
template<>
struct ConversionTrait<int>
{
int FromJson(const Json::Value& json)
{
return json.asInt();
}
bool CanConvert(const Json::Value& json)
{
return json.isInt();
}
};
template<>
struct ConversionTrait<unsigned int>
{
unsigned int FromJson(const Json::Value& json)
{
return json.asUInt();
}
bool CanConvert(const Json::Value& json)
{
return json.isUInt();
}
};
template<>
struct ConversionTrait<float>
{
float FromJson(const Json::Value& json)
{
return json.asFloat();
}
bool CanConvert(const Json::Value& json)
{
return json.isNumeric();
}
};
template<>
struct ConversionTrait<double>
{
double FromJson(const Json::Value& json)
{
return json.asDouble();
}
bool CanConvert(const Json::Value& json)
{
return json.isNumeric();
}
};
template<>
struct ConversionTrait<GUID>
{
GUID FromJson(const Json::Value& json)
{
return ::Microsoft::Console::Utils::GuidFromString(til::u8u16(Detail::GetStringView(json)));
}
bool CanConvert(const Json::Value& json)
{
if (!json.isString())
{
return false;
}
const auto string{ Detail::GetStringView(json) };
return string.length() == 38 && string.front() == '{' && string.back() == '}';
}
};
// (GUID and winrt::guid are mutually convertible!)
template<>
struct ConversionTrait<winrt::guid> : public ConversionTrait<GUID>
{
};
template<>
struct ConversionTrait<til::color>
{
til::color FromJson(const Json::Value& json)
{
return ::Microsoft::Console::Utils::ColorFromHexString(Detail::GetStringView(json));
}
bool CanConvert(const Json::Value& json)
{
if (!json.isString())
{
return false;
}
const auto string{ Detail::GetStringView(json) };
return (string.length() == 7 || string.length() == 4) && string.front() == '#';
}
};
template<typename T, typename TBase>
struct EnumMapper
{
using BaseEnumMapper = EnumMapper<T, TBase>;
using ValueType = T;
using pair_type = std::pair<std::string_view, T>;
T FromJson(const Json::Value& json)
{
const auto name{ Detail::GetStringView(json) };
for (const auto& pair : TBase::mappings)
{
if (pair.first == name)
{
return pair.second;
}
}
throw UnexpectedValueException{ name };
}
bool CanConvert(const Json::Value& json)
{
return json.isString();
}
};
// FlagMapper is EnumMapper, but it works for bitfields.
// It supports a string (single flag) or an array of strings.
// Does an O(n*m) search; meant for small search spaces!
//
// Cleverly leverage EnumMapper to do the heavy lifting.
template<typename T, typename TBase>
struct FlagMapper : public EnumMapper<T, TBase>
{
private:
// Hide BaseEnumMapper so FlagMapper's consumers cannot see
// it.
using BaseEnumMapper = EnumMapper<T, TBase>::BaseEnumMapper;
public:
using BaseFlagMapper = FlagMapper<T, TBase>;
static constexpr T AllSet{ static_cast<T>(~0u) };
static constexpr T AllClear{ static_cast<T>(0u) };
T FromJson(const Json::Value& json)
{
if (json.isString())
{
return BaseEnumMapper::FromJson(json);
}
else if (json.isArray())
{
unsigned int seen{ 0 };
T value{};
for (const auto& element : json)
{
const auto newFlag{ BaseEnumMapper::FromJson(element) };
if (++seen > 1 &&
((newFlag == AllClear && value != AllClear) ||
(value == AllClear && newFlag != AllClear)))
{
// attempt to combine AllClear (explicitly) with anything else
throw UnexpectedValueException{ element.asString() };
}
value |= newFlag;
}
return value;
}
// We'll only get here if CanConvert has failed us.
return AllClear;
}
bool CanConvert(const Json::Value& json)
{
return BaseEnumMapper::CanConvert(json) || json.isArray();
}
};
void GetOptionalDouble(const Json::Value& json,
std::string_view key,
std::optional<double>& target);
// Method Description:
// - Helper that will populate a reference with a value converted from a json object.
// - Helper that can be used for retrieving an optional value from a json
// object, and parsing it's value to layer on a given target object.
// - If the key we're looking for _doesn't_ exist in the json object,
// we'll leave the target object unmodified.
// - If the key exists in the json object, but is set to `null`, then
// we'll instead set the target back to nullopt.
// - Each caller should provide a conversion function that takes a
// Json::Value and returns an object of the same type as target.
// Arguments:
// - json: the json object to convert
// - target: the value to populate with the converted result
// - json: The json object to search for the given key
// - key: The key to look for in the json object
// - target: the optional object to receive the value from json
// - conversion: a std::function<T(const Json::Value&)> which can be used to
// convert the Json::Value to the appropriate type.
// - validation: optional, if provided, will be called first to ensure that
// the json::value is of the correct type before attempting to call
// `conversion`.
// Return Value:
// - a boolean indicating whether the value existed (in this case, was non-null)
//
// GetValue, type-deduced, manual converter
template<typename T, typename Converter>
bool GetValue(const Json::Value& json, T& target, Converter&& conv)
// - <none>
template<typename T, typename F>
void GetOptionalValue(const Json::Value& json,
std::string_view key,
std::optional<T>& target,
F&& conversion,
const std::function<bool(const Json::Value&)>& validation = nullptr)
{
if constexpr (Detail::DeduceOptional<T>::IsOptional)
if (json.isMember(JsonKey(key)))
{
// FOR OPTION TYPES
// - If the json object is set to `null`, then
// we'll instead set the target back to the empty optional.
if (json.isNull())
if (auto jsonVal{ json[JsonKey(key)] })
{
target = T{}; // zero-construct an empty optional
return true;
if (validation == nullptr || validation(jsonVal))
{
target = conversion(jsonVal);
}
}
else
{
// This branch is hit when the json object contained the key,
// but the key was set to `null`. In this case, explicitly clear
// the target.
target = std::nullopt;
}
}
if (json)
{
if (!conv.CanConvert(json))
{
throw TypeMismatchException{};
}
target = conv.FromJson(json);
return true;
}
return false;
}
// GetValue, forced return type, manual converter
template<typename T, typename Converter>
std::decay_t<T> GetValue(const Json::Value& json, Converter&& conv)
// Method Description:
// - Helper that can be used for retrieving a value from a json
// object, and parsing it's value to set on a given target object.
// - If the key we're looking for _doesn't_ exist in the json object,
// we'll leave the target object unmodified.
// - If the key exists in the json object, we'll use the provided
// `validation` function to ensure that the json value is of the
// correct type.
// - If we successfully validate the json value type (or no validation
// function was provided), then we'll use `conversion` to parse the
// value and place the result into `target`
// - Each caller should provide a conversion function that takes a
// Json::Value and returns an object of the same type as target.
// - Unlike GetOptionalValue, if the key exists but is set to `null`, we'll
// just ignore it.
// Arguments:
// - json: The json object to search for the given key
// - key: The key to look for in the json object
// - target: the optional object to receive the value from json
// - conversion: a std::function<T(const Json::Value&)> which can be used to
// convert the Json::Value to the appropriate type.
// - validation: optional, if provided, will be called first to ensure that
// the json::value is of the correct type before attempting to call
// `conversion`.
// Return Value:
// - <none>
template<typename T, typename F>
void GetValue(const Json::Value& json,
std::string_view key,
T& target,
F&& conversion,
const std::function<bool(const Json::Value&)>& validation = nullptr)
{
std::decay_t<T> local{};
GetValue(json, local, std::forward<Converter>(conv));
return local; // returns zero-initialized or value
}
// GetValueForKey, type-deduced, manual converter
template<typename T, typename Converter>
bool GetValueForKey(const Json::Value& json, std::string_view key, T& target, Converter&& conv)
{
if (auto found{ json.find(&*key.cbegin(), (&*key.cbegin()) + key.size()) })
if (json.isMember(JsonKey(key)))
{
try
if (auto jsonVal{ json[JsonKey(key)] })
{
return GetValue(*found, target, std::forward<Converter>(conv));
}
catch (...)
{
// Wrap any caught exceptions in one that preserves context.
throw KeyedException(key, std::current_exception());
if (validation == nullptr || validation(jsonVal))
{
target = conversion(jsonVal);
}
}
}
return false;
}
// GetValueForKey, forced return type, manual converter
template<typename T, typename Converter>
std::decay_t<T> GetValueForKey(const Json::Value& json, std::string_view key, Converter&& conv)
{
std::decay_t<T> local{};
GetValueForKey(json, key, local, std::forward<Converter>(conv));
return local; // returns zero-initialized?
}
void GetInt(const Json::Value& json,
std::string_view key,
int& target);
// GetValue, type-deduced, with automatic converter
template<typename T>
bool GetValue(const Json::Value& json, T& target)
{
return GetValue(json, target, ConversionTrait<typename Detail::DeduceOptional<T>::Type>{});
}
void GetUInt(const Json::Value& json,
std::string_view key,
uint32_t& target);
// GetValue, forced return type, with automatic converter
template<typename T>
std::decay_t<T> GetValue(const Json::Value& json)
{
std::decay_t<T> local{};
GetValue(json, local, ConversionTrait<typename Detail::DeduceOptional<T>::Type>{});
return local; // returns zero-initialized or value
}
void GetDouble(const Json::Value& json,
std::string_view key,
double& target);
// GetValueForKey, type-deduced, with automatic converter
template<typename T>
bool GetValueForKey(const Json::Value& json, std::string_view key, T& target)
{
return GetValueForKey(json, key, target, ConversionTrait<typename Detail::DeduceOptional<T>::Type>{});
}
void GetBool(const Json::Value& json,
std::string_view key,
bool& target);
// GetValueForKey, forced return type, with automatic converter
template<typename T>
std::decay_t<T> GetValueForKey(const Json::Value& json, std::string_view key)
{
return GetValueForKey<T>(json, key, ConversionTrait<typename Detail::DeduceOptional<T>::Type>{});
}
// Get multiple values for keys (json, k, &v, k, &v, k, &v, ...).
// Uses the default converter for each v.
// Careful: this can cause a template explosion.
constexpr void GetValuesForKeys(const Json::Value& /*json*/) {}
template<typename T, typename... Args>
void GetValuesForKeys(const Json::Value& json, std::string_view key1, T&& val1, Args&&... args)
{
GetValueForKey(json, key1, val1);
GetValuesForKeys(json, std::forward<Args>(args)...);
}
void GetWstring(const Json::Value& json,
std::string_view key,
std::wstring& target);
};
#define JSON_ENUM_MAPPER(...) \
template<> \
struct ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__> : \
public ::TerminalApp::JsonUtils::EnumMapper<__VA_ARGS__, ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__>>
#define JSON_FLAG_MAPPER(...) \
template<> \
struct ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__> : \
public ::TerminalApp::JsonUtils::FlagMapper<__VA_ARGS__, ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__>>
#define JSON_MAPPINGS(Count) \
static constexpr std::array<pair_type, Count> mappings

View File

@@ -0,0 +1,490 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- JsonUtils.h
Abstract:
- Helpers for the TerminalApp project
Author(s):
- Mike Griese - August 2019
- Dustin Howett - January 2020
--*/
#pragma once
#include <json.h>
#include "../types/inc/utils.hpp"
namespace winrt
{
// If we don't use winrt, nobody will include the ConversionTraits for winrt stuff.
// If nobody includes it, these forward declarations will suffice.
struct guid;
struct hstring;
namespace Windows::Foundation
{
template<typename T>
struct IReference;
}
}
namespace TerminalApp::JsonUtils
{
namespace Detail
{
// Function Description:
// - Returns a string_view to a Json::Value's internal string storage,
// hopefully without copying it.
__declspec(noinline) inline const std::string_view GetStringView(const Json::Value& json)
{
const char* begin{ nullptr };
const char* end{ nullptr };
json.getString(&begin, &end);
const std::string_view zeroCopyString{ begin, gsl::narrow_cast<size_t>(end - begin) };
return zeroCopyString;
}
template<typename T>
struct DeduceOptional
{
using Type = typename std::decay<T>::type;
static constexpr bool IsOptional = false;
};
template<typename TOpt>
struct DeduceOptional<std::optional<TOpt>>
{
using Type = typename std::decay<TOpt>::type;
static constexpr bool IsOptional = true;
};
template<typename TOpt>
struct DeduceOptional<::winrt::Windows::Foundation::IReference<TOpt>>
{
using Type = typename std::decay<TOpt>::type;
static constexpr bool IsOptional = true;
};
}
// These exceptions cannot use localized messages, as we do not have
// guaranteed access to the resource loader.
class TypeMismatchException : public std::runtime_error
{
public:
TypeMismatchException() :
runtime_error("unexpected data type") {}
};
class KeyedException : public std::runtime_error
{
public:
KeyedException(const std::string_view key, std::exception_ptr exception) :
runtime_error(fmt::format("error parsing \"{0}\"", key).c_str()),
_key{ key },
_innerException{ std::move(exception) } {}
std::string GetKey() const
{
return _key;
}
[[noreturn]] void RethrowInner() const
{
std::rethrow_exception(_innerException);
}
private:
std::string _key;
std::exception_ptr _innerException;
};
class UnexpectedValueException : public std::runtime_error
{
public:
UnexpectedValueException(const std::string_view value) :
runtime_error(fmt::format("unexpected value \"{0}\"", value).c_str()),
_value{ value } {}
std::string GetValue() const
{
return _value;
}
private:
std::string _value;
};
template<typename T>
struct ConversionTrait
{
// Forward-declare these so the linker can pick up specializations from elsewhere!
T FromJson(const Json::Value&);
bool CanConvert(const Json::Value& json);
};
template<>
struct ConversionTrait<std::string>
{
std::string FromJson(const Json::Value& json)
{
return json.asString();
}
bool CanConvert(const Json::Value& json)
{
return json.isString();
}
};
template<>
struct ConversionTrait<std::wstring>
{
std::wstring FromJson(const Json::Value& json)
{
return til::u8u16(Detail::GetStringView(json));
}
bool CanConvert(const Json::Value& json)
{
return json.isString();
}
};
#ifdef WINRT_BASE_H
template<>
struct ConversionTrait<winrt::hstring> : public ConversionTrait<std::wstring>
{
// Leverage the wstring converter's validation
winrt::hstring FromJson(const Json::Value& json)
{
return winrt::hstring{ til::u8u16(Detail::GetStringView(json)) };
}
};
#endif
template<>
struct ConversionTrait<bool>
{
bool FromJson(const Json::Value& json)
{
return json.asBool();
}
bool CanConvert(const Json::Value& json)
{
return json.isBool();
}
};
template<>
struct ConversionTrait<int>
{
int FromJson(const Json::Value& json)
{
return json.asInt();
}
bool CanConvert(const Json::Value& json)
{
return json.isInt();
}
};
template<>
struct ConversionTrait<unsigned int>
{
unsigned int FromJson(const Json::Value& json)
{
return json.asUInt();
}
bool CanConvert(const Json::Value& json)
{
return json.isUInt();
}
};
template<>
struct ConversionTrait<float>
{
float FromJson(const Json::Value& json)
{
return json.asFloat();
}
bool CanConvert(const Json::Value& json)
{
return json.isNumeric();
}
};
template<>
struct ConversionTrait<double>
{
double FromJson(const Json::Value& json)
{
return json.asDouble();
}
bool CanConvert(const Json::Value& json)
{
return json.isNumeric();
}
};
template<>
struct ConversionTrait<GUID>
{
GUID FromJson(const Json::Value& json)
{
return ::Microsoft::Console::Utils::GuidFromString(til::u8u16(Detail::GetStringView(json)));
}
bool CanConvert(const Json::Value& json)
{
if (!json.isString())
{
return false;
}
const auto string{ Detail::GetStringView(json) };
return string.length() == 38 && string.front() == '{' && string.back() == '}';
}
};
// (GUID and winrt::guid are mutually convertible!)
template<>
struct ConversionTrait<winrt::guid> : public ConversionTrait<GUID>
{
};
template<>
struct ConversionTrait<til::color>
{
til::color FromJson(const Json::Value& json)
{
return ::Microsoft::Console::Utils::ColorFromHexString(Detail::GetStringView(json));
}
bool CanConvert(const Json::Value& json)
{
if (!json.isString())
{
return false;
}
const auto string{ Detail::GetStringView(json) };
return (string.length() == 7 || string.length() == 4) && string.front() == '#';
}
};
template<typename T, typename TBase>
struct EnumMapper
{
using BaseEnumMapper = EnumMapper<T, TBase>;
using pair_type = std::pair<std::string_view, T>;
T FromJson(const Json::Value& json)
{
const auto name{ Detail::GetStringView(json) };
for (const auto& pair : TBase::mappings)
{
if (pair.first == name)
{
return pair.second;
}
}
throw UnexpectedValueException{ name };
}
bool CanConvert(const Json::Value& json)
{
return json.isString();
}
};
// FlagMapper is EnumMapper, but it works for bitfields.
// It supports a string (single flag) or an array of strings.
// Does an O(n*m) search; meant for small search spaces!
//
// Cleverly leverage EnumMapper to do the heavy lifting.
template<typename T, typename TBase>
struct FlagMapper : public EnumMapper<T, TBase>
{
private:
// Hide BaseEnumMapper so FlagMapper's consumers cannot see
// it.
using BaseEnumMapper = EnumMapper<T, TBase>::BaseEnumMapper;
public:
using BaseFlagMapper = FlagMapper<T, TBase>;
static constexpr T AllSet{ static_cast<T>(~0u) };
static constexpr T AllClear{ static_cast<T>(0u) };
T FromJson(const Json::Value& json)
{
if (json.isString())
{
return BaseEnumMapper::FromJson(json);
}
else if (json.isArray())
{
unsigned int seen{ 0 };
T value{};
for (const auto& element : json)
{
const auto newFlag{ BaseEnumMapper::FromJson(element) };
if (++seen > 1 &&
((newFlag == AllClear && value != AllClear) ||
(value == AllClear && newFlag != AllClear)))
{
// attempt to combine AllClear (explicitly) with anything else
throw UnexpectedValueException{ element.asString() };
}
value |= newFlag;
}
return value;
}
// We'll only get here if CanConvert has failed us.
return AllClear;
}
bool CanConvert(const Json::Value& json)
{
return BaseEnumMapper::CanConvert(json) || json.isArray();
}
};
// Method Description:
// - Helper that will populate a reference with a value converted from a json object.
// Arguments:
// - json: the json object to convert
// - target: the value to populate with the converted result
// Return Value:
// - a boolean indicating whether the value existed (in this case, was non-null)
//
// GetValue, type-deduced, manual converter
template<typename T, typename Converter>
bool GetValue(const Json::Value& json, T& target, Converter&& conv)
{
if constexpr (Detail::DeduceOptional<T>::IsOptional)
{
// FOR OPTION TYPES
// - If the json object is set to `null`, then
// we'll instead set the target back to the empty optional.
if (json.isNull())
{
target = T{}; // zero-construct an empty optional
return true;
}
}
if (json)
{
if (!conv.CanConvert(json))
{
throw TypeMismatchException{};
}
target = conv.FromJson(json);
return true;
}
return false;
}
// GetValue, forced return type, manual converter
template<typename T, typename Converter>
std::decay_t<T> GetValue(const Json::Value& json, Converter&& conv)
{
std::decay_t<T> local{};
GetValue(json, local, std::forward<Converter>(conv));
return local; // returns zero-initialized or value
}
// GetValueForKey, type-deduced, manual converter
template<typename T, typename Converter>
bool GetValueForKey(const Json::Value& json, std::string_view key, T& target, Converter&& conv)
{
if (auto found{ json.find(&*key.cbegin(), (&*key.cbegin()) + key.size()) })
{
try
{
return GetValue(*found, target, std::forward<Converter>(conv));
}
catch (...)
{
// Wrap any caught exceptions in one that preserves context.
throw KeyedException(key, std::current_exception());
}
}
return false;
}
// GetValueForKey, forced return type, manual converter
template<typename T, typename Converter>
std::decay_t<T> GetValueForKey(const Json::Value& json, std::string_view key, Converter&& conv)
{
std::decay_t<T> local{};
GetValueForKey(json, key, local, std::forward<Converter>(conv));
return local; // returns zero-initialized?
}
// GetValue, type-deduced, with automatic converter
template<typename T>
bool GetValue(const Json::Value& json, T& target)
{
return GetValue(json, target, ConversionTrait<typename Detail::DeduceOptional<T>::Type>{});
}
// GetValue, forced return type, with automatic converter
template<typename T>
std::decay_t<T> GetValue(const Json::Value& json)
{
std::decay_t<T> local{};
GetValue(json, local, ConversionTrait<typename Detail::DeduceOptional<T>::Type>{});
return local; // returns zero-initialized or value
}
// GetValueForKey, type-deduced, with automatic converter
template<typename T>
bool GetValueForKey(const Json::Value& json, std::string_view key, T& target)
{
return GetValueForKey(json, key, target, ConversionTrait<typename Detail::DeduceOptional<T>::Type>{});
}
// GetValueForKey, forced return type, with automatic converter
template<typename T>
std::decay_t<T> GetValueForKey(const Json::Value& json, std::string_view key)
{
return GetValueForKey<T>(json, key, ConversionTrait<typename Detail::DeduceOptional<T>::Type>{});
}
// Get multiple values for keys (json, k, &v, k, &v, k, &v, ...).
// Uses the default converter for each v.
// Careful: this can cause a template explosion.
constexpr void GetValuesForKeys(const Json::Value& /*json*/) {}
template<typename T, typename... Args>
void GetValuesForKeys(const Json::Value& json, std::string_view key1, T&& val1, Args&&... args)
{
GetValueForKey(json, key1, val1);
GetValuesForKeys(json, std::forward<Args>(args)...);
}
};
#define JSON_ENUM_MAPPER(...) \
template<> \
struct ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__> : \
public ::TerminalApp::JsonUtils::EnumMapper<__VA_ARGS__, ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__>>
#define JSON_FLAG_MAPPER(...) \
template<> \
struct ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__> : \
public ::TerminalApp::JsonUtils::FlagMapper<__VA_ARGS__, ::TerminalApp::JsonUtils::ConversionTrait<__VA_ARGS__>>
#define JSON_MAPPINGS(Count) \
static constexpr std::array<pair_type, Count> mappings

View File

@@ -7,7 +7,6 @@
#include "CascadiaSettings.h"
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Graphics::Display;
using namespace winrt::Windows::UI;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Core;
@@ -922,102 +921,6 @@ bool Pane::CanSplit(SplitState splitType)
return false;
}
// Method Description:
// - This is a helper to determine if a given Pane can be split, but without
// using the ActualWidth() and ActualHeight() methods. This is used during
// processing of many "split-pane" commands, which could happen _before_ we've
// laid out a Pane for the first time. When this happens, the Pane's don't
// have an actual size yet. However, we'd still like to figure out if the pane
// could be split, once they're all laid out.
// - This method assumes that the Pane we're attempting to split is `target`,
// and this method should be called on the root of a tree of Panes.
// - We'll walk down the tree attempting to find `target`. As we traverse the
// tree, we'll reduce the size passed to each subsequent recursive call. The
// size passed to this method represents how much space this Pane _will_ have
// to use.
// * If this pane is a leaf, and it's the pane we're looking for, use the
// available space to calculate which direction to split in.
// * If this pane is _any other leaf_, then just return nullopt, to indicate
// that the `target` Pane is not down this branch.
// * If this pane is a parent, calculate how much space our children will be
// able to use, and recurse into them.
// Arguments:
// - target: The Pane we're attempting to split.
// - splitType: The direction we're attempting to split in.
// - availableSpace: The theoretical space that's available for this pane to be able to split.
// Return Value:
// - nullopt if `target` is not this pane or a child of this pane, otherwise
// true iff we could split this pane, given `availableSpace`
// Note:
// - This method is highly similar to Pane::PreCalculateAutoSplit
std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> target,
SplitState splitType,
const winrt::Windows::Foundation::Size availableSpace) const
{
if (_IsLeaf())
{
if (target.get() == this)
{
// If this pane is a leaf, and it's the pane we're looking for, use
// the available space to calculate which direction to split in.
const Size minSize = _GetMinSize();
if (splitType == SplitState::None)
{
return { false };
}
else if (splitType == SplitState::Vertical)
{
const auto widthMinusSeparator = availableSpace.Width - CombinedPaneBorderSize;
const auto newWidth = widthMinusSeparator * Half;
return { newWidth > minSize.Width };
}
else if (splitType == SplitState::Horizontal)
{
const auto heightMinusSeparator = availableSpace.Height - CombinedPaneBorderSize;
const auto newHeight = heightMinusSeparator * Half;
return { newHeight > minSize.Height };
}
}
else
{
// If this pane is _any other leaf_, then just return nullopt, to
// indicate that the `target` Pane is not down this branch.
return std::nullopt;
}
}
else
{
// If this pane is a parent, calculate how much space our children will
// be able to use, and recurse into them.
const bool isVerticalSplit = _splitState == SplitState::Vertical;
const float firstWidth = isVerticalSplit ?
(availableSpace.Width * _desiredSplitPosition) - PaneBorderSize :
availableSpace.Width;
const float secondWidth = isVerticalSplit ?
(availableSpace.Width - firstWidth) - PaneBorderSize :
availableSpace.Width;
const float firstHeight = !isVerticalSplit ?
(availableSpace.Height * _desiredSplitPosition) - PaneBorderSize :
availableSpace.Height;
const float secondHeight = !isVerticalSplit ?
(availableSpace.Height - firstHeight) - PaneBorderSize :
availableSpace.Height;
const auto firstResult = _firstChild->PreCalculateCanSplit(target, splitType, { firstWidth, firstHeight });
return firstResult.has_value() ? firstResult : _secondChild->PreCalculateCanSplit(target, splitType, { secondWidth, secondHeight });
}
// We should not possibly be getting here - both the above branches should
// return a value.
FAIL_FAST();
}
// Method Description:
// - Split the focused pane in our tree of panes, and place the given
// TermControl into the newly created pane. If we're the focused pane, then

View File

@@ -64,9 +64,7 @@ public:
const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
std::optional<winrt::TerminalApp::SplitState> PreCalculateAutoSplit(const std::shared_ptr<Pane> target, const winrt::Windows::Foundation::Size parentSize) const;
std::optional<bool> PreCalculateCanSplit(const std::shared_ptr<Pane> target,
winrt::TerminalApp::SplitState splitType,
const winrt::Windows::Foundation::Size availableSpace) const;
void Shutdown();
void Close();

View File

@@ -9,7 +9,6 @@
#include <DefaultSettings.h>
#include "LegacyProfileGeneratorNamespaces.h"
#include "TerminalSettingsSerializationHelpers.h"
using namespace TerminalApp;
using namespace winrt::Microsoft::Terminal::Settings;
@@ -53,6 +52,57 @@ static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageA
static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" };
static constexpr std::string_view AntialiasingModeKey{ "antialiasingMode" };
// Possible values for closeOnExit
static constexpr std::string_view CloseOnExitAlways{ "always" };
static constexpr std::string_view CloseOnExitGraceful{ "graceful" };
static constexpr std::string_view CloseOnExitNever{ "never" };
// 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 Font Weight
static constexpr std::string_view FontWeightThin{ "thin" };
static constexpr std::string_view FontWeightExtraLight{ "extra-light" };
static constexpr std::string_view FontWeightLight{ "light" };
static constexpr std::string_view FontWeightSemiLight{ "semi-light" };
static constexpr std::string_view FontWeightNormal{ "normal" };
static constexpr std::string_view FontWeightMedium{ "medium" };
static constexpr std::string_view FontWeightSemiBold{ "semi-bold" };
static constexpr std::string_view FontWeightBold{ "bold" };
static constexpr std::string_view FontWeightExtraBold{ "extra-bold" };
static constexpr std::string_view FontWeightBlack{ "black" };
static constexpr std::string_view FontWeightExtraBlack{ "extra-black" };
// 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" };
// Possible values for Image Alignment
static constexpr std::string_view ImageAlignmentCenter{ "center" };
static constexpr std::string_view ImageAlignmentLeft{ "left" };
static constexpr std::string_view ImageAlignmentTop{ "top" };
static constexpr std::string_view ImageAlignmentRight{ "right" };
static constexpr std::string_view ImageAlignmentBottom{ "bottom" };
static constexpr std::string_view ImageAlignmentTopLeft{ "topLeft" };
static constexpr std::string_view ImageAlignmentTopRight{ "topRight" };
static constexpr std::string_view ImageAlignmentBottomLeft{ "bottomLeft" };
static constexpr std::string_view ImageAlignmentBottomRight{ "bottomRight" };
// Possible values for TextAntialiasingMode
static constexpr std::wstring_view AntialiasingModeGrayscale{ L"grayscale" };
static constexpr std::wstring_view AntialiasingModeCleartype{ L"cleartype" };
static constexpr std::wstring_view AntialiasingModeAliased{ L"aliased" };
Profile::Profile() :
Profile(std::nullopt)
{
@@ -198,7 +248,8 @@ TerminalSettings Profile::CreateTerminalSettings(const std::unordered_map<std::w
if (_scrollbarState)
{
terminalSettings.ScrollState(_scrollbarState.value());
ScrollbarState result = ParseScrollbarState(_scrollbarState.value());
terminalSettings.ScrollState(result);
}
if (HasBackgroundImage())
@@ -299,9 +350,11 @@ 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.
if (const auto otherGuid{ JsonUtils::GetValueForKey<std::optional<GUID>>(json, GuidKey) })
if (json.isMember(JsonKey(GuidKey)))
{
if (otherGuid != _guid) // optional compare takes care of this
const auto guid{ json[JsonKey(GuidKey)] };
const auto otherGuid = Utils::GuidFromString(GetWstringFromJson(guid));
if (_guid.value() != otherGuid)
{
return false;
}
@@ -315,17 +368,16 @@ bool Profile::ShouldBeLayered(const Json::Value& json) const
return false;
}
std::optional<std::wstring> otherSource;
bool otherHadSource = JsonUtils::GetValueForKey(json, SourceKey, otherSource);
const auto& otherSource = json.isMember(JsonKey(SourceKey)) ? json[JsonKey(SourceKey)] : Json::Value::null;
// For profiles with a `source`, also check the `source` property.
bool sourceMatches = false;
if (_source.has_value())
{
if (otherHadSource)
if (json.isMember(JsonKey(SourceKey)))
{
// If we have a source and the other has a source, compare them!
sourceMatches = otherSource == _source;
const auto otherSourceString = GetWstringFromJson(otherSource);
sourceMatches = otherSourceString == _source.value();
}
else
{
@@ -343,13 +395,52 @@ bool Profile::ShouldBeLayered(const Json::Value& json) const
}
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"");
// We do not have a source. The only way we match is if source is set to null or "".
if (otherSource.isNull() || (otherSource.isString() && otherSource == ""))
{
sourceMatches = true;
}
}
return sourceMatches;
}
// Method Description:
// - Helper function to convert a json value into a value of the Stretch enum.
// Calls into ParseImageStretchMode. Used with JsonUtils::GetOptionalValue.
// Arguments:
// - json: the Json::Value object to parse.
// Return Value:
// - An appropriate value from Windows.UI.Xaml.Media.Stretch
Media::Stretch Profile::_ConvertJsonToStretchMode(const Json::Value& json)
{
return Profile::ParseImageStretchMode(json.asString());
}
// Method Description:
// - Helper function to convert a json value into a value of the Stretch enum.
// Calls into ParseImageAlignment. Used with JsonUtils::GetOptionalValue.
// Arguments:
// - json: the Json::Value object to parse.
// Return Value:
// - A pair of HorizontalAlignment and VerticalAlignment
std::tuple<HorizontalAlignment, VerticalAlignment> Profile::_ConvertJsonToAlignment(const Json::Value& json)
{
return Profile::ParseImageAlignment(json.asString());
}
// Method Description:
// - Helper function to convert a json value into a bool.
// Used with JsonUtils::GetOptionalValue.
// Arguments:
// - json: the Json::Value object to parse.
// Return Value:
// - A bool
bool Profile::_ConvertJsonToBool(const Json::Value& json)
{
return json.asBool();
}
// Method Description:
// - 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
@@ -365,45 +456,89 @@ bool Profile::ShouldBeLayered(const Json::Value& json) const
void Profile::LayerJson(const Json::Value& json)
{
// Profile-specific Settings
JsonUtils::GetValueForKey(json, NameKey, _name);
JsonUtils::GetValueForKey(json, GuidKey, _guid);
JsonUtils::GetValueForKey(json, HiddenKey, _hidden);
JsonUtils::GetWstring(json, NameKey, _name);
JsonUtils::GetOptionalGuid(json, GuidKey, _guid);
JsonUtils::GetBool(json, HiddenKey, _hidden);
// Core Settings
JsonUtils::GetValueForKey(json, ForegroundKey, _defaultForeground);
JsonUtils::GetValueForKey(json, BackgroundKey, _defaultBackground);
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _selectionBackground);
JsonUtils::GetValueForKey(json, CursorColorKey, _cursorColor);
JsonUtils::GetValueForKey(json, ColorSchemeKey, _schemeName);
JsonUtils::GetOptionalColor(json, ForegroundKey, _defaultForeground);
JsonUtils::GetOptionalColor(json, BackgroundKey, _defaultBackground);
JsonUtils::GetOptionalColor(json, SelectionBackgroundKey, _selectionBackground);
JsonUtils::GetOptionalColor(json, CursorColorKey, _cursorColor);
JsonUtils::GetOptionalString(json, ColorSchemeKey, _schemeName);
// TODO:MSFT:20642297 - Use a sentinel value (-1) for "Infinite scrollback"
JsonUtils::GetValueForKey(json, HistorySizeKey, _historySize);
JsonUtils::GetValueForKey(json, SnapOnInputKey, _snapOnInput);
JsonUtils::GetValueForKey(json, AltGrAliasingKey, _altGrAliasing);
JsonUtils::GetValueForKey(json, CursorHeightKey, _cursorHeight);
JsonUtils::GetValueForKey(json, CursorShapeKey, _cursorShape);
JsonUtils::GetValueForKey(json, TabTitleKey, _tabTitle);
JsonUtils::GetInt(json, HistorySizeKey, _historySize);
JsonUtils::GetBool(json, SnapOnInputKey, _snapOnInput);
JsonUtils::GetBool(json, AltGrAliasingKey, _altGrAliasing);
JsonUtils::GetUInt(json, CursorHeightKey, _cursorHeight);
if (json.isMember(JsonKey(CursorShapeKey)))
{
auto cursorShape{ json[JsonKey(CursorShapeKey)] };
_cursorShape = _ParseCursorShape(GetWstringFromJson(cursorShape));
}
JsonUtils::GetOptionalString(json, TabTitleKey, _tabTitle);
// Control Settings
JsonUtils::GetValueForKey(json, FontWeightKey, _fontWeight);
JsonUtils::GetValueForKey(json, ConnectionTypeKey, _connectionType);
JsonUtils::GetValueForKey(json, CommandlineKey, _commandline);
JsonUtils::GetValueForKey(json, FontFaceKey, _fontFace);
JsonUtils::GetValueForKey(json, FontSizeKey, _fontSize);
JsonUtils::GetValueForKey(json, AcrylicTransparencyKey, _acrylicTransparency);
JsonUtils::GetValueForKey(json, UseAcrylicKey, _useAcrylic);
JsonUtils::GetValueForKey(json, SuppressApplicationTitleKey, _suppressApplicationTitle);
JsonUtils::GetValueForKey(json, CloseOnExitKey, _closeOnExitMode);
JsonUtils::GetValueForKey(json, PaddingKey, _padding);
JsonUtils::GetValueForKey(json, ScrollbarStateKey, _scrollbarState);
JsonUtils::GetValueForKey(json, StartingDirectoryKey, _startingDirectory);
JsonUtils::GetValueForKey(json, IconKey, _icon);
JsonUtils::GetValueForKey(json, BackgroundImageKey, _backgroundImage);
JsonUtils::GetValueForKey(json, BackgroundImageOpacityKey, _backgroundImageOpacity);
JsonUtils::GetValueForKey(json, BackgroundImageStretchModeKey, _backgroundImageStretchMode);
JsonUtils::GetValueForKey(json, BackgroundImageAlignmentKey, _backgroundImageAlignment);
JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _retroTerminalEffect);
JsonUtils::GetValueForKey(json, AntialiasingModeKey, _antialiasingMode);
JsonUtils::GetOptionalGuid(json, ConnectionTypeKey, _connectionType);
JsonUtils::GetWstring(json, CommandlineKey, _commandline);
JsonUtils::GetWstring(json, FontFaceKey, _fontFace);
JsonUtils::GetInt(json, FontSizeKey, _fontSize);
if (json.isMember(JsonKey(FontWeightKey)))
{
auto fontWeight{ json[JsonKey(FontWeightKey)] };
_fontWeight = _ParseFontWeight(fontWeight);
}
JsonUtils::GetDouble(json, AcrylicTransparencyKey, _acrylicTransparency);
JsonUtils::GetBool(json, UseAcrylicKey, _useAcrylic);
JsonUtils::GetBool(json, SuppressApplicationTitleKey, _suppressApplicationTitle);
if (json.isMember(JsonKey(CloseOnExitKey)))
{
auto closeOnExit{ json[JsonKey(CloseOnExitKey)] };
_closeOnExitMode = ParseCloseOnExitMode(closeOnExit);
}
JsonUtils::GetWstring(json, PaddingKey, _padding);
JsonUtils::GetOptionalString(json, ScrollbarStateKey, _scrollbarState);
JsonUtils::GetOptionalString(json, StartingDirectoryKey, _startingDirectory);
JsonUtils::GetOptionalString(json, IconKey, _icon);
JsonUtils::GetOptionalString(json, BackgroundImageKey, _backgroundImage);
JsonUtils::GetOptionalDouble(json, BackgroundImageOpacityKey, _backgroundImageOpacity);
JsonUtils::GetOptionalValue(json, BackgroundImageStretchModeKey, _backgroundImageStretchMode, &Profile::_ConvertJsonToStretchMode);
JsonUtils::GetOptionalValue(json, BackgroundImageAlignmentKey, _backgroundImageAlignment, &Profile::_ConvertJsonToAlignment);
JsonUtils::GetOptionalValue(json, RetroTerminalEffectKey, _retroTerminalEffect, Profile::_ConvertJsonToBool);
if (json.isMember(JsonKey(AntialiasingModeKey)))
{
auto antialiasingMode{ json[JsonKey(AntialiasingModeKey)] };
_antialiasingMode = ParseTextAntialiasingMode(GetWstringFromJson(antialiasingMode));
}
}
void Profile::SetFontFace(std::wstring fontFace) noexcept
@@ -635,6 +770,249 @@ std::wstring Profile::EvaluateStartingDirectory(const std::wstring& directory)
}
}
// Method Description:
// - Helper function for converting a user-specified font weight value to its corresponding enum
// Arguments:
// - The value from the settings.json file
// Return Value:
// - The corresponding value which maps to the string provided by the user
winrt::Windows::UI::Text::FontWeight Profile::_ParseFontWeight(const Json::Value& json)
{
if (json.isUInt())
{
winrt::Windows::UI::Text::FontWeight weight;
weight.Weight = static_cast<uint16_t>(json.asUInt());
// We're only accepting variable values between 100 and 990 so we don't go too crazy.
if (weight.Weight >= 100 && weight.Weight <= 990)
{
return weight;
}
}
if (json.isString())
{
auto fontWeight = json.asString();
if (fontWeight == FontWeightThin)
{
return winrt::Windows::UI::Text::FontWeights::Thin();
}
else if (fontWeight == FontWeightExtraLight)
{
return winrt::Windows::UI::Text::FontWeights::ExtraLight();
}
else if (fontWeight == FontWeightLight)
{
return winrt::Windows::UI::Text::FontWeights::Light();
}
else if (fontWeight == FontWeightSemiLight)
{
return winrt::Windows::UI::Text::FontWeights::SemiLight();
}
else if (fontWeight == FontWeightNormal)
{
return winrt::Windows::UI::Text::FontWeights::Normal();
}
else if (fontWeight == FontWeightMedium)
{
return winrt::Windows::UI::Text::FontWeights::Medium();
}
else if (fontWeight == FontWeightSemiBold)
{
return winrt::Windows::UI::Text::FontWeights::SemiBold();
}
else if (fontWeight == FontWeightBold)
{
return winrt::Windows::UI::Text::FontWeights::Bold();
}
else if (fontWeight == FontWeightExtraBold)
{
return winrt::Windows::UI::Text::FontWeights::ExtraBold();
}
else if (fontWeight == FontWeightBlack)
{
return winrt::Windows::UI::Text::FontWeights::Black();
}
else if (fontWeight == FontWeightExtraBlack)
{
return winrt::Windows::UI::Text::FontWeights::ExtraBlack();
}
}
return winrt::Windows::UI::Text::FontWeights::Normal();
}
// Method Description:
// - Helper function for converting a user-specified closeOnExit value to its corresponding enum
// Arguments:
// - The value from the settings.json file
// Return Value:
// - The corresponding enum value which maps to the string provided by the user
CloseOnExitMode Profile::ParseCloseOnExitMode(const Json::Value& json)
{
if (json.isBool())
{
return json.asBool() ? CloseOnExitMode::Graceful : CloseOnExitMode::Never;
}
if (json.isString())
{
auto closeOnExit = json.asString();
if (closeOnExit == CloseOnExitAlways)
{
return CloseOnExitMode::Always;
}
else if (closeOnExit == CloseOnExitGraceful)
{
return CloseOnExitMode::Graceful;
}
else if (closeOnExit == CloseOnExitNever)
{
return CloseOnExitMode::Never;
}
}
return CloseOnExitMode::Graceful;
}
// Method Description:
// - Helper function for converting a user-specified scrollbar state to its corresponding enum
// Arguments:
// - The value from the settings.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 settings.json file
// Return Value:
// - The corresponding enum value which maps to the string provided by the user
Media::Stretch Profile::ParseImageStretchMode(const std::string_view imageStretchMode)
{
if (imageStretchMode == ImageStretchModeNone)
{
return Media::Stretch::None;
}
else if (imageStretchMode == ImageStretchModeFill)
{
return Media::Stretch::Fill;
}
else if (imageStretchMode == ImageStretchModeUniform)
{
return Media::Stretch::Uniform;
}
else // Fall through to default behavior
{
return Media::Stretch::UniformToFill;
}
}
// Method Description:
// - Helper function for converting a user-specified image horizontal and vertical
// alignment to the appropriate enum values tuple
// Arguments:
// - The value from the settings.json file
// Return Value:
// - The corresponding enum values tuple which maps to the string provided by the user
std::tuple<HorizontalAlignment, VerticalAlignment> Profile::ParseImageAlignment(const std::string_view imageAlignment)
{
if (imageAlignment == ImageAlignmentTopLeft)
{
return std::make_tuple(HorizontalAlignment::Left,
VerticalAlignment::Top);
}
else if (imageAlignment == ImageAlignmentBottomLeft)
{
return std::make_tuple(HorizontalAlignment::Left,
VerticalAlignment::Bottom);
}
else if (imageAlignment == ImageAlignmentLeft)
{
return std::make_tuple(HorizontalAlignment::Left,
VerticalAlignment::Center);
}
else if (imageAlignment == ImageAlignmentTopRight)
{
return std::make_tuple(HorizontalAlignment::Right,
VerticalAlignment::Top);
}
else if (imageAlignment == ImageAlignmentBottomRight)
{
return std::make_tuple(HorizontalAlignment::Right,
VerticalAlignment::Bottom);
}
else if (imageAlignment == ImageAlignmentRight)
{
return std::make_tuple(HorizontalAlignment::Right,
VerticalAlignment::Center);
}
else if (imageAlignment == ImageAlignmentTop)
{
return std::make_tuple(HorizontalAlignment::Center,
VerticalAlignment::Top);
}
else if (imageAlignment == ImageAlignmentBottom)
{
return std::make_tuple(HorizontalAlignment::Center,
VerticalAlignment::Bottom);
}
else // Fall through to default alignment
{
return std::make_tuple(HorizontalAlignment::Center,
VerticalAlignment::Center);
}
}
// 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:
// - If this profile never had a GUID set for it, generate a runtime GUID for
// the profile. If a profile had their guid manually set to {0}, this method
@@ -700,13 +1078,17 @@ GUID Profile::_GenerateGuidForProfile(const std::wstring& name, const std::optio
// - The json's `guid`, or a guid synthesized for it.
GUID Profile::GetGuidOrGenerateForJson(const Json::Value& json) noexcept
{
if (const auto guid{ JsonUtils::GetValueForKey<std::optional<GUID>>(json, GuidKey) })
std::optional<GUID> guid{ std::nullopt };
JsonUtils::GetOptionalGuid(json, GuidKey, guid);
if (guid)
{
return guid.value();
}
const auto name{ JsonUtils::GetValueForKey<std::wstring>(json, NameKey) };
const auto source{ JsonUtils::GetValueForKey<std::optional<std::wstring>>(json, SourceKey) };
const auto name = GetWstringFromJson(json[JsonKey(NameKey)]);
std::optional<std::wstring> source{ std::nullopt };
JsonUtils::GetOptionalString(json, SourceKey, source);
return Profile::_GenerateGuidForProfile(name, source);
}
@@ -715,3 +1097,28 @@ void Profile::SetRetroTerminalEffect(bool value) noexcept
{
_retroTerminalEffect = value;
}
// Method Description:
// - Helper function for converting a user-specified antialiasing mode
// corresponding TextAntialiasingMode enum value
// Arguments:
// - antialiasingMode: The string value from the settings file to parse
// Return Value:
// - The corresponding enum value which maps to the string provided by the user
TextAntialiasingMode Profile::ParseTextAntialiasingMode(const std::wstring& antialiasingMode)
{
if (antialiasingMode == AntialiasingModeCleartype)
{
return TextAntialiasingMode::Cleartype;
}
else if (antialiasingMode == AntialiasingModeAliased)
{
return TextAntialiasingMode::Aliased;
}
else if (antialiasingMode == AntialiasingModeGrayscale)
{
return TextAntialiasingMode::Grayscale;
}
// default behavior for invalid data
return TextAntialiasingMode::Grayscale;
}

View File

@@ -15,7 +15,6 @@ Author(s):
--*/
#pragma once
#include "ColorScheme.h"
#include "SettingsTypes.h"
// fwdecl unittest classes
namespace TerminalAppLocalTests
@@ -36,7 +35,14 @@ constexpr GUID RUNTIME_GENERATED_PROFILE_NAMESPACE_GUID = { 0xf65ddb7e, 0x706b,
namespace TerminalApp
{
class Profile;
}
enum class CloseOnExitMode
{
Never = 0,
Graceful,
Always
};
};
class TerminalApp::Profile final
{
@@ -101,8 +107,24 @@ public:
private:
static std::wstring EvaluateStartingDirectory(const std::wstring& directory);
static winrt::Microsoft::Terminal::Settings::ScrollbarState ParseScrollbarState(const std::wstring& scrollbarState);
static winrt::Windows::UI::Xaml::Media::Stretch ParseImageStretchMode(const std::string_view imageStretchMode);
static winrt::Windows::UI::Xaml::Media::Stretch _ConvertJsonToStretchMode(const Json::Value& json);
static std::tuple<winrt::Windows::UI::Xaml::HorizontalAlignment, winrt::Windows::UI::Xaml::VerticalAlignment> ParseImageAlignment(const std::string_view imageAlignment);
static std::tuple<winrt::Windows::UI::Xaml::HorizontalAlignment, winrt::Windows::UI::Xaml::VerticalAlignment> _ConvertJsonToAlignment(const Json::Value& json);
static winrt::Windows::UI::Text::FontWeight _ParseFontWeight(const Json::Value& json);
static CloseOnExitMode ParseCloseOnExitMode(const Json::Value& json);
static winrt::Microsoft::Terminal::Settings::CursorStyle _ParseCursorShape(const std::wstring& cursorShapeString);
static winrt::Microsoft::Terminal::Settings::TextAntialiasingMode ParseTextAntialiasingMode(const std::wstring& antialiasingMode);
static GUID _GenerateGuidForProfile(const std::wstring& name, const std::optional<std::wstring>& source) noexcept;
static bool _ConvertJsonToBool(const Json::Value& json);
std::optional<GUID> _guid{ std::nullopt };
std::optional<std::wstring> _source{ std::nullopt };
std::wstring _name;
@@ -137,7 +159,7 @@ private:
std::optional<winrt::Windows::UI::Xaml::Media::Stretch> _backgroundImageStretchMode;
std::optional<std::tuple<winrt::Windows::UI::Xaml::HorizontalAlignment, winrt::Windows::UI::Xaml::VerticalAlignment>> _backgroundImageAlignment;
std::optional<::winrt::Microsoft::Terminal::Settings::ScrollbarState> _scrollbarState;
std::optional<std::wstring> _scrollbarState;
CloseOnExitMode _closeOnExitMode;
std::wstring _padding;

View File

@@ -543,10 +543,6 @@
<data name="ResetTabNameCommandKey" xml:space="preserve">
<value>Reset tab title</value>
</data>
<data name="ExecuteCommandlineCommandKey" xml:space="preserve">
<value>Run commandline "{0}" in this window</value>
<comment>{0} will be replaced with user-defined commandline</comment>
</data>
<data name="CrimsonColorButton.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>Crimson</value>
</data>

View File

@@ -1,43 +0,0 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- SettingsTypes.h
Abstract:
- Types used in the settings model (non-exported)
--*/
#pragma once
namespace TerminalApp
{
enum class CloseOnExitMode
{
Never = 0,
Graceful,
Always
};
struct LaunchPosition
{
std::optional<int> x;
std::optional<int> y;
};
enum class ColorType
{
Value = 0,
Accent,
TerminalBackground,
TerminalForeground,
ResourceKey
};
struct ThemeColor
{
ColorType type{ ColorType::Value };
std::optional<til::color> value{ std::nullopt };
};
};

View File

@@ -194,10 +194,6 @@ namespace winrt::TerminalApp::implementation
_RenameTabHandlers(*this, *eventArgs);
break;
}
case ShortcutAction::ExecuteCommandline:
{
_ExecuteCommandlineHandlers(*this, *eventArgs);
}
default:
return false;
}

View File

@@ -54,7 +54,6 @@ namespace winrt::TerminalApp::implementation
TYPED_EVENT(SetTabColor, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(OpenTabColorPicker, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(RenameTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ExecuteCommandline, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
// clang-format on
private:

View File

@@ -35,11 +35,10 @@ namespace TerminalApp
ToggleFocusMode,
ToggleFullscreen,
ToggleAlwaysOnTop,
OpenSettings,
SetTabColor,
OpenTabColorPicker,
OpenSettings,
RenameTab,
ExecuteCommandline,
ToggleCommandPalette
};
@@ -85,6 +84,5 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> SetTabColor;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> OpenTabColorPicker;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> RenameTab;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> ExecuteCommandline;
}
}

View File

@@ -875,10 +875,6 @@ namespace winrt::TerminalApp::implementation
return _rootPane->PreCalculateAutoSplit(_activePane, availableSpace).value_or(SplitState::Vertical);
}
bool Tab::PreCalculateCanSplit(SplitState splitType, winrt::Windows::Foundation::Size availableSpace) const
{
return _rootPane->PreCalculateCanSplit(_activePane, splitType, availableSpace).value_or(false);
}
DEFINE_EVENT(Tab, ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>);
DEFINE_EVENT(Tab, ColorSelected, _colorSelected, winrt::delegate<winrt::Windows::UI::Color>);
DEFINE_EVENT(Tab, ColorCleared, _colorCleared, winrt::delegate<>);

View File

@@ -40,7 +40,6 @@ namespace winrt::TerminalApp::implementation
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
SplitState PreCalculateAutoSplit(winrt::Windows::Foundation::Size rootSize) const;
bool PreCalculateCanSplit(SplitState splitType, winrt::Windows::Foundation::Size availableSpace) const;
void ResizeContent(const winrt::Windows::Foundation::Size& newSize);
void ResizePane(const winrt::TerminalApp::Direction& direction);

View File

@@ -46,8 +46,7 @@ namespace winrt
namespace winrt::TerminalApp::implementation
{
TerminalPage::TerminalPage() :
_tabs{ winrt::single_threaded_observable_vector<TerminalApp::Tab>() },
_startupActions{ winrt::single_threaded_vector<winrt::TerminalApp::ActionAndArgs>() }
_tabs{ winrt::single_threaded_observable_vector<TerminalApp::Tab>() }
{
InitializeComponent();
}
@@ -224,7 +223,7 @@ namespace winrt::TerminalApp::implementation
if (_startupState == StartupState::NotInitialized)
{
_startupState = StartupState::InStartup;
if (_startupActions.Size() == 0)
if (_startupActions.empty())
{
_OpenNewTab(nullptr);
@@ -232,27 +231,22 @@ namespace winrt::TerminalApp::implementation
}
else
{
_ProcessStartupActions(_startupActions, true);
_ProcessStartupActions();
}
}
}
// Method Description:
// - Process all the startup actions in the provided list of startup
// actions. We'll do this all at once here.
// - Process all the startup actions in our list of startup actions. We'll
// do this all at once here.
// Arguments:
// - actions: a winrt vector of actions to process. Note that this must NOT
// be an IVector&, because we need the collection to be accessible on the
// other side of the co_await.
// - initial: if true, we're parsing these args during startup, and we
// should fire an Initialized event.
// - <none>
// Return Value:
// - <none>
winrt::fire_and_forget TerminalPage::_ProcessStartupActions(Windows::Foundation::Collections::IVector<winrt::TerminalApp::ActionAndArgs> actions,
const bool initial)
winrt::fire_and_forget TerminalPage::_ProcessStartupActions()
{
// If there are no actions left, do nothing.
if (actions.Size() == 0)
if (_startupActions.empty())
{
return;
}
@@ -262,20 +256,11 @@ namespace winrt::TerminalApp::implementation
co_await winrt::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal);
if (auto page{ weakThis.get() })
{
for (const auto& action : actions)
for (const auto& action : _startupActions)
{
if (auto page{ weakThis.get() })
{
_actionDispatch->DoAction(action);
}
else
{
return;
}
_actionDispatch->DoAction(action);
}
}
if (initial)
{
_CompleteInitialization();
}
}
@@ -632,13 +617,6 @@ namespace winrt::TerminalApp::implementation
auto newTabImpl = winrt::make_self<Tab>(profileGuid, term);
_tabs.Append(*newTabImpl);
auto themeTabBG = _settings->GlobalSettings().Theme()->TabBackground();
if (themeTabBG.has_value())
{
auto tabColor = _EvaluateThemeColor(*themeTabBG, 0x0);
newTabImpl->SetTabColor(tabColor);
}
// Hookup our event handlers to the new terminal
_RegisterTerminalEvents(term, *newTabImpl);
@@ -879,7 +857,6 @@ namespace winrt::TerminalApp::implementation
_actionDispatch->SetTabColor({ this, &TerminalPage::_HandleSetTabColor });
_actionDispatch->OpenTabColorPicker({ this, &TerminalPage::_HandleOpenTabColorPicker });
_actionDispatch->RenameTab({ this, &TerminalPage::_HandleRenameTab });
_actionDispatch->ExecuteCommandline({ this, &TerminalPage::_HandleExecuteCommandline });
}
// Method Description:
@@ -1387,22 +1364,21 @@ namespace winrt::TerminalApp::implementation
const auto controlConnection = _CreateConnectionFromSettings(realGuid, controlSettings);
const float contentWidth = ::base::saturated_cast<float>(_tabContent.ActualWidth());
const float contentHeight = ::base::saturated_cast<float>(_tabContent.ActualHeight());
const winrt::Windows::Foundation::Size availableSpace{ contentWidth, contentHeight };
const auto canSplit = focusedTab->CanSplitPane(splitType);
auto realSplitType = splitType;
if (realSplitType == SplitState::Automatic)
{
realSplitType = focusedTab->PreCalculateAutoSplit(availableSpace);
}
const auto canSplit = focusedTab->PreCalculateCanSplit(realSplitType, availableSpace);
if (!canSplit)
if (!canSplit && _startupState == StartupState::Initialized)
{
return;
}
auto realSplitType = splitType;
if (realSplitType == SplitState::Automatic && _startupState < StartupState::Initialized)
{
float contentWidth = gsl::narrow_cast<float>(_tabContent.ActualWidth());
float contentHeight = gsl::narrow_cast<float>(_tabContent.ActualHeight());
realSplitType = focusedTab->PreCalculateAutoSplit({ contentWidth, contentHeight });
}
TermControl newControl{ controlSettings, controlConnection };
// Hookup our event handlers to the new terminal
@@ -1944,15 +1920,6 @@ namespace winrt::TerminalApp::implementation
// the alwaysOnTop setting will be lost.
_isAlwaysOnTop = _settings->GlobalSettings().AlwaysOnTop();
_alwaysOnTopChangedHandlers(*this, nullptr);
// THEME
auto themeTabRowBG = _settings->GlobalSettings().Theme()->TabRowBackground();
if (themeTabRowBG.has_value())
{
auto tabRowColor = _EvaluateThemeColor(*themeTabRowBG, 0x0);
Windows::UI::Color accentColor = ColorHelper::GetAccentColor(tabRowColor);
_SetTabRowColor(tabRowColor, accentColor);
}
}
// Method Description:
@@ -1963,13 +1930,9 @@ namespace winrt::TerminalApp::implementation
// - actions: a list of Actions to process on startup.
// Return Value:
// - <none>
void TerminalPage::SetStartupActions(std::vector<winrt::TerminalApp::ActionAndArgs>& actions)
void TerminalPage::SetStartupActions(std::deque<winrt::TerminalApp::ActionAndArgs>& actions)
{
// The fastest way to copy all the actions out of the std::vector and
// put them into a winrt::IVector is by making a copy, then moving the
// copy into the winrt vector ctor.
auto listCopy = actions;
_startupActions = winrt::single_threaded_vector<winrt::TerminalApp::ActionAndArgs>(std::move(listCopy));
_startupActions = actions;
}
winrt::TerminalApp::IDialogPresenter TerminalPage::DialogPresenter() const
@@ -2229,49 +2192,6 @@ namespace winrt::TerminalApp::implementation
// TODO GH#3327: Look at what to do with the NC area when we have XAML theming
}
// Function Description:
// - This is a helper method to get the commandline out of a
// ExecuteCommandline action, break it into subcommands, and attempt to
// parse it into actions. This is used by _HandleExecuteCommandline for
// processing commandlines in the current WT window.
// Arguments:
// - args: the ExecuteCommandlineArgs to synthesize a list of startup actions for.
// Return Value:
// - an empty list if we failed to parse, otherwise a list of actions to execute.
std::vector<winrt::TerminalApp::ActionAndArgs> TerminalPage::ConvertExecuteCommandlineToActions(const TerminalApp::ExecuteCommandlineArgs& args)
{
if (!args || args.Commandline().empty())
{
return {};
}
// Convert the commandline into an array of args with
// CommandLineToArgvW, similar to how the app typically does when
// called from the commandline.
int argc = 0;
wil::unique_any<LPWSTR*, decltype(&::LocalFree), ::LocalFree> argv{ CommandLineToArgvW(args.Commandline().c_str(), &argc) };
if (argv)
{
std::vector<winrt::hstring> args;
// Make sure the first argument is wt.exe, because ParseArgs will
// always skip the program name. The particular value of this first
// string doesn't terribly matter.
args.emplace_back(L"wt.exe");
for (auto& elem : wil::make_range(argv.get(), argc))
{
args.emplace_back(elem);
}
winrt::array_view<const winrt::hstring> argsView{ args };
::TerminalApp::AppCommandlineArgs appArgs;
if (appArgs.ParseArgs(argsView) == 0)
{
return appArgs.GetStartupActions();
}
}
return {};
}
void TerminalPage::_CommandPaletteClosed(const IInspectable& /*sender*/,
const RoutedEventArgs& /*eventArgs*/)
{
@@ -2305,164 +2225,6 @@ namespace winrt::TerminalApp::implementation
return _isAlwaysOnTop;
}
// Method Description:
// - Sets the tab split button color when a new tab color is selected
// - Sets the tab row color when a new tab color is selected
// Arguments:
// - color: The color of the newly selected tab, used to properly calculate
// the foreground color of the split button (to match the font
// color of the tab)
// - accentColor: the actual color we are going to use to paint the tab row and
// split button, so that there is some contrast between the tab
// and the non-client are behind it
// Return Value:
// - <none>
void TerminalPage::_SetTabRowColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor)
{
bool IsBrightColor = ColorHelper::IsBrightColor(color);
bool isLightAccentColor = ColorHelper::IsBrightColor(accentColor);
winrt::Windows::UI::Color pressedColor{};
winrt::Windows::UI::Color hoverColor{};
winrt::Windows::UI::Color foregroundColor{};
const float hoverColorAdjustment = 5.f;
const float pressedColorAdjustment = 7.f;
if (IsBrightColor)
{
foregroundColor = winrt::Windows::UI::Colors::Black();
}
else
{
foregroundColor = winrt::Windows::UI::Colors::White();
}
if (isLightAccentColor)
{
hoverColor = ColorHelper::Darken(accentColor, hoverColorAdjustment);
pressedColor = ColorHelper::Darken(accentColor, pressedColorAdjustment);
}
else
{
hoverColor = ColorHelper::Lighten(accentColor, hoverColorAdjustment);
pressedColor = ColorHelper::Lighten(accentColor, pressedColorAdjustment);
}
Media::SolidColorBrush backgroundBrush{ accentColor };
Media::SolidColorBrush backgroundHoverBrush{ hoverColor };
Media::SolidColorBrush backgroundPressedBrush{ pressedColor };
Media::SolidColorBrush foregroundBrush{ foregroundColor };
_newTabButton.Resources().Insert(winrt::box_value(L"SplitButtonBackground"), backgroundBrush);
_newTabButton.Resources().Insert(winrt::box_value(L"SplitButtonBackgroundPointerOver"), backgroundHoverBrush);
_newTabButton.Resources().Insert(winrt::box_value(L"SplitButtonBackgroundPressed"), backgroundPressedBrush);
_newTabButton.Resources().Insert(winrt::box_value(L"SplitButtonForeground"), foregroundBrush);
_newTabButton.Resources().Insert(winrt::box_value(L"SplitButtonForegroundPointerOver"), foregroundBrush);
_newTabButton.Resources().Insert(winrt::box_value(L"SplitButtonForegroundPressed"), foregroundBrush);
_newTabButton.Background(backgroundBrush);
_newTabButton.Foreground(foregroundBrush);
TabRow().TabView().Background(backgroundBrush);
_TitlebarColorChangedHandlers(*this, nullptr);
}
// Method Description:
// - Clears the tab split button color to a system color
// (or white if none is found) when the tab's color is cleared
// - Clears the tab row color to a system color
// (or white if none is found) when the tab's color is cleared
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_ClearTabRowColor()
{
winrt::hstring keys[] = {
L"SplitButtonBackground",
L"SplitButtonBackgroundPointerOver",
L"SplitButtonBackgroundPressed",
L"SplitButtonForeground",
L"SplitButtonForegroundPointerOver",
L"SplitButtonForegroundPressed"
};
// simply clear any of the colors in the split button's dict
for (auto keyString : keys)
{
auto key = winrt::box_value(keyString);
if (_newTabButton.Resources().HasKey(key))
{
_newTabButton.Resources().Remove(key);
}
}
const auto res = Application::Current().Resources();
const auto defaultBackgroundKey = winrt::box_value(L"TabViewItemHeaderBackground");
const auto defaultForegroundKey = winrt::box_value(L"SystemControlForegroundBaseHighBrush");
winrt::Windows::UI::Xaml::Media::SolidColorBrush backgroundBrush;
winrt::Windows::UI::Xaml::Media::SolidColorBrush foregroundBrush;
if (res.HasKey(defaultBackgroundKey))
{
winrt::Windows::Foundation::IInspectable obj = res.Lookup(defaultBackgroundKey);
backgroundBrush = obj.try_as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>();
}
else
{
backgroundBrush = winrt::Windows::UI::Xaml::Media::SolidColorBrush{ winrt::Windows::UI::Colors::Black() };
}
if (res.HasKey(defaultForegroundKey))
{
winrt::Windows::Foundation::IInspectable obj = res.Lookup(defaultForegroundKey);
foregroundBrush = obj.try_as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>();
}
else
{
foregroundBrush = winrt::Windows::UI::Xaml::Media::SolidColorBrush{ winrt::Windows::UI::Colors::White() };
}
_newTabButton.Background(backgroundBrush);
_newTabButton.Foreground(foregroundBrush);
TabRow().TabView().Background(backgroundBrush);
_TitlebarColorChangedHandlers(*this, nullptr);
}
Windows::UI::Color TerminalPage::TitlebarColor()
{
return TabRow().TabView().Background().as<Windows::UI::Xaml::Media::SolidColorBrush>().Color();
}
til::color TerminalPage::_EvaluateThemeColor(const ::TerminalApp::ThemeColor& themeColor,
const til::color& /*terminalBG*/)
{
if (themeColor.type == ::TerminalApp::ColorType::Value)
{
return themeColor.value.value();
}
else if (themeColor.type == ::TerminalApp::ColorType::Accent)
{
const auto res = winrt::Windows::UI::Xaml::Application::Current().Resources();
const auto accentColorKey = winrt::box_value(L"SystemAccentColor");
if (res.HasKey(accentColorKey))
{
const auto colorFromResources = res.Lookup(accentColorKey);
return winrt::unbox_value_or<winrt::Windows::UI::Color>(colorFromResources, winrt::Windows::UI::Colors::Black());
}
else
{
// DON'T use Transparent here - if it's "Transparent", then it won't
// be able to hittest for clicks.
return winrt::Windows::UI::Colors::Black();
}
}
return 0xff00ff;
}
// -------------------------------- WinRT Events ---------------------------------
// Winrt events need a method for adding a callback to the event and removing the callback.
// These macros will define them both for you.

View File

@@ -56,10 +56,7 @@ namespace winrt::TerminalApp::implementation
bool Fullscreen() const;
bool AlwaysOnTop() const;
Windows::UI::Color TitlebarColor();
void SetStartupActions(std::vector<winrt::TerminalApp::ActionAndArgs>& actions);
static std::vector<winrt::TerminalApp::ActionAndArgs> ConvertExecuteCommandlineToActions(const TerminalApp::ExecuteCommandlineArgs& args);
void SetStartupActions(std::deque<winrt::TerminalApp::ActionAndArgs>& actions);
winrt::TerminalApp::IDialogPresenter DialogPresenter() const;
void DialogPresenter(winrt::TerminalApp::IDialogPresenter dialogPresenter);
@@ -72,7 +69,6 @@ namespace winrt::TerminalApp::implementation
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(FullscreenChanged, _fullscreenChangedHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(AlwaysOnTopChanged, _alwaysOnTopChangedHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(Initialized, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::RoutedEventArgs);
TYPED_EVENT(TitlebarColorChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::RoutedEventArgs);
private:
friend struct TerminalPageT<TerminalPage>; // for Xaml to bind events
@@ -110,8 +106,8 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::UI::Xaml::Controls::Grid::LayoutUpdated_revoker _layoutUpdatedRevoker;
StartupState _startupState{ StartupState::NotInitialized };
Windows::Foundation::Collections::IVector<winrt::TerminalApp::ActionAndArgs> _startupActions;
winrt::fire_and_forget _ProcessStartupActions(Windows::Foundation::Collections::IVector<winrt::TerminalApp::ActionAndArgs> actions, const bool initial);
std::deque<winrt::TerminalApp::ActionAndArgs> _startupActions;
winrt::fire_and_forget _ProcessStartupActions();
void _ShowAboutDialog();
void _ShowCloseWarningDialog();
@@ -194,10 +190,6 @@ namespace winrt::TerminalApp::implementation
void _CommandPaletteClosed(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
void _SetTabRowColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor);
void _ClearTabRowColor();
til::color _EvaluateThemeColor(const ::TerminalApp::ThemeColor& themeColor, const til::color& terminalBG);
#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
void _HandleOpenNewTabDropdown(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
@@ -229,7 +221,6 @@ namespace winrt::TerminalApp::implementation
void _HandleSetTabColor(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleOpenTabColorPicker(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleRenameTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleExecuteCommandline(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleToggleCommandPalette(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
// Make sure to hook new actions up in _RegisterActionCallbacks!
#pragma endregion

View File

@@ -22,8 +22,6 @@ namespace TerminalApp
Boolean Fullscreen { get; };
Boolean AlwaysOnTop { get; };
Windows.UI.Color TitlebarColor { get; };
// We cannot use the default XAML APIs because we want to make sure
// that there's only one application-global dialog visible at a time,
// and because of GH#5224.
@@ -36,6 +34,5 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> FullscreenChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> AlwaysOnTopChanged;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.RoutedEventArgs> Initialized;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.RoutedEventArgs> TitlebarColorChanged;
}
}

View File

@@ -1,298 +0,0 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- TerminalSettingsSerializationHelpers.h
Abstract:
- Specializations of the JsonUtils helpers for things that might end up in a
settings document.
--*/
#pragma once
#include "pch.h"
#include "JsonUtils.h"
#include "SettingsTypes.h"
#include <winrt/Microsoft.Terminal.Settings.h>
#include <winrt/TerminalApp.h>
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::CursorStyle)
{
static constexpr std::array<pair_type, 5> mappings = {
pair_type{ "bar", ValueType::Bar },
pair_type{ "vintage", ValueType::Vintage },
pair_type{ "underscore", ValueType::Underscore },
pair_type{ "filledBox", ValueType::FilledBox },
pair_type{ "emptyBox", ValueType::EmptyBox }
};
};
JSON_ENUM_MAPPER(::winrt::Windows::UI::Xaml::Media::Stretch)
{
static constexpr std::array<pair_type, 4> mappings = {
pair_type{ "uniformToFill", ValueType::UniformToFill },
pair_type{ "none", ValueType::None },
pair_type{ "fill", ValueType::Fill },
pair_type{ "uniform", ValueType::Uniform }
};
};
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::ScrollbarState)
{
static constexpr std::array<pair_type, 2> mappings = {
pair_type{ "visible", ValueType::Visible },
pair_type{ "hidden", ValueType::Hidden }
};
};
JSON_ENUM_MAPPER(std::tuple<::winrt::Windows::UI::Xaml::HorizontalAlignment, ::winrt::Windows::UI::Xaml::VerticalAlignment>)
{
// reduce repetition
using HA = ::winrt::Windows::UI::Xaml::HorizontalAlignment;
using VA = ::winrt::Windows::UI::Xaml::VerticalAlignment;
static constexpr std::array<pair_type, 9> mappings = {
pair_type{ "center", std::make_tuple(HA::Center, VA::Center) },
pair_type{ "topLeft", std::make_tuple(HA::Left, VA::Top) },
pair_type{ "bottomLeft", std::make_tuple(HA::Left, VA::Bottom) },
pair_type{ "left", std::make_tuple(HA::Left, VA::Center) },
pair_type{ "topRight", std::make_tuple(HA::Right, VA::Top) },
pair_type{ "bottomRight", std::make_tuple(HA::Right, VA::Bottom) },
pair_type{ "right", std::make_tuple(HA::Right, VA::Center) },
pair_type{ "top", std::make_tuple(HA::Center, VA::Top) },
pair_type{ "bottom", std::make_tuple(HA::Center, VA::Bottom) }
};
};
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::TextAntialiasingMode)
{
static constexpr std::array<pair_type, 3> mappings = {
pair_type{ "grayscale", ValueType::Grayscale },
pair_type{ "cleartype", ValueType::Cleartype },
pair_type{ "aliased", ValueType::Aliased }
};
};
// Type Description:
// - Helper for converting a user-specified closeOnExit value to its corresponding enum
JSON_ENUM_MAPPER(::TerminalApp::CloseOnExitMode)
{
JSON_MAPPINGS(3) = {
pair_type{ "always", ValueType::Always },
pair_type{ "graceful", ValueType::Graceful },
pair_type{ "never", ValueType::Never },
};
// Override mapping parser to add boolean parsing
CloseOnExitMode FromJson(const Json::Value& json)
{
if (json.isBool())
{
return json.asBool() ? ValueType::Graceful : ValueType::Never;
}
return EnumMapper::FromJson(json);
}
bool CanConvert(const Json::Value& json)
{
return EnumMapper::CanConvert(json) || json.isBool();
}
};
// This specialization isn't using JSON_ENUM_MAPPER because we need to have a different
// value type (unsinged int) and return type (FontWeight struct). JSON_ENUM_MAPPER
// expects that the value type _is_ the return type.
template<>
struct ::TerminalApp::JsonUtils::ConversionTrait<::winrt::Windows::UI::Text::FontWeight> :
public ::TerminalApp::JsonUtils::EnumMapper<
unsigned int,
::TerminalApp::JsonUtils::ConversionTrait<::winrt::Windows::UI::Text::FontWeight>>
{
// The original parser used the font weight getters Bold(), Normal(), etc.
// They were both cumbersome and *not constant expressions*
JSON_MAPPINGS(11) = {
pair_type{ "thin", 100u },
pair_type{ "extra-light", 200u },
pair_type{ "light", 300u },
pair_type{ "semi-light", 350u },
pair_type{ "normal", 400u },
pair_type{ "medium", 500u },
pair_type{ "semi-bold", 600u },
pair_type{ "bold", 700u },
pair_type{ "extra-bold", 800u },
pair_type{ "black", 900u },
pair_type{ "extra-black", 950u },
};
// Override mapping parser to add boolean parsing
auto FromJson(const Json::Value& json)
{
unsigned int value{ 400 };
if (json.isUInt())
{
value = json.asUInt();
}
else
{
value = BaseEnumMapper::FromJson(json);
}
::winrt::Windows::UI::Text::FontWeight weight{
static_cast<uint16_t>(std::clamp(value, 100u, 990u))
};
return weight;
}
bool CanConvert(const Json::Value& json)
{
return BaseEnumMapper::CanConvert(json) || json.isUInt();
}
};
JSON_ENUM_MAPPER(::winrt::Windows::UI::Xaml::ElementTheme)
{
JSON_MAPPINGS(3) = {
pair_type{ "system", ValueType::Default },
pair_type{ "light", ValueType::Light },
pair_type{ "dark", ValueType::Dark },
};
};
JSON_ENUM_MAPPER(::winrt::TerminalApp::LaunchMode)
{
JSON_MAPPINGS(3) = {
pair_type{ "default", ValueType::DefaultMode },
pair_type{ "maximized", ValueType::MaximizedMode },
pair_type{ "fullscreen", ValueType::FullscreenMode },
};
};
JSON_ENUM_MAPPER(::winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode)
{
JSON_MAPPINGS(3) = {
pair_type{ "equal", ValueType::Equal },
pair_type{ "titleLength", ValueType::SizeToContent },
pair_type{ "compact", ValueType::Compact },
};
};
// Type Description:
// - Helper for converting the initial position string into
// 2 coordinate values. We allow users to only provide one coordinate,
// thus, we use comma as the separator:
// (100, 100): standard input string
// (, 100), (100, ): if a value is missing, we set this value as a default
// (,): both x and y are set to default
// (abc, 100): if a value is not valid, we treat it as default
// (100, 100, 100): we only read the first two values, this is equivalent to (100, 100)
template<>
struct ::TerminalApp::JsonUtils::ConversionTrait<::TerminalApp::LaunchPosition>
{
::TerminalApp::LaunchPosition FromJson(const Json::Value& json)
{
::TerminalApp::LaunchPosition ret;
std::string initialPosition{ json.asString() };
static constexpr char singleCharDelim = ',';
std::stringstream tokenStream(initialPosition);
std::string token;
uint8_t initialPosIndex = 0;
// Get initial position values till we run out of delimiter separated values in the stream
// or we hit max number of allowable values (= 2)
// Non-numeral values or empty string will be caught as exception and we do not assign them
for (; std::getline(tokenStream, token, singleCharDelim) && (initialPosIndex < 2); initialPosIndex++)
{
try
{
int32_t position = std::stoi(token);
if (initialPosIndex == 0)
{
ret.x.emplace(position);
}
if (initialPosIndex == 1)
{
ret.y.emplace(position);
}
}
catch (...)
{
// Do nothing
}
}
return ret;
}
bool CanConvert(const Json::Value& json)
{
return json.isString();
}
};
// Possible Direction values
JSON_ENUM_MAPPER(::winrt::TerminalApp::Direction)
{
JSON_MAPPINGS(4) = {
pair_type{ "left", ValueType::Left },
pair_type{ "right", ValueType::Right },
pair_type{ "up", ValueType::Up },
pair_type{ "down", ValueType::Down },
};
};
// Possible SplitState values
JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitState)
{
JSON_MAPPINGS(3) = {
pair_type{ "vertical", ValueType::Vertical },
pair_type{ "horizontal", ValueType::Horizontal },
pair_type{ "auto", ValueType::Automatic },
};
};
// Possible SplitType values
JSON_ENUM_MAPPER(::winrt::TerminalApp::SplitType)
{
JSON_MAPPINGS(1) = {
pair_type{ "duplicate", ValueType::Duplicate },
};
};
JSON_ENUM_MAPPER(::winrt::TerminalApp::SettingsTarget)
{
JSON_MAPPINGS(3) = {
pair_type{ "settingsFile", ValueType::SettingsFile },
pair_type{ "defaultsFile", ValueType::DefaultsFile },
pair_type{ "allFiles", ValueType::AllFiles },
};
};
template<>
struct ::TerminalApp::JsonUtils::ConversionTrait<::TerminalApp::ThemeColor>
{
::TerminalApp::ThemeColor FromJson(const Json::Value& json)
{
::TerminalApp::ThemeColor ret;
std::string str{ json.asString() };
if (str == "accent")
{
ret.type = ::TerminalApp::ColorType::Accent;
}
else
{
ret.type = ::TerminalApp::ColorType::Value;
const auto value{ JsonUtils::GetValue<til::color>(json) };
ret.value = value;
}
return ret;
}
bool CanConvert(const Json::Value& json)
{
return json.isString();
}
};

View File

@@ -1,104 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Theme.h"
#include "DefaultSettings.h"
#include "../../types/inc/Utils.hpp"
#include "Utils.h"
#include "JsonUtils.h"
#include "TerminalSettingsSerializationHelpers.h"
using namespace ::Microsoft::Console;
using namespace TerminalApp;
using namespace winrt::Microsoft::Terminal::Settings;
static constexpr std::string_view NameKey{ "name" };
static constexpr std::string_view WindowApplicationThemeKey{ "window.applicationTheme" };
// static constexpr std::string_view BackgroundKey{ "background" };
static constexpr std::string_view TabRowBackgroundKey{ "tabRow.background" };
static constexpr std::string_view TabBackgroundKey{ "tab.background" };
Theme::Theme()
{
}
Theme::~Theme()
{
}
// Method Description:
// - Apply our values to the given TerminalSettings object. Sets the foreground,
// background, and color table of the settings object.
// Arguments:
// - terminalSettings: the object to apply our settings to.
// Return Value:
// - <none>
void Theme::ApplyTheme(TerminalSettings terminalSettings) const
{
}
// Method Description:
// - Create a new instance of this class from a serialized JsonObject.
// Arguments:
// - json: an object which should be a serialization of a Theme object.
// Return Value:
// - a new Theme instance created from the values in `json`
Theme Theme::FromJson(const Json::Value& json)
{
Theme result;
result.LayerJson(json);
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 Theme::ShouldBeLayered(const Json::Value& json) const
{
std::wstring nameFromJson{};
if (JsonUtils::GetValueForKey(json, NameKey, nameFromJson))
{
return nameFromJson == _Name;
}
return false;
}
// Method Description:
// - 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
// given object, we'll parse them and replace our settings with values from
// the new json object. Properties that _aren't_ in the json object will _not_
// be replaced.
// Arguments:
// - json: an object which should be a partial serialization of a Theme object.
// Return Value:
// <none>
void Theme::LayerJson(const Json::Value& json)
{
JsonUtils::GetValueForKey(json, NameKey, _Name);
JsonUtils::GetValueForKey(json, WindowApplicationThemeKey, _ApplicationTheme);
// JsonUtils::GetValueForKey(json, ForegroundKey, _defaultForeground);
JsonUtils::GetValueForKey(json, TabRowBackgroundKey, _TabRowBackground);
JsonUtils::GetValueForKey(json, TabBackgroundKey, _TabBackground);
}
// Method Description:
// - Parse the name from the JSON representation of a Theme.
// Arguments:
// - json: an object which should be a serialization of a Theme 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> Theme::GetNameFromJson(const Json::Value& json)
{
return JsonUtils::GetValueForKey<std::optional<std::wstring>>(json, NameKey);
}

View File

@@ -1,55 +0,0 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- Theme.h
Abstract:
- TODO
Author(s):
- Mike Griese - July 2020
--*/
#pragma once
#include <winrt/Microsoft.Terminal.Settings.h>
#include "../../inc/conattrs.hpp"
#include "../inc/cppwinrt_utils.h"
#include "SettingsTypes.h"
// fwdecl unittest classes
namespace TerminalAppLocalTests
{
class SettingsTests;
class ColorSchemeTests;
};
namespace TerminalApp
{
class Theme;
};
class TerminalApp::Theme final
{
public:
Theme();
~Theme();
void ApplyTheme(winrt::Microsoft::Terminal::Settings::TerminalSettings terminalSettings) const;
static Theme FromJson(const Json::Value& json);
bool ShouldBeLayered(const Json::Value& json) const;
void LayerJson(const Json::Value& json);
static std::optional<std::wstring> GetNameFromJson(const Json::Value& json);
GETSET_PROPERTY(winrt::hstring, Name);
GETSET_PROPERTY(winrt::Windows::UI::Xaml::ElementTheme, ApplicationTheme, winrt::Windows::UI::Xaml::ElementTheme::Default);
GETSET_PROPERTY(std::optional<::TerminalApp::ThemeColor>, TabRowBackground);
GETSET_PROPERTY(std::optional<::TerminalApp::ThemeColor>, TabBackground);
private:
friend class TerminalAppLocalTests::SettingsTests;
friend class TerminalAppLocalTests::ColorSchemeTests;
};

View File

@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Utils.h"
// Method Description:
// - Constructs a wstring from a given Json::Value object. Reads the object as
// a std::string using asString, then builds an hstring from that std::string,
// then converts that hstring into a std::wstring.
// Arguments:
// - json: the Json::Value to parse as a string
// Return Value:
// - the wstring equivalent of the value in json
std::wstring GetWstringFromJson(const Json::Value& json)
{
return winrt::to_hstring(json.asString()).c_str();
}

View File

@@ -13,6 +13,8 @@ Author(s):
--*/
#pragma once
std::wstring GetWstringFromJson(const Json::Value& json);
// Method Description:
// - Create a std::string from a string_view. We do this because we can't look
// up a key in a Json::Value with a string_view directly, so instead we'll use

View File

@@ -187,7 +187,7 @@
"foreground": "#839496",
"background": "#002B36",
"cursorColor": "#FFFFFF",
"black": "#002B36",
"black": "#073642",
"red": "#DC322F",
"green": "#859900",
"yellow": "#B58900",
@@ -195,7 +195,7 @@
"purple": "#D33682",
"cyan": "#2AA198",
"white": "#EEE8D5",
"brightBlack": "#073642",
"brightBlack": "#002B36",
"brightRed": "#CB4B16",
"brightGreen": "#586E75",
"brightYellow": "#657B83",
@@ -209,7 +209,7 @@
"foreground": "#657B83",
"background": "#FDF6E3",
"cursorColor": "#002B36",
"black": "#002B36",
"black": "#073642",
"red": "#DC322F",
"green": "#859900",
"yellow": "#B58900",
@@ -217,7 +217,7 @@
"purple": "#D33682",
"cyan": "#2AA198",
"white": "#EEE8D5",
"brightBlack": "#073642",
"brightBlack": "#002B36",
"brightRed": "#CB4B16",
"brightGreen": "#586E75",
"brightYellow": "#657B83",
@@ -271,21 +271,6 @@
"brightWhite": "#EEEEEC"
}
],
"themes":
[
{
"name": "system",
"window.applicationTheme": "system",
},
{
"name": "dark",
"window.applicationTheme": "dark",
},
{
"name": "light",
"window.applicationTheme": "light",
}
],
"bindings":
[
// Application-level Keys

View File

@@ -102,7 +102,6 @@
</ClInclude>
<ClInclude Include="../Pane.h" />
<ClInclude Include="../ColorScheme.h" />
<ClInclude Include="../Theme.h" />
<ClInclude Include="../GlobalAppSettings.h" />
<ClInclude Include="../Profile.h" />
<ClInclude Include="../CascadiaSettings.h" />
@@ -110,7 +109,6 @@
<ClInclude Include="../JsonUtils.h" />
<ClInclude Include="../Utils.h" />
<ClInclude Include="../DefaultProfileUtils.h" />
<ClInclude Include="../TerminalSettingsSerializationHelpers.h" />
<ClInclude Include="../TerminalWarnings.h" />
<ClInclude Include="../IDynamicProfileGenerator.h" />
<ClInclude Include="../PowershellCoreProfileGenerator.h" />
@@ -174,13 +172,14 @@
</ClCompile>
<ClCompile Include="../Pane.cpp" />
<ClCompile Include="../ColorScheme.cpp" />
<ClCompile Include="../Theme.cpp" />
<ClCompile Include="../GlobalAppSettings.cpp" />
<ClCompile Include="../Profile.cpp" />
<ClCompile Include="../CascadiaSettings.cpp" />
<ClCompile Include="../CascadiaSettingsSerialization.cpp" />
<ClCompile Include="../AppKeyBindingsSerialization.cpp" />
<ClCompile Include="../KeyChordSerialization.cpp" />
<ClCompile Include="../JsonUtils.cpp" />
<ClCompile Include="../Utils.cpp" />
<ClCompile Include="../DefaultProfileUtils.cpp" />
<ClCompile Include="../PowershellCoreProfileGenerator.cpp" />
<ClCompile Include="../WslDistroGenerator.cpp" />

View File

@@ -8,6 +8,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="../init.cpp" />
<ClCompile Include="../Utils.cpp" />
<ClCompile Include="pch.cpp" />
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="../AzureCloudShellGenerator.cpp">
@@ -49,6 +50,9 @@
<ClCompile Include="$(OpenConsoleDir)\dep\jsoncpp\jsoncpp.cpp">
<Filter>json</Filter>
</ClCompile>
<ClCompile Include="../JsonUtils.cpp">
<Filter>json</Filter>
</ClCompile>
<ClCompile Include="../Tab.cpp">
<Filter>tab</Filter>
</ClCompile>
@@ -59,7 +63,7 @@
<ClCompile Include="../Commandline.cpp" />
<ClCompile Include="../ColorHelper.cpp" />
<ClCompile Include="../DebugTapConnection.cpp" />
<ClCompile Include="../Theme.cpp">
<ClCompile Include="../CommandSerialization.cpp">
<Filter>settings</Filter>
</ClCompile>
</ItemGroup>
@@ -88,9 +92,6 @@
<ClInclude Include="../GlobalAppSettings.h">
<Filter>settings</Filter>
</ClInclude>
<ClInclude Include="../TerminalSettingsSerializationHelpers.h">
<Filter>settings</Filter>
</ClInclude>
<ClInclude Include="../KeyChordSerialization.h">
<Filter>settings</Filter>
</ClInclude>
@@ -119,7 +120,7 @@
<ClInclude Include="../TelnetGenerator.h">
<Filter>profileGeneration</Filter>
</ClInclude>
<ClInclude Include="../Theme.h">
<ClInclude Include="../CommandSerialization.h">
<Filter>settings</Filter>
</ClInclude>
</ItemGroup>
@@ -139,11 +140,10 @@
<Midl Include="../Tab.idl">
<Filter>tab</Filter>
</Midl>
<Midl Include="../IF7Listener.idl" />
<Midl Include="../Command.idl">
<Filter>commandPalette</Filter>
</Midl>
<Midl Include="../IDirectKeyListener.idl" />
<Midl Include="../CommandKeyChordVisibilityConverter.idl" />
</ItemGroup>
<ItemGroup>
<None Include="../packages.config" />

View File

@@ -29,7 +29,6 @@
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.Metadata.h>
#include <winrt/Windows.Graphics.Display.h>
#include <winrt/windows.ui.core.h>
#include <winrt/Windows.ui.input.h>
#include <winrt/Windows.UI.Text.h>

View File

@@ -17,7 +17,6 @@
using namespace ::Microsoft::Console::Types;
using namespace ::Microsoft::Terminal::Core;
using namespace winrt::Windows::Graphics::Display;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Input;
using namespace winrt::Windows::UI::Xaml::Automation::Peers;
@@ -629,7 +628,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
// Then, using the font, get the number of characters that can fit.
// Resize our terminal connection to match that size, and initialize the terminal with that size.
const auto viewInPixels = Viewport::FromDimensions({ 0, 0 }, windowSize);
LOG_IF_FAILED(dxEngine->SetWindowSize({ viewInPixels.Width(), viewInPixels.Height() }));
THROW_IF_FAILED(dxEngine->SetWindowSize({ viewInPixels.Width(), viewInPixels.Height() }));
// Update DxEngine's SelectionBackground
dxEngine->SetSelectionBackground(_settings.SelectionBackground());
@@ -2275,65 +2274,28 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
// as font size, scrollbar and other control scaling, etc. Make sure the
// caller knows what monitor the control is about to appear on.
// Return Value:
// - a size containing the requested dimensions in pixels.
winrt::Windows::Foundation::Size TermControl::GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi)
// - a point containing the requested dimensions in pixels.
winrt::Windows::Foundation::Point TermControl::GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi)
{
// If the settings have negative or zero row or column counts, ignore those counts.
// (The lower TerminalCore layer also has upper bounds as well, but at this layer
// we may eventually impose different ones depending on how many pixels we can address.)
const auto cols = ::base::saturated_cast<float>(std::max(settings.InitialCols(), 1));
const auto rows = ::base::saturated_cast<float>(std::max(settings.InitialRows(), 1));
const winrt::Windows::Foundation::Size initialSize{ cols, rows };
return GetProposedDimensions(initialSize,
settings.FontSize(),
settings.FontWeight(),
settings.FontFace(),
settings.ScrollState(),
settings.Padding(),
dpi);
}
// Function Description:
// - Determines how much space (in pixels) an app would need to reserve to
// create a control with the settings stored in the settings param. This
// accounts for things like the font size and face, the initialRows and
// initialCols, and scrollbar visibility. The returned sized is based upon
// the provided DPI value
// Arguments:
// - initialSizeInChars: The size to get the proposed dimensions for.
// - fontHeight: The font height to use to calculate the proposed size for.
// - fontWeight: The font weight to use to calculate the proposed size for.
// - fontFace: The font name to use to calculate the proposed size for.
// - scrollState: The ScrollbarState to use to calculate the proposed size for.
// - padding: The padding to use to calculate the proposed size for.
// - dpi: The DPI we should create the terminal at. This affects things such
// as font size, scrollbar and other control scaling, etc. Make sure the
// caller knows what monitor the control is about to appear on.
// Return Value:
// - a size containing the requested dimensions in pixels.
winrt::Windows::Foundation::Size TermControl::GetProposedDimensions(const winrt::Windows::Foundation::Size& initialSizeInChars,
const int32_t& fontHeight,
const winrt::Windows::UI::Text::FontWeight& fontWeight,
const winrt::hstring& fontFace,
const Microsoft::Terminal::Settings::ScrollbarState& scrollState,
const winrt::hstring& padding,
const uint32_t dpi)
{
const auto cols = ::base::saturated_cast<int>(initialSizeInChars.Width);
const auto rows = ::base::saturated_cast<int>(initialSizeInChars.Height);
// Initialize our font information.
const auto fontFace = settings.FontFace();
const short fontHeight = gsl::narrow_cast<short>(settings.FontSize());
const auto fontWeight = settings.FontWeight();
// The font width doesn't terribly matter, we'll only be using the
// height to look it up
// The other params here also largely don't matter.
// The family is only used to determine if the font is truetype or
// not, but DX doesn't use that info at all.
// The Codepage is additionally not actually used by the DX engine at all.
FontInfo actualFont = { fontFace, 0, fontWeight.Weight, { 0, gsl::narrow_cast<short>(fontHeight) }, CP_UTF8, false };
FontInfo actualFont = { fontFace, 0, fontWeight.Weight, { 0, fontHeight }, CP_UTF8, false };
FontInfoDesired desiredFont = { actualFont };
// If the settings have negative or zero row or column counts, ignore those counts.
// (The lower TerminalCore layer also has upper bounds as well, but at this layer
// we may eventually impose different ones depending on how many pixels we can address.)
const auto cols = std::max(settings.InitialCols(), 1);
const auto rows = std::max(settings.InitialRows(), 1);
// Create a DX engine and initialize it with our font and DPI. We'll
// then use it to measure how much space the requested rows and columns
// will take up.
@@ -2353,13 +2315,13 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
double width = cols * fontSize.X;
// Reserve additional space if scrollbar is intended to be visible
if (scrollState == ScrollbarState::Visible)
if (settings.ScrollState() == ScrollbarState::Visible)
{
width += scrollbarSize;
}
double height = rows * fontSize.Y;
auto thickness = _ParseThicknessFromPadding(padding);
auto thickness = _ParseThicknessFromPadding(settings.Padding());
// GH#2061 - make sure to account for the size the padding _will be_ scaled to
width += scale * (thickness.Left + thickness.Right);
height += scale * (thickness.Top + thickness.Bottom);
@@ -2392,41 +2354,21 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
// have a visible character.
winrt::Windows::Foundation::Size TermControl::MinimumSize()
{
if (_initializedTerminal)
const auto fontSize = _actualFont.GetSize();
double width = fontSize.X;
double height = fontSize.Y;
// Reserve additional space if scrollbar is intended to be visible
if (_settings.ScrollState() == ScrollbarState::Visible)
{
const auto fontSize = _actualFont.GetSize();
double width = fontSize.X;
double height = fontSize.Y;
// Reserve additional space if scrollbar is intended to be visible
if (_settings.ScrollState() == ScrollbarState::Visible)
{
width += ScrollBar().ActualWidth();
}
// Account for the size of any padding
const auto padding = GetPadding();
width += padding.Left + padding.Right;
height += padding.Top + padding.Bottom;
return { gsl::narrow_cast<float>(width), gsl::narrow_cast<float>(height) };
}
else
{
// If the terminal hasn't been initialized yet, then the font size will
// have dimensions {1, fontSize.Y}, which can mess with consumers of
// this method. In that case, we'll need to pre-calculate the font
// width, before we actually have a renderer or swapchain.
const winrt::Windows::Foundation::Size minSize{ 1, 1 };
const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
const auto dpi = ::base::saturated_cast<uint32_t>(USER_DEFAULT_SCREEN_DPI * scaleFactor);
return GetProposedDimensions(minSize,
_settings.FontSize(),
_settings.FontWeight(),
_settings.FontFace(),
_settings.ScrollState(),
_settings.Padding(),
dpi);
width += ScrollBar().ActualWidth();
}
// Account for the size of any padding
const auto padding = GetPadding();
width += padding.Left + padding.Right;
height += padding.Top + padding.Bottom;
return { gsl::narrow_cast<float>(width), gsl::narrow_cast<float>(height) };
}
// Method Description:

View File

@@ -100,14 +100,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
TerminalConnection::ConnectionState ConnectionState() const;
static Windows::Foundation::Size GetProposedDimensions(Microsoft::Terminal::Settings::IControlSettings const& settings, const uint32_t dpi);
static Windows::Foundation::Size GetProposedDimensions(const winrt::Windows::Foundation::Size& initialSizeInChars,
const int32_t& fontSize,
const winrt::Windows::UI::Text::FontWeight& fontWeight,
const winrt::hstring& fontFace,
const Microsoft::Terminal::Settings::ScrollbarState& scrollState,
const winrt::hstring& padding,
const uint32_t dpi);
static Windows::Foundation::Point GetProposedDimensions(Microsoft::Terminal::Settings::IControlSettings const& settings, const uint32_t dpi);
// clang-format off
// -------------------------------- WinRT Events ---------------------------------

View File

@@ -35,7 +35,7 @@ namespace Microsoft.Terminal.TerminalControl
TermControl();
TermControl(Microsoft.Terminal.Settings.IControlSettings settings, Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
static Windows.Foundation.Size GetProposedDimensions(Microsoft.Terminal.Settings.IControlSettings settings, UInt32 dpi);
static Windows.Foundation.Point GetProposedDimensions(Microsoft.Terminal.Settings.IControlSettings settings, UInt32 dpi);
void UpdateSettings(Microsoft.Terminal.Settings.IControlSettings newSettings);

View File

@@ -29,7 +29,7 @@ ThrottledFunc<>::ThrottledFunc(ThrottledFunc::Func func, TimeSpan delay, CoreDis
// - <none>
void ThrottledFunc<>::Run()
{
if (_isRunPending.test_and_set(std::memory_order_acquire))
if (_isRunPending.test_and_set())
{
// already pending
return;
@@ -44,7 +44,7 @@ void ThrottledFunc<>::Run()
if (auto self{ weakThis.lock() })
{
timer.Stop();
self->_isRunPending.clear(std::memory_order_release);
self->_isRunPending.clear();
self->_func();
}
});

View File

@@ -354,12 +354,12 @@ bool TerminalDispatch::EnableAlternateScroll(const bool enabled) noexcept
return true;
}
bool TerminalDispatch::SetPrivateModes(const gsl::span<const DispatchTypes::PrivateModeParams> params) noexcept
bool TerminalDispatch::SetPrivateModes(const std::basic_string_view<DispatchTypes::PrivateModeParams> params) noexcept
{
return _SetResetPrivateModes(params, true);
}
bool TerminalDispatch::ResetPrivateModes(const gsl::span<const DispatchTypes::PrivateModeParams> params) noexcept
bool TerminalDispatch::ResetPrivateModes(const std::basic_string_view<DispatchTypes::PrivateModeParams> params) noexcept
{
return _SetResetPrivateModes(params, false);
}
@@ -374,7 +374,7 @@ bool TerminalDispatch::ResetPrivateModes(const gsl::span<const DispatchTypes::Pr
// - enable - True for set, false for unset.
// Return Value:
// - True if ALL params were handled successfully. False otherwise.
bool TerminalDispatch::_SetResetPrivateModes(const gsl::span<const DispatchTypes::PrivateModeParams> params, const bool enable) noexcept
bool TerminalDispatch::_SetResetPrivateModes(const std::basic_string_view<DispatchTypes::PrivateModeParams> params, const bool enable) noexcept
{
// because the user might chain together params we don't support with params we DO support, execute all
// params in the sequence, and only return failure if we failed at least one of them

View File

@@ -13,7 +13,7 @@ public:
void Print(const wchar_t wchPrintable) noexcept override;
void PrintString(const std::wstring_view string) noexcept override;
bool SetGraphicsRendition(const gsl::span<const ::Microsoft::Console::VirtualTerminal::DispatchTypes::GraphicsOptions> options) noexcept override;
bool SetGraphicsRendition(const std::basic_string_view<::Microsoft::Console::VirtualTerminal::DispatchTypes::GraphicsOptions> options) noexcept override;
bool CursorPosition(const size_t line,
const size_t column) noexcept override; // CUP
@@ -59,16 +59,16 @@ public:
bool EnableAnyEventMouseMode(const bool enabled) noexcept override; // ?1003
bool EnableAlternateScroll(const bool enabled) noexcept override; // ?1007
bool SetPrivateModes(const gsl::span<const ::Microsoft::Console::VirtualTerminal::DispatchTypes::PrivateModeParams> /*params*/) noexcept override; // DECSET
bool ResetPrivateModes(const gsl::span<const ::Microsoft::Console::VirtualTerminal::DispatchTypes::PrivateModeParams> /*params*/) noexcept override; // DECRST
bool SetPrivateModes(const std::basic_string_view<::Microsoft::Console::VirtualTerminal::DispatchTypes::PrivateModeParams> /*params*/) noexcept override; // DECSET
bool ResetPrivateModes(const std::basic_string_view<::Microsoft::Console::VirtualTerminal::DispatchTypes::PrivateModeParams> /*params*/) noexcept override; // DECRST
private:
::Microsoft::Terminal::Core::ITerminalApi& _terminalApi;
size_t _SetRgbColorsHelper(const gsl::span<const ::Microsoft::Console::VirtualTerminal::DispatchTypes::GraphicsOptions> options,
size_t _SetRgbColorsHelper(const std::basic_string_view<::Microsoft::Console::VirtualTerminal::DispatchTypes::GraphicsOptions> options,
TextAttribute& attr,
const bool isForeground) noexcept;
bool _SetResetPrivateModes(const gsl::span<const ::Microsoft::Console::VirtualTerminal::DispatchTypes::PrivateModeParams> params, const bool enable) noexcept;
bool _SetResetPrivateModes(const std::basic_string_view<::Microsoft::Console::VirtualTerminal::DispatchTypes::PrivateModeParams> params, const bool enable) noexcept;
bool _PrivateModeParamsHelper(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::PrivateModeParams param, const bool enable) noexcept;
};

View File

@@ -41,7 +41,7 @@ const BYTE BRIGHT_WHITE = BRIGHT_ATTR | RED_ATTR | GREEN_ATTR | BLUE_ATTR;
// - isForeground - Whether or not the parsed color is for the foreground.
// Return Value:
// - The number of options consumed, not including the initial 38/48.
size_t TerminalDispatch::_SetRgbColorsHelper(const gsl::span<const DispatchTypes::GraphicsOptions> options,
size_t TerminalDispatch::_SetRgbColorsHelper(const std::basic_string_view<DispatchTypes::GraphicsOptions> options,
TextAttribute& attr,
const bool isForeground) noexcept
{
@@ -94,7 +94,7 @@ size_t TerminalDispatch::_SetRgbColorsHelper(const gsl::span<const DispatchTypes
// one at a time by setting or removing flags in the font style properties.
// Return Value:
// - True if handled successfully. False otherwise.
bool TerminalDispatch::SetGraphicsRendition(const gsl::span<const DispatchTypes::GraphicsOptions> options) noexcept
bool TerminalDispatch::SetGraphicsRendition(const std::basic_string_view<DispatchTypes::GraphicsOptions> options) noexcept
{
TextAttribute attr = _terminalApi.GetTextAttributes();
@@ -126,10 +126,10 @@ bool TerminalDispatch::SetGraphicsRendition(const gsl::span<const DispatchTypes:
attr.SetFaint(false);
break;
case Italics:
attr.SetItalic(true);
attr.SetItalics(true);
break;
case NotItalics:
attr.SetItalic(false);
attr.SetItalics(false);
break;
case BlinkOrXterm256Index:
attr.SetBlinking(true);
@@ -156,16 +156,16 @@ bool TerminalDispatch::SetGraphicsRendition(const gsl::span<const DispatchTypes:
attr.SetReverseVideo(false);
break;
case Underline:
attr.SetUnderlined(true);
attr.SetUnderline(true);
break;
case NoUnderline:
attr.SetUnderlined(false);
attr.SetUnderline(false);
break;
case Overline:
attr.SetOverlined(true);
attr.SetOverline(true);
break;
case NoOverline:
attr.SetOverlined(false);
attr.SetOverline(false);
break;
case ForegroundBlack:
attr.SetIndexedForeground(DARK_BLACK);
@@ -264,10 +264,10 @@ bool TerminalDispatch::SetGraphicsRendition(const gsl::span<const DispatchTypes:
attr.SetIndexedBackground(BRIGHT_WHITE);
break;
case ForegroundExtended:
i += _SetRgbColorsHelper(options.subspan(i + 1), attr, true);
i += _SetRgbColorsHelper(options.substr(i + 1), attr, true);
break;
case BackgroundExtended:
i += _SetRgbColorsHelper(options.subspan(i + 1), attr, false);
i += _SetRgbColorsHelper(options.substr(i + 1), attr, false);
break;
}
}

View File

@@ -160,7 +160,6 @@ void AppHost::Initialize()
_logic.FullscreenChanged({ this, &AppHost::_FullscreenChanged });
_logic.FocusModeChanged({ this, &AppHost::_FocusModeChanged });
_logic.AlwaysOnTopChanged({ this, &AppHost::_AlwaysOnTopChanged });
_logic.TitlebarColorChanged({ this, &AppHost::_TitlebarColorChanged });
_logic.Create();
@@ -287,9 +286,9 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, winrt::Ter
auto initialSize = _logic.GetLaunchDimensions(dpix);
const short islandWidth = Utils::ClampToShortMax(
static_cast<long>(ceil(initialSize.Width)), 1);
static_cast<long>(ceil(initialSize.X)), 1);
const short islandHeight = Utils::ClampToShortMax(
static_cast<long>(ceil(initialSize.Height)), 1);
static_cast<long>(ceil(initialSize.Y)), 1);
// Get the size of a window we'd need to host that client rect. This will
// add the titlebar space.
@@ -374,12 +373,6 @@ void AppHost::_AlwaysOnTopChanged(const winrt::Windows::Foundation::IInspectable
_window->SetAlwaysOnTop(_logic.AlwaysOnTop());
}
void AppHost::_TitlebarColorChanged(const winrt::Windows::Foundation::IInspectable&,
const winrt::Windows::Foundation::IInspectable&)
{
_window->SetTitlebarColor(_logic.TitlebarColor());
}
// Method Description:
// - Called when the IslandWindow has received a WM_MOUSEWHEEL message. This can
// happen on some laptops, where their trackpads won't scroll inactive windows

View File

@@ -39,7 +39,5 @@ private:
const winrt::Windows::Foundation::IInspectable& arg);
void _AlwaysOnTopChanged(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& arg);
void _TitlebarColorChanged(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& arg);
void _WindowMouseWheeled(const til::point coord, const int32_t delta);
};

View File

@@ -701,9 +701,5 @@ void IslandWindow::_ApplyWindowSize()
SWP_FRAMECHANGED));
}
void IslandWindow::SetTitlebarColor(const winrt::Windows::UI::Color /*color*/)
{
}
DEFINE_EVENT(IslandWindow, DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);
DEFINE_EVENT(IslandWindow, WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>);

View File

@@ -36,8 +36,6 @@ public:
void FullscreenChanged(const bool fullscreen);
void SetAlwaysOnTop(const bool alwaysOnTop);
virtual void SetTitlebarColor(const winrt::Windows::UI::Color color);
#pragma endregion
DECLARE_EVENT(DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);

View File

@@ -929,8 +929,3 @@ void NonClientIslandWindow::_OpenSystemMenu(const int cursorX, const int cursorY
PostMessage(_window.get(), WM_SYSCOMMAND, ret, 0);
}
}
void NonClientIslandWindow::SetTitlebarColor(const winrt::Windows::UI::Color color)
{
_titlebar.Background().as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>().Color(color);
}

View File

@@ -46,8 +46,6 @@ public:
void SetTitlebarContent(winrt::Windows::UI::Xaml::UIElement content);
void OnApplicationThemeChanged(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme) override;
void SetTitlebarColor(const winrt::Windows::UI::Color color) override;
private:
std::optional<COORD> _oldIslandPos;

View File

@@ -62,16 +62,6 @@ namespace Microsoft.Terminal.Wpf
/// </summary>
WM_CHAR = 0x0102,
/// <summary>
/// The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when a system key is pressed. A system key is F10 or Alt+Something.
/// </summary>
WM_SYSKEYDOWN = 0x0104,
/// <summary>
/// The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when a system key is released. A system key is F10 or Alt+Something.
/// </summary>
WM_SYSKEYUP = 0x0105,
/// <summary>
/// The WM_MOUSEMOVE message is posted to a window when the cursor moves. If the mouse is not captured, the message is posted to the window that contains the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>

View File

@@ -235,7 +235,6 @@ namespace Microsoft.Terminal.Wpf
this.Focus();
NativeMethods.SetFocus(this.hwnd);
break;
case NativeMethods.WindowMessage.WM_SYSKEYDOWN: // fallthrough
case NativeMethods.WindowMessage.WM_KEYDOWN:
{
// WM_KEYDOWN lParam layout documentation: https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keydown
@@ -247,7 +246,6 @@ namespace Microsoft.Terminal.Wpf
break;
}
case NativeMethods.WindowMessage.WM_SYSKEYUP: // fallthrough
case NativeMethods.WindowMessage.WM_KEYUP:
{
// WM_KEYUP lParam layout documentation: https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keyup
@@ -257,13 +255,9 @@ namespace Microsoft.Terminal.Wpf
}
case NativeMethods.WindowMessage.WM_CHAR:
{
// WM_CHAR lParam layout documentation: https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-char
ulong scanCode = (((ulong)lParam) & 0x00FF0000) >> 16;
NativeMethods.TerminalSendCharEvent(this.terminal, (char)wParam, (ushort)scanCode);
break;
}
// WM_CHAR lParam layout documentation: https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-char
NativeMethods.TerminalSendCharEvent(this.terminal, (char)wParam, (ushort)((uint)lParam >> 16));
break;
case NativeMethods.WindowMessage.WM_WINDOWPOSCHANGED:
var windowpos = (NativeMethods.WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(NativeMethods.WINDOWPOS));
if (((NativeMethods.SetWindowPosFlags)windowpos.flags).HasFlag(NativeMethods.SetWindowPosFlags.SWP_NOSIZE))

View File

@@ -28,6 +28,8 @@ namespace TerminalAppUnitTests
TEST_METHOD(ParseSimpleColorScheme);
TEST_METHOD(ProfileGeneratesGuid);
TEST_METHOD(TestWrongValueType);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
@@ -167,4 +169,58 @@ namespace TerminalAppUnitTests
VERIFY_ARE_EQUAL(profile3.GetGuid(), nullGuid);
VERIFY_ARE_EQUAL(profile4.GetGuid(), cmdGuid);
}
void JsonTests::TestWrongValueType()
{
// This json blob has a whole bunch of settings with the wrong value
// types - strings for int values, ints for strings, floats for ints,
// etc. When we encounter data that's the wrong data type, we should
// gracefully ignore it, as opposed to throwing an exception, causing us
// to fail to load the settings at all.
const std::string settings0String{ R"(
{
"defaultProfile" : "{00000000-1111-0000-0000-000000000000}",
"profiles": [
{
"guid" : "{00000000-1111-0000-0000-000000000000}",
"acrylicOpacity" : "0.5",
"closeOnExit" : "true",
"fontSize" : "10",
"historySize" : 1234.5678,
"padding" : 20,
"snapOnInput" : "false",
"icon" : 4,
"backgroundImageOpacity": false,
"useAcrylic" : 14
}
]
})" };
const auto settings0Json = VerifyParseSucceeded(settings0String);
CascadiaSettings settings;
settings._ParseJsonString(settings0String, false);
// We should not throw an exception trying to parse the settings here.
settings.LayerJson(settings._userSettings);
VERIFY_ARE_EQUAL(1u, settings._profiles.size());
auto& profile = settings._profiles.at(0);
Profile defaults{};
VERIFY_ARE_EQUAL(defaults._acrylicTransparency, profile._acrylicTransparency);
VERIFY_ARE_EQUAL(defaults._closeOnExitMode, profile._closeOnExitMode);
VERIFY_ARE_EQUAL(defaults._fontSize, profile._fontSize);
VERIFY_ARE_EQUAL(defaults._historySize, profile._historySize);
// A 20 as an int can still be treated as a json string
VERIFY_ARE_EQUAL(L"20", profile._padding);
VERIFY_ARE_EQUAL(defaults._snapOnInput, profile._snapOnInput);
// 4 is a valid string value
VERIFY_ARE_EQUAL(L"4", profile._icon);
// false is not a valid optional<double>
VERIFY_IS_FALSE(profile._backgroundImageOpacity.has_value());
VERIFY_ARE_EQUAL(defaults._useAcrylic, profile._useAcrylic);
}
}

View File

@@ -3,7 +3,7 @@
#include "precomp.h"
#include "../TerminalApp/JsonUtils.h"
#include "../TerminalApp/JsonUtilsNew.h"
using namespace Microsoft::Console;
using namespace WEX::Logging;

View File

@@ -208,12 +208,12 @@ public:
size_t& written) noexcept override;
[[nodiscard]] HRESULT WriteConsoleInputAImpl(InputBuffer& context,
const gsl::span<const INPUT_RECORD> buffer,
const std::basic_string_view<INPUT_RECORD> buffer,
size_t& written,
const bool append) noexcept override;
[[nodiscard]] HRESULT WriteConsoleInputWImpl(InputBuffer& context,
const gsl::span<const INPUT_RECORD> buffer,
const std::basic_string_view<INPUT_RECORD> buffer,
size_t& written,
const bool append) noexcept override;
@@ -228,7 +228,7 @@ public:
Microsoft::Console::Types::Viewport& writtenRectangle) noexcept override;
[[nodiscard]] HRESULT WriteConsoleOutputAttributeImpl(IConsoleOutputObject& OutContext,
const gsl::span<const WORD> attrs,
const std::basic_string_view<WORD> attrs,
const COORD target,
size_t& used) noexcept override;

View File

@@ -69,7 +69,7 @@ void WriteToScreen(SCREEN_INFORMATION& screenInfo, const Viewport& region)
// Return Value:
// - S_OK, E_INVALIDARG or similar HRESULT error.
[[nodiscard]] HRESULT ApiRoutines::WriteConsoleOutputAttributeImpl(IConsoleOutputObject& OutContext,
const gsl::span<const WORD> attrs,
const std::basic_string_view<WORD> attrs,
const COORD target,
size_t& used) noexcept
{

View File

@@ -149,7 +149,7 @@ std::unordered_map<std::wstring,
if (target.has_value() && target->size() > 0)
{
til::at(*target, 0) = UNICODE_NULL;
gsl::at(*target, 0) = UNICODE_NULL;
}
std::wstring exeNameString(exeName);
@@ -211,7 +211,7 @@ std::unordered_map<std::wstring,
{
if (target.size() > 0)
{
til::at(target, 0) = ANSI_NULL;
gsl::at(target, 0) = ANSI_NULL;
}
LockConsole();
@@ -451,7 +451,7 @@ void Alias::s_ClearCmdExeAliases()
if (aliasBuffer.has_value() && aliasBuffer->size() > 0)
{
til::at(*aliasBuffer, 0) = UNICODE_NULL;
gsl::at(*aliasBuffer, 0) = UNICODE_NULL;
}
std::wstring exeNameString(exeName);
@@ -543,7 +543,7 @@ void Alias::s_ClearCmdExeAliases()
{
if (alias.size() > 0)
{
til::at(alias, 0) = '\0';
gsl::at(alias, 0) = '\0';
}
LockConsole();
@@ -698,7 +698,7 @@ void Alias::s_ClearCmdExeAliases()
writtenOrNeeded = 0;
if (aliasExesBuffer.has_value() && aliasExesBuffer->size() > 0)
{
til::at(*aliasExesBuffer, 0) = UNICODE_NULL;
gsl::at(*aliasExesBuffer, 0) = UNICODE_NULL;
}
LPWSTR AliasExesBufferPtrW = aliasExesBuffer.has_value() ? aliasExesBuffer->data() : nullptr;
@@ -761,7 +761,7 @@ void Alias::s_ClearCmdExeAliases()
{
if (aliasExes.size() > 0)
{
til::at(aliasExes, 0) = '\0';
gsl::at(aliasExes, 0) = '\0';
}
LockConsole();

View File

@@ -112,7 +112,7 @@ void ConversionAreaInfo::SetAttributes(const TextAttribute& attr)
void ConversionAreaInfo::WriteText(const std::vector<OutputCell>& text,
const SHORT column)
{
gsl::span<const OutputCell> view(text.data(), text.size());
std::basic_string_view<OutputCell> view(text.data(), text.size());
_screenBuffer->Write(view, { column, 0 });
}

View File

@@ -57,15 +57,15 @@ void ConsoleImeInfo::RedrawCompMessage()
// - attributes - Encoded attributes including the cursor position and the color index (to the array)
// - colorArray - An array of colors to use for the text
void ConsoleImeInfo::WriteCompMessage(const std::wstring_view text,
const gsl::span<const BYTE> attributes,
const gsl::span<const WORD> colorArray)
const std::basic_string_view<BYTE> attributes,
const std::basic_string_view<WORD> colorArray)
{
ClearAllAreas();
// Save copies of the composition message in case we need to redraw it as things scroll/resize
_text = text;
_attributes.assign(attributes.begin(), attributes.end());
_colorArray.assign(colorArray.begin(), colorArray.end());
_attributes = attributes;
_colorArray = colorArray;
_WriteUndeterminedChars(text, attributes, colorArray);
}
@@ -177,8 +177,8 @@ void ConsoleImeInfo::ClearAllAreas()
// Return Value:
// - TextAttribute object with color and cursor and line drawing data.
TextAttribute ConsoleImeInfo::s_RetrieveAttributeAt(const size_t pos,
const gsl::span<const BYTE> attributes,
const gsl::span<const WORD> colorArray)
const std::basic_string_view<BYTE> attributes,
const std::basic_string_view<WORD> colorArray)
{
// Encoded attribute is the shorthand information passed from the IME
// that contains a cursor position packed in along with which color in the
@@ -214,8 +214,8 @@ TextAttribute ConsoleImeInfo::s_RetrieveAttributeAt(const size_t pos,
// Return Value:
// - Vector of OutputCells where each one represents one cell of the output buffer.
std::vector<OutputCell> ConsoleImeInfo::s_ConvertToCells(const std::wstring_view text,
const gsl::span<const BYTE> attributes,
const gsl::span<const WORD> colorArray)
const std::basic_string_view<BYTE> attributes,
const std::basic_string_view<WORD> colorArray)
{
std::vector<OutputCell> cells;
@@ -389,8 +389,8 @@ std::vector<OutputCell>::const_iterator ConsoleImeInfo::_WriteConversionArea(con
// each text character. This view must be the same size as the text view.
// - colorArray - 8 colors to be used to format the text for display
void ConsoleImeInfo::_WriteUndeterminedChars(const std::wstring_view text,
const gsl::span<const BYTE> attributes,
const gsl::span<const WORD> colorArray)
const std::basic_string_view<BYTE> attributes,
const std::basic_string_view<WORD> colorArray)
{
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
SCREEN_INFORMATION& screenInfo = gci.GetActiveOutputBuffer();

View File

@@ -48,8 +48,8 @@ public:
[[nodiscard]] HRESULT ResizeAllAreas(const COORD newSize);
void WriteCompMessage(const std::wstring_view text,
const gsl::span<const BYTE> attributes,
const gsl::span<const WORD> colorArray);
const std::basic_string_view<BYTE> attributes,
const std::basic_string_view<WORD> colorArray);
void WriteResultMessage(const std::wstring_view text);
@@ -64,18 +64,18 @@ private:
void _ClearComposition();
void _WriteUndeterminedChars(const std::wstring_view text,
const gsl::span<const BYTE> attributes,
const gsl::span<const WORD> colorArray);
const std::basic_string_view<BYTE> attributes,
const std::basic_string_view<WORD> colorArray);
void _InsertConvertedString(const std::wstring_view text);
static TextAttribute s_RetrieveAttributeAt(const size_t pos,
const gsl::span<const BYTE> attributes,
const gsl::span<const WORD> colorArray);
const std::basic_string_view<BYTE> attributes,
const std::basic_string_view<WORD> colorArray);
static std::vector<OutputCell> s_ConvertToCells(const std::wstring_view text,
const gsl::span<const BYTE> attributes,
const gsl::span<const WORD> colorArray);
const std::basic_string_view<BYTE> attributes,
const std::basic_string_view<WORD> colorArray);
std::vector<OutputCell>::const_iterator _WriteConversionArea(const std::vector<OutputCell>::const_iterator begin,
const std::vector<OutputCell>::const_iterator end,
@@ -86,6 +86,6 @@ private:
bool _isSavedCursorVisible;
std::wstring _text;
std::vector<BYTE> _attributes;
std::vector<WORD> _colorArray;
std::basic_string<BYTE> _attributes;
std::basic_string<WORD> _colorArray;
};

View File

@@ -125,8 +125,8 @@ void WriteConvRegionToScreen(const SCREEN_INFORMATION& ScreenInfo,
}
[[nodiscard]] HRESULT ImeComposeData(std::wstring_view text,
gsl::span<const BYTE> attributes,
gsl::span<const WORD> colorArray)
std::basic_string_view<BYTE> attributes,
std::basic_string_view<WORD> colorArray)
{
try
{

View File

@@ -67,10 +67,10 @@ DWORD UnicodeRasterFontCellMungeOnRead(const gsl::span<CHAR_INFO> buffer)
for (DWORD iSrc = 0; iSrc < buffer.size(); iSrc++)
{
// If it's not a trailing byte, copy it straight over, stripping out the Leading/Trailing flags from the attributes field.
auto& src{ til::at(buffer, iSrc) };
auto& src{ gsl::at(buffer, iSrc) };
if (!WI_IsFlagSet(src.Attributes, COMMON_LVB_TRAILING_BYTE))
{
auto& dst{ til::at(buffer, iDst) };
auto& dst{ gsl::at(buffer, iDst) };
dst = src;
WI_ClearAllFlags(dst.Attributes, COMMON_LVB_SBCSDBCS);
iDst++;

View File

@@ -472,7 +472,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
// Return Value:
// - HRESULT indicating success or failure
[[nodiscard]] HRESULT ApiRoutines::WriteConsoleInputAImpl(InputBuffer& context,
const gsl::span<const INPUT_RECORD> buffer,
const std::basic_string_view<INPUT_RECORD> buffer,
size_t& written,
const bool append) noexcept
{
@@ -516,7 +516,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
// Return Value:
// - HRESULT indicating success or failure
[[nodiscard]] HRESULT ApiRoutines::WriteConsoleInputWImpl(InputBuffer& context,
const gsl::span<const INPUT_RECORD> buffer,
const std::basic_string_view<INPUT_RECORD> buffer,
size_t& written,
const bool append) noexcept
{
@@ -1042,7 +1042,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
const auto subspan = buffer.subspan(totalOffset, writeRectangle.Width());
// Convert to a CHAR_INFO view to fit into the iterator
const auto charInfos = gsl::span<const CHAR_INFO>(subspan.data(), subspan.size());
const auto charInfos = std::basic_string_view<CHAR_INFO>(subspan.data(), subspan.size());
// Make the iterator and write to the target position.
OutputCellIterator it(charInfos);

View File

@@ -1604,7 +1604,7 @@ void DoSrvPrivateRefreshWindow(_In_ const SCREEN_INFORMATION& screenInfo)
if (title.has_value() && title->size() > 0)
{
til::at(*title, 0) = ANSI_NULL;
gsl::at(*title, 0) = ANSI_NULL;
}
// Get the appropriate title and length depending on the mode.
@@ -1667,7 +1667,7 @@ void DoSrvPrivateRefreshWindow(_In_ const SCREEN_INFORMATION& screenInfo)
if (title.size() > 0)
{
til::at(title, 0) = ANSI_NULL;
gsl::at(title, 0) = ANSI_NULL;
}
// Figure out how big our temporary Unicode buffer must be to get the title.
@@ -1722,7 +1722,7 @@ void DoSrvPrivateRefreshWindow(_In_ const SCREEN_INFORMATION& screenInfo)
// If we didn't copy anything back and there is space, null terminate the given buffer and return.
if (title.size() > 0)
{
til::at(title, 0) = ANSI_NULL;
gsl::at(title, 0) = ANSI_NULL;
written = 1;
}
}

View File

@@ -782,7 +782,7 @@ HRESULT GetConsoleCommandHistoryWImplHelper(const std::wstring_view exeName,
writtenOrNeeded = 0;
if (historyBuffer.size() > 0)
{
til::at(historyBuffer, 0) = UNICODE_NULL;
gsl::at(historyBuffer, 0) = UNICODE_NULL;
}
CommandHistory* const CommandHistory = CommandHistory::s_FindByExe(exeName);
@@ -859,7 +859,7 @@ HRESULT ApiRoutines::GetConsoleCommandHistoryAImpl(const std::string_view exeNam
{
if (commandHistory.size() > 0)
{
til::at(commandHistory, 0) = ANSI_NULL;
gsl::at(commandHistory, 0) = ANSI_NULL;
}
LockConsole();

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