mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-11 16:51:00 +00:00
Compare commits
4 Commits
dev/migrie
...
dev/miniks
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3dca4263d5 | ||
|
|
462006ba51 | ||
|
|
5b6d2e0708 | ||
|
|
ffe0e024b3 |
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" }
|
||||
]
|
||||
},
|
||||
|
||||
BIN
res/Cascadia.ttf
BIN
res/Cascadia.ttf
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
|
||||
[[nodiscard]] TextAttribute GetCurrentAttributes() const noexcept;
|
||||
|
||||
void SetCurrentAttributes(const TextAttribute& currentAttributes) noexcept;
|
||||
void SetCurrentAttributes(const TextAttribute currentAttributes) noexcept;
|
||||
|
||||
void Reset();
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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"";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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"";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -115,9 +115,4 @@ namespace TerminalApp
|
||||
{
|
||||
String Title { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass ExecuteCommandlineArgs : IActionArgs
|
||||
{
|
||||
String Commandline;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() };
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
125
src/cascadia/TerminalApp/JsonUtils.cpp
Normal file
125
src/cascadia/TerminalApp/JsonUtils.cpp
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
490
src/cascadia/TerminalApp/JsonUtilsNew.h
Normal file
490
src/cascadia/TerminalApp/JsonUtilsNew.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 };
|
||||
};
|
||||
};
|
||||
@@ -194,10 +194,6 @@ namespace winrt::TerminalApp::implementation
|
||||
_RenameTabHandlers(*this, *eventArgs);
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::ExecuteCommandline:
|
||||
{
|
||||
_ExecuteCommandlineHandlers(*this, *eventArgs);
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<>);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
18
src/cascadia/TerminalApp/Utils.cpp
Normal file
18
src/cascadia/TerminalApp/Utils.cpp
Normal 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();
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 ---------------------------------
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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<>);
|
||||
|
||||
@@ -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<>);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include "../TerminalApp/JsonUtils.h"
|
||||
#include "../TerminalApp/JsonUtilsNew.h"
|
||||
|
||||
using namespace Microsoft::Console;
|
||||
using namespace WEX::Logging;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user