mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-07 06:39:44 +00:00
Compare commits
26 Commits
dev/migrie
...
dev/miniks
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa11bd1d9d | ||
|
|
bd4216f926 | ||
|
|
a8be923688 | ||
|
|
1eea75e3e7 | ||
|
|
ad723f9671 | ||
|
|
4db39a6f55 | ||
|
|
d7255fdbef | ||
|
|
23aef43c81 | ||
|
|
8c1a45f6f0 | ||
|
|
ebe9016356 | ||
|
|
d4885149ae | ||
|
|
ee5c5a474b | ||
|
|
4aa62f9edd | ||
|
|
cc6ad0b99b | ||
|
|
28e1e226ad | ||
|
|
6f23280011 | ||
|
|
37dab43af0 | ||
|
|
d77e55596b | ||
|
|
0be1c9deef | ||
|
|
5f9321310f | ||
|
|
061e636163 | ||
|
|
8aaa93f139 | ||
|
|
90a24b20b8 | ||
|
|
aa1ed0a19c | ||
|
|
2fc1ef04ce | ||
|
|
fefd1408f2 |
@@ -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:
|
||||
@@ -250,11 +255,11 @@ 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 = newAttrs.at(0).GetAttributes();
|
||||
const TextAttribute NewAttr = newAttrs[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.
|
||||
if (_list.size() == 1 && _list.at(0).GetAttributes() == NewAttr)
|
||||
if (_list.size() == 1 && _list[0].GetAttributes() == NewAttr)
|
||||
{
|
||||
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,
|
||||
|
||||
@@ -233,7 +233,9 @@ void CharRow::ClearGlyph(const size_t column)
|
||||
// - Note: will throw exception if column is out of bounds
|
||||
const CharRow::reference CharRow::GlyphAt(const size_t column) const
|
||||
{
|
||||
#ifdef DBG
|
||||
THROW_HR_IF(E_INVALIDARG, column >= _data.size());
|
||||
#endif
|
||||
return { const_cast<CharRow&>(*this), column };
|
||||
}
|
||||
|
||||
@@ -246,7 +248,9 @@ const CharRow::reference CharRow::GlyphAt(const size_t column) const
|
||||
// - Note: will throw exception if column is out of bounds
|
||||
CharRow::reference CharRow::GlyphAt(const size_t column)
|
||||
{
|
||||
#ifdef DBG
|
||||
THROW_HR_IF(E_INVALIDARG, column >= _data.size());
|
||||
#endif
|
||||
return { *this, column };
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ CharRowCellReference::operator std::wstring_view() const
|
||||
// - ref to the CharRowCell
|
||||
CharRowCell& CharRowCellReference::_cellData()
|
||||
{
|
||||
return _parent._data.at(_index);
|
||||
return _parent._data[_index];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -50,7 +50,7 @@ CharRowCell& CharRowCellReference::_cellData()
|
||||
// - ref to the CharRowCell
|
||||
const CharRowCell& CharRowCellReference::_cellData() const
|
||||
{
|
||||
return _parent._data.at(_index);
|
||||
return _parent._data[_index];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@@ -169,42 +169,33 @@ OutputCellIterator::OutputCellIterator(const std::basic_string_view<OutputCell>
|
||||
// - True if the views on dereference are valid. False if it shouldn't be dereferenced.
|
||||
OutputCellIterator::operator bool() const noexcept
|
||||
{
|
||||
try
|
||||
switch (_mode)
|
||||
{
|
||||
switch (_mode)
|
||||
{
|
||||
case Mode::Loose:
|
||||
case Mode::LooseTextOnly:
|
||||
{
|
||||
// In lieu of using start and end, this custom iterator type simply becomes bool false
|
||||
// when we run out of items to iterate over.
|
||||
return _pos < std::get<std::wstring_view>(_run).length();
|
||||
}
|
||||
case Mode::Fill:
|
||||
{
|
||||
if (_fillLimit > 0)
|
||||
{
|
||||
return _pos < _fillLimit;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Mode::Cell:
|
||||
{
|
||||
return _pos < std::get<std::basic_string_view<OutputCell>>(_run).length();
|
||||
}
|
||||
case Mode::CharInfo:
|
||||
{
|
||||
return _pos < std::get<std::basic_string_view<CHAR_INFO>>(_run).length();
|
||||
}
|
||||
case Mode::LegacyAttr:
|
||||
{
|
||||
return _pos < std::get<std::wstring_view>(_run).length();
|
||||
}
|
||||
default:
|
||||
FAIL_FAST_HR(E_NOTIMPL);
|
||||
}
|
||||
case Mode::Loose:
|
||||
case Mode::LooseTextOnly: {
|
||||
// In lieu of using start and end, this custom iterator type simply becomes bool false
|
||||
// when we run out of items to iterate over.
|
||||
return _pos < std::get<std::wstring_view>(_run).length();
|
||||
}
|
||||
case Mode::Fill: {
|
||||
if (_fillLimit > 0)
|
||||
{
|
||||
return _pos < _fillLimit;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Mode::Cell: {
|
||||
return _pos < std::get<std::basic_string_view<OutputCell>>(_run).length();
|
||||
}
|
||||
case Mode::CharInfo: {
|
||||
return _pos < std::get<std::basic_string_view<CHAR_INFO>>(_run).length();
|
||||
}
|
||||
case Mode::LegacyAttr: {
|
||||
return _pos < std::get<std::wstring_view>(_run).length();
|
||||
}
|
||||
default:
|
||||
FAIL_FAST_HR(E_NOTIMPL);
|
||||
}
|
||||
CATCH_FAIL_FAST();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -218,8 +209,7 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
|
||||
switch (_mode)
|
||||
{
|
||||
case Mode::Loose:
|
||||
{
|
||||
case Mode::Loose: {
|
||||
if (!_TryMoveTrailing())
|
||||
{
|
||||
// When walking through a text sequence, we need to move forward by the number of wchar_ts consumed in the previous view
|
||||
@@ -232,8 +222,7 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::LooseTextOnly:
|
||||
{
|
||||
case Mode::LooseTextOnly: {
|
||||
if (!_TryMoveTrailing())
|
||||
{
|
||||
// When walking through a text sequence, we need to move forward by the number of wchar_ts consumed in the previous view
|
||||
@@ -246,8 +235,7 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::Fill:
|
||||
{
|
||||
case Mode::Fill: {
|
||||
if (!_TryMoveTrailing())
|
||||
{
|
||||
if (_currentView.DbcsAttr().IsTrailing())
|
||||
@@ -269,8 +257,7 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::Cell:
|
||||
{
|
||||
case Mode::Cell: {
|
||||
// Walk forward by one because cells are assumed to be in the form they needed to be
|
||||
_pos++;
|
||||
if (operator bool())
|
||||
@@ -279,8 +266,7 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::CharInfo:
|
||||
{
|
||||
case Mode::CharInfo: {
|
||||
// Walk forward by one because charinfos are just the legacy version of cells and prealigned to columns
|
||||
_pos++;
|
||||
if (operator bool())
|
||||
@@ -289,8 +275,7 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::LegacyAttr:
|
||||
{
|
||||
case Mode::LegacyAttr: {
|
||||
// Walk forward by one because color attributes apply cell by cell (no complex text information)
|
||||
_pos++;
|
||||
if (operator bool())
|
||||
|
||||
@@ -160,66 +160,95 @@ 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);
|
||||
|
||||
while (it && currentIndex <= finalColumnInRow)
|
||||
if (it)
|
||||
{
|
||||
// Fill the color if the behavior isn't set to keeping the current color.
|
||||
if (it->TextAttrBehavior() != TextAttributeBehavior::Current)
|
||||
// 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)
|
||||
{
|
||||
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())
|
||||
// Fill the color if the behavior isn't set to keeping the current color.
|
||||
if (it->TextAttrBehavior() != TextAttributeBehavior::Current)
|
||||
{
|
||||
_charRow.ClearCell(currentIndex);
|
||||
// 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 },
|
||||
index,
|
||||
currentIndex - 1,
|
||||
_charRow.size()));
|
||||
currentColor = it->TextAttr();
|
||||
colorUses = 1;
|
||||
colorStarts = 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())
|
||||
|
||||
// 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)
|
||||
{
|
||||
_charRow.ClearCell(currentIndex);
|
||||
_charRow.SetDoubleBytePadded(true);
|
||||
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());
|
||||
}
|
||||
}
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
// Move to the next cell for the next time through the loop.
|
||||
++currentIndex;
|
||||
}
|
||||
|
||||
// Move to the next cell for the next time through the loop.
|
||||
++currentIndex;
|
||||
// Now commit the final color into the attr row
|
||||
const TextAttributeRun run{ colorUses, currentColor };
|
||||
LOG_IF_FAILED(_attrRow.InsertAttrRuns({ &run, 1 },
|
||||
colorStarts,
|
||||
currentIndex - 1,
|
||||
_charRow.size()));
|
||||
}
|
||||
|
||||
return it;
|
||||
|
||||
@@ -33,13 +33,16 @@ TextBuffer::TextBuffer(const COORD screenBufferSize,
|
||||
_cursor{ cursorSize, *this },
|
||||
_storage{},
|
||||
_unicodeStorage{},
|
||||
_renderTarget{ renderTarget }
|
||||
_renderTarget{ renderTarget },
|
||||
_size{}
|
||||
{
|
||||
// initialize ROWs
|
||||
for (size_t i = 0; i < static_cast<size_t>(screenBufferSize.Y); ++i)
|
||||
{
|
||||
_storage.emplace_back(static_cast<SHORT>(i), screenBufferSize.X, _currentAttributes, this);
|
||||
}
|
||||
|
||||
_UpdateSize();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -78,7 +81,7 @@ const ROW& TextBuffer::GetRowByOffset(const size_t index) const
|
||||
|
||||
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
|
||||
const size_t offsetIndex = (_firstRow + index) % totalRows;
|
||||
return _storage.at(offsetIndex);
|
||||
return _storage[offsetIndex];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -94,7 +97,7 @@ ROW& TextBuffer::GetRowByOffset(const size_t index)
|
||||
|
||||
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
|
||||
const size_t offsetIndex = (_firstRow + index) % totalRows;
|
||||
return _storage.at(offsetIndex);
|
||||
return _storage[offsetIndex];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -652,9 +655,15 @@ const SHORT TextBuffer::GetFirstRowIndex() const noexcept
|
||||
{
|
||||
return _firstRow;
|
||||
}
|
||||
const Viewport TextBuffer::GetSize() const
|
||||
|
||||
const Viewport TextBuffer::GetSize() const noexcept
|
||||
{
|
||||
return Viewport::FromDimensions({ 0, 0 }, { gsl::narrow<SHORT>(_storage.at(0).size()), gsl::narrow<SHORT>(_storage.size()) });
|
||||
return _size;
|
||||
}
|
||||
|
||||
void TextBuffer::_UpdateSize()
|
||||
{
|
||||
_size = Viewport::FromDimensions({ 0, 0 }, { gsl::narrow<SHORT>(_storage.at(0).size()), gsl::narrow<SHORT>(_storage.size()) });
|
||||
}
|
||||
|
||||
void TextBuffer::_SetFirstRowIndex(const SHORT FirstRowIndex) noexcept
|
||||
@@ -845,6 +854,9 @@ void TextBuffer::Reset()
|
||||
// Also take advantage of the row ID refresh loop to resize the rows in the X dimension
|
||||
// and cleanup the UnicodeStorage characters that might fall outside the resized buffer.
|
||||
_RefreshRowIDs(newSize.X);
|
||||
|
||||
// Update the cached size value
|
||||
_UpdateSize();
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
|
||||
const SHORT GetFirstRowIndex() const noexcept;
|
||||
|
||||
const Microsoft::Console::Types::Viewport GetSize() const;
|
||||
const Microsoft::Console::Types::Viewport GetSize() const noexcept;
|
||||
|
||||
void ScrollRows(const SHORT firstRow, const SHORT size, const SHORT delta);
|
||||
|
||||
@@ -177,6 +177,8 @@ public:
|
||||
std::optional<std::reference_wrapper<PositionInformation>> positionInfo);
|
||||
|
||||
private:
|
||||
void _UpdateSize();
|
||||
Microsoft::Console::Types::Viewport _size;
|
||||
std::deque<ROW> _storage;
|
||||
Cursor _cursor;
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace TerminalAppLocalTests
|
||||
const auto commands1Json = VerifyParseSucceeded(commands1String);
|
||||
const auto commands2Json = VerifyParseSucceeded(commands2String);
|
||||
|
||||
std::map<winrt::hstring, Command> commands;
|
||||
std::unordered_map<winrt::hstring, Command> commands;
|
||||
VERIFY_ARE_EQUAL(0u, commands.size());
|
||||
{
|
||||
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
|
||||
@@ -95,7 +95,7 @@ namespace TerminalAppLocalTests
|
||||
const auto commands2Json = VerifyParseSucceeded(commands2String);
|
||||
const auto commands3Json = VerifyParseSucceeded(commands3String);
|
||||
|
||||
std::map<winrt::hstring, Command> commands;
|
||||
std::unordered_map<winrt::hstring, Command> commands;
|
||||
VERIFY_ARE_EQUAL(0u, commands.size());
|
||||
{
|
||||
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
|
||||
@@ -155,7 +155,7 @@ namespace TerminalAppLocalTests
|
||||
|
||||
const auto commands0Json = VerifyParseSucceeded(commands0String);
|
||||
|
||||
std::map<winrt::hstring, Command> commands;
|
||||
std::unordered_map<winrt::hstring, Command> commands;
|
||||
VERIFY_ARE_EQUAL(0u, commands.size());
|
||||
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
|
||||
VERIFY_ARE_EQUAL(0u, warnings.size());
|
||||
@@ -239,7 +239,7 @@ namespace TerminalAppLocalTests
|
||||
const std::string commands0String{ R"([ { "name": { "key": "DuplicateTabCommandKey"}, "command": "copy" } ])" };
|
||||
const auto commands0Json = VerifyParseSucceeded(commands0String);
|
||||
|
||||
std::map<winrt::hstring, Command> commands;
|
||||
std::unordered_map<winrt::hstring, Command> commands;
|
||||
VERIFY_ARE_EQUAL(0u, commands.size());
|
||||
{
|
||||
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
|
||||
@@ -279,7 +279,7 @@ namespace TerminalAppLocalTests
|
||||
|
||||
const auto commands0Json = VerifyParseSucceeded(commands0String);
|
||||
|
||||
std::map<winrt::hstring, Command> commands;
|
||||
std::unordered_map<winrt::hstring, Command> commands;
|
||||
VERIFY_ARE_EQUAL(0u, commands.size());
|
||||
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
|
||||
VERIFY_ARE_EQUAL(0u, warnings.size());
|
||||
@@ -300,7 +300,7 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
|
||||
}
|
||||
{
|
||||
auto command = commands.at(L"Split pane, direction: Vertical");
|
||||
auto command = commands.at(L"Split pane, direction: vertical");
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
VERIFY_IS_NOT_NULL(command.Action());
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.Action().Action());
|
||||
@@ -310,7 +310,7 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Vertical, realArgs.SplitStyle());
|
||||
}
|
||||
{
|
||||
auto command = commands.at(L"Split pane, direction: Horizontal");
|
||||
auto command = commands.at(L"Split pane, direction: horizontal");
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
VERIFY_IS_NOT_NULL(command.Action());
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.Action().Action());
|
||||
@@ -329,7 +329,7 @@ namespace TerminalAppLocalTests
|
||||
|
||||
const auto commands0Json = VerifyParseSucceeded(commands0String);
|
||||
|
||||
std::map<winrt::hstring, Command> commands;
|
||||
std::unordered_map<winrt::hstring, Command> commands;
|
||||
VERIFY_ARE_EQUAL(0u, commands.size());
|
||||
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
|
||||
VERIFY_ARE_EQUAL(0u, warnings.size());
|
||||
|
||||
@@ -29,7 +29,6 @@ static constexpr std::string_view ResizePaneKey{ "resizePane" };
|
||||
static constexpr std::string_view MoveFocusKey{ "moveFocus" };
|
||||
static constexpr std::string_view FindKey{ "find" };
|
||||
static constexpr std::string_view ToggleFullscreenKey{ "toggleFullscreen" };
|
||||
static constexpr std::string_view ExecuteCommandlineKey{ "wt" };
|
||||
static constexpr std::string_view SetTabColorKey{ "setTabColor" };
|
||||
static constexpr std::string_view OpenTabColorPickerKey{ "openTabColorPicker" };
|
||||
static constexpr std::string_view RenameTabKey{ "renameTab" };
|
||||
@@ -80,7 +79,6 @@ namespace winrt::TerminalApp::implementation
|
||||
{ FindKey, ShortcutAction::Find },
|
||||
{ RenameTabKey, ShortcutAction::RenameTab },
|
||||
{ ToggleCommandPaletteKey, ShortcutAction::ToggleCommandPalette },
|
||||
{ ExecuteCommandlineKey, ShortcutAction::ExecuteCommandline },
|
||||
};
|
||||
|
||||
using ParseResult = std::tuple<IActionArgs, std::vector<::TerminalApp::SettingsLoadWarnings>>;
|
||||
@@ -106,8 +104,6 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
{ ShortcutAction::SplitPane, winrt::TerminalApp::implementation::SplitPaneArgs::FromJson },
|
||||
|
||||
{ ShortcutAction::ExecuteCommandline, winrt::TerminalApp::implementation::ExecuteCommandlineArgs::FromJson },
|
||||
|
||||
{ ShortcutAction::OpenSettings, winrt::TerminalApp::implementation::OpenSettingsArgs::FromJson },
|
||||
|
||||
{ ShortcutAction::SetTabColor, winrt::TerminalApp::implementation::SetTabColorArgs::FromJson },
|
||||
@@ -256,7 +252,6 @@ namespace winrt::TerminalApp::implementation
|
||||
{ ShortcutAction::ToggleFullscreen, RS_(L"ToggleFullscreenCommandKey") },
|
||||
{ ShortcutAction::SplitPane, RS_(L"SplitPaneCommandKey") },
|
||||
{ ShortcutAction::Invalid, L"" },
|
||||
{ ShortcutAction::ExecuteCommandline, L"" },
|
||||
{ ShortcutAction::Find, RS_(L"FindCommandKey") },
|
||||
{ ShortcutAction::SetTabColor, RS_(L"ResetTabColorCommandKey") },
|
||||
{ ShortcutAction::OpenTabColorPicker, RS_(L"OpenTabColorPickerCommandKey") },
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "MoveFocusArgs.g.cpp"
|
||||
#include "AdjustFontSizeArgs.g.cpp"
|
||||
#include "SplitPaneArgs.g.cpp"
|
||||
#include "ExecuteCommandlineArgs.g.cpp"
|
||||
#include "OpenSettingsArgs.g.cpp"
|
||||
#include "SetTabColorArgs.g.cpp"
|
||||
#include "RenameTabArgs.g.cpp"
|
||||
@@ -229,14 +228,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
winrt::hstring ExecuteCommandlineArgs::GenerateName() const
|
||||
{
|
||||
return winrt::hstring{
|
||||
fmt::format(std::wstring_view(RS_(L"ExecuteCommandlineCommandKey")),
|
||||
_Commandline)
|
||||
};
|
||||
}
|
||||
|
||||
winrt::hstring SetTabColorArgs::GenerateName() const
|
||||
{
|
||||
// "Set tab color to #RRGGBB"
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "MoveFocusArgs.g.h"
|
||||
#include "AdjustFontSizeArgs.g.h"
|
||||
#include "SplitPaneArgs.g.h"
|
||||
#include "ExecuteCommandlineArgs.g.h"
|
||||
#include "OpenSettingsArgs.g.h"
|
||||
#include "SetTabColorArgs.g.h"
|
||||
#include "RenameTabArgs.g.h"
|
||||
@@ -404,37 +403,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
};
|
||||
|
||||
struct ExecuteCommandlineArgs : public ExecuteCommandlineArgsT<ExecuteCommandlineArgs>
|
||||
{
|
||||
ExecuteCommandlineArgs() = default;
|
||||
GETSET_PROPERTY(winrt::hstring, Commandline, false);
|
||||
|
||||
static constexpr std::string_view CommandlineKey{ "commandline" };
|
||||
|
||||
public:
|
||||
hstring GenerateName() const;
|
||||
|
||||
bool Equals(const IActionArgs& other)
|
||||
{
|
||||
auto otherAsUs = other.try_as<ExecuteCommandlineArgs>();
|
||||
if (otherAsUs)
|
||||
{
|
||||
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>();
|
||||
if (auto commandline{ json[JsonKey(CommandlineKey)] })
|
||||
{
|
||||
args->_Commandline = winrt::to_hstring(commandline.asString());
|
||||
}
|
||||
return { *args, {} };
|
||||
}
|
||||
};
|
||||
|
||||
// Possible SettingsTarget values
|
||||
// TODO:GH#2550/#3475 - move these to a centralized deserializing place
|
||||
static constexpr std::string_view SettingsFileString{ "settingsFile" };
|
||||
|
||||
@@ -101,11 +101,6 @@ namespace TerminalApp
|
||||
SplitType SplitMode { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass ExecuteCommandlineArgs : IActionArgs
|
||||
{
|
||||
String Commandline;
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass OpenSettingsArgs : IActionArgs
|
||||
{
|
||||
SettingsTarget Target { get; };
|
||||
|
||||
@@ -312,40 +312,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>())
|
||||
{
|
||||
// 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(realArgs.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.
|
||||
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;
|
||||
bool handled = appArgs.ParseArgs(argsView) == 0;
|
||||
if (handled)
|
||||
{
|
||||
_startupActions = appArgs.GetStartupActions();
|
||||
_ProcessStartupActions(false);
|
||||
}
|
||||
|
||||
actionArgs.Handled(handled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,52 +637,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,9 +28,7 @@ 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);
|
||||
|
||||
@@ -472,7 +472,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)
|
||||
{
|
||||
@@ -502,7 +502,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())
|
||||
{
|
||||
@@ -517,7 +517,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;
|
||||
@@ -972,7 +972,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();
|
||||
@@ -982,6 +982,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
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::hstring ApplicationDisplayName() const;
|
||||
winrt::hstring ApplicationVersion() const;
|
||||
|
||||
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();
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace TerminalApp
|
||||
String ApplicationDisplayName { get; };
|
||||
String ApplicationVersion { 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();
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "CommandPalette.h"
|
||||
#include "ActionArgs.h"
|
||||
#include "ActionAndArgs.h"
|
||||
|
||||
#include "CommandPalette.g.cpp"
|
||||
#include <winrt/Microsoft.Terminal.Settings.h>
|
||||
@@ -99,18 +97,17 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
else if (key == VirtualKey::Enter)
|
||||
{
|
||||
if (_mode == PaletteMode::ActionMode)
|
||||
// Action Mode: Dispatch the action of the selected command.
|
||||
|
||||
if (const auto selectedItem = _filteredActionsView().SelectedItem())
|
||||
{
|
||||
// Action Mode: Dispatch the action of the selected command.
|
||||
if (const auto selectedItem = _filteredActionsView().SelectedItem())
|
||||
if (const auto data = selectedItem.try_as<Command>())
|
||||
{
|
||||
_dispatchAction();
|
||||
const auto actionAndArgs = data.Action();
|
||||
_dispatch.DoAction(actionAndArgs);
|
||||
_close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_dispatchCommandline();
|
||||
}
|
||||
|
||||
e.Handled(true);
|
||||
}
|
||||
@@ -187,7 +184,6 @@ namespace winrt::TerminalApp::implementation
|
||||
void CommandPalette::_filterTextChanged(IInspectable const& /*sender*/,
|
||||
Windows::UI::Xaml::RoutedEventArgs const& /*args*/)
|
||||
{
|
||||
_checkMode();
|
||||
_updateFilteredActions();
|
||||
_filteredActionsView().SelectedIndex(0);
|
||||
|
||||
@@ -241,12 +237,6 @@ namespace winrt::TerminalApp::implementation
|
||||
void CommandPalette::_updateFilteredActions()
|
||||
{
|
||||
_filteredActions.Clear();
|
||||
|
||||
if (_mode == PaletteMode::CommandlineMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto searchText = _searchBox().Text();
|
||||
const bool addAll = searchText.empty();
|
||||
|
||||
@@ -421,60 +411,4 @@ namespace winrt::TerminalApp::implementation
|
||||
_searchBox().Text(L"");
|
||||
}
|
||||
|
||||
void CommandPalette::_checkMode()
|
||||
{
|
||||
_mode = PaletteMode::ActionMode;
|
||||
|
||||
auto inputText = _searchBox().Text();
|
||||
if (inputText.size() > 0)
|
||||
{
|
||||
if (inputText[0] == L'>')
|
||||
{
|
||||
_mode = PaletteMode::CommandlineMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CommandPalette::_dispatchAction()
|
||||
{
|
||||
// Action Mode: Dispatch the action of the selected command.
|
||||
|
||||
if (const auto selectedItem = _filteredActionsView().SelectedItem())
|
||||
{
|
||||
if (const auto data = selectedItem.try_as<Command>())
|
||||
{
|
||||
const auto actionAndArgs = data.Action();
|
||||
_dispatch.DoAction(actionAndArgs);
|
||||
_close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CommandPalette::_dispatchCommandline()
|
||||
{
|
||||
const auto inputText = _searchBox().Text();
|
||||
const std::wstring input{ _searchBox().Text() };
|
||||
const auto rawCmdline{ input.substr(1) };
|
||||
|
||||
// Trim leading whitespace
|
||||
const auto firstNonSpace = rawCmdline.find_first_not_of(L" ");
|
||||
if (firstNonSpace == std::wstring::npos)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
winrt::hstring cmdline{ rawCmdline.substr(firstNonSpace) };
|
||||
|
||||
// Build the NewTab action from the values we've parsed on the commandline.
|
||||
auto executeActionAndArgs = winrt::make_self<implementation::ActionAndArgs>();
|
||||
executeActionAndArgs->Action(ShortcutAction::ExecuteCommandline);
|
||||
auto args = winrt::make_self<implementation::ExecuteCommandlineArgs>();
|
||||
args->Commandline(cmdline);
|
||||
executeActionAndArgs->Args(*args);
|
||||
|
||||
if (_dispatch.DoAction(*executeActionAndArgs))
|
||||
{
|
||||
_close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,6 @@
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
enum class PaletteMode : uint32_t
|
||||
{
|
||||
ActionMode = 0,
|
||||
CommandlineMode
|
||||
};
|
||||
|
||||
struct CommandPalette : CommandPaletteT<CommandPalette>
|
||||
{
|
||||
CommandPalette();
|
||||
@@ -30,8 +24,6 @@ namespace winrt::TerminalApp::implementation
|
||||
Windows::Foundation::Collections::IVector<TerminalApp::Command> _allActions{ nullptr };
|
||||
winrt::TerminalApp::ShortcutActionDispatch _dispatch;
|
||||
|
||||
PaletteMode _mode{ PaletteMode::ActionMode };
|
||||
|
||||
void _filterTextChanged(Windows::Foundation::IInspectable const& sender,
|
||||
Windows::UI::Xaml::RoutedEventArgs const& args);
|
||||
void _keyDownHandler(Windows::Foundation::IInspectable const& sender,
|
||||
@@ -44,14 +36,9 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _selectNextItem(const bool moveDown);
|
||||
|
||||
void _checkMode();
|
||||
|
||||
void _updateFilteredActions();
|
||||
static int _getWeight(const winrt::hstring& searchText, const winrt::hstring& name);
|
||||
void _close();
|
||||
|
||||
void _dispatchAction();
|
||||
void _dispatchCommandline();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
if (splitType == SplitState::Vertical)
|
||||
{
|
||||
const auto widthMinusSeparator = availableSpace.Width - CombinedPaneBorderSize;
|
||||
const auto newWidth = widthMinusSeparator * Half;
|
||||
|
||||
return { newWidth > minSize.Width };
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
|
||||
@@ -480,10 +480,6 @@
|
||||
<data name="ToggleCommandPaletteCommandKey" xml:space="preserve">
|
||||
<value>Toggle command palette</value>
|
||||
</data>
|
||||
<data name="ExecuteCommandlineCommandKey" xml:space="preserve">
|
||||
<value>Run the commandline "{0}" in this window</value>
|
||||
<comment>{0} will be replaced with a user-provided commandline</comment>
|
||||
</data>
|
||||
<data name="SetTabColorCommandKey" xml:space="preserve">
|
||||
<value>Set tab color to {0}</value>
|
||||
<comment>{0} will be replaced with a color, displayed in hexadecimal (#RRGGBB) notation.</comment>
|
||||
|
||||
@@ -164,10 +164,6 @@ namespace winrt::TerminalApp::implementation
|
||||
_ToggleCommandPaletteHandlers(*this, *eventArgs);
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::ExecuteCommandline:
|
||||
{
|
||||
_ExecuteCommandlineHandlers(*this, *eventArgs);
|
||||
}
|
||||
case ShortcutAction::SetTabColor:
|
||||
{
|
||||
_SetTabColorHandlers(*this, *eventArgs);
|
||||
|
||||
@@ -48,7 +48,6 @@ namespace winrt::TerminalApp::implementation
|
||||
TYPED_EVENT(MoveFocus, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(ToggleFullscreen, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(ToggleCommandPalette, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(ExecuteCommandline, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(SetTabColor, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(OpenTabColorPicker, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
|
||||
TYPED_EVENT(RenameTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
|
||||
|
||||
@@ -35,7 +35,6 @@ namespace TerminalApp
|
||||
SetTabColor,
|
||||
OpenTabColorPicker,
|
||||
OpenSettings,
|
||||
ExecuteCommandline,
|
||||
RenameTab,
|
||||
ToggleCommandPalette
|
||||
};
|
||||
@@ -76,7 +75,6 @@ namespace TerminalApp
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> MoveFocus;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> ToggleFullscreen;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> ToggleCommandPalette;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> ExecuteCommandline;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> SetTabColor;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> OpenTabColorPicker;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> RenameTab;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -230,7 +230,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
else
|
||||
{
|
||||
_ProcessStartupActions(true);
|
||||
_ProcessStartupActions();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,11 +239,10 @@ namespace winrt::TerminalApp::implementation
|
||||
// - Process all the startup actions in our list of startup actions. We'll
|
||||
// do this all at once here.
|
||||
// Arguments:
|
||||
// - 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(const bool initial)
|
||||
winrt::fire_and_forget TerminalPage::_ProcessStartupActions()
|
||||
{
|
||||
// If there are no actions left, do nothing.
|
||||
if (_startupActions.empty())
|
||||
@@ -253,24 +252,15 @@ namespace winrt::TerminalApp::implementation
|
||||
auto weakThis{ get_weak() };
|
||||
|
||||
// Handle it on a subsequent pass of the UI thread.
|
||||
for (const auto& action : _startupActions)
|
||||
co_await winrt::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal);
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
co_await winrt::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal);
|
||||
if (auto page{ weakThis.get() })
|
||||
for (const auto& action : _startupActions)
|
||||
{
|
||||
_actionDispatch->DoAction(action);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
if (initial)
|
||||
{
|
||||
_CompleteInitialization();
|
||||
}
|
||||
|
||||
_CompleteInitialization();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,6 +595,16 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
auto tabViewItem = newTabImpl->GetTabViewItem();
|
||||
_tabView.TabItems().Append(tabViewItem);
|
||||
// GH#6570
|
||||
// The TabView does not apply compact sizing to items added after Compact is enabled.
|
||||
// By forcibly reapplying compact sizing every time we add a new tab, we'll make sure
|
||||
// that it works.
|
||||
// Workaround from https://github.com/microsoft/microsoft-ui-xaml/issues/2711
|
||||
if (_tabView.TabWidthMode() == MUX::Controls::TabViewWidthMode::Compact)
|
||||
{
|
||||
_tabView.UpdateLayout();
|
||||
_tabView.TabWidthMode(MUX::Controls::TabViewWidthMode::Compact);
|
||||
}
|
||||
|
||||
// Set this tab's icon to the icon from the user's profile
|
||||
const auto* const profile = _settings->FindProfile(profileGuid);
|
||||
@@ -804,7 +804,6 @@ namespace winrt::TerminalApp::implementation
|
||||
_actionDispatch->ResetFontSize({ this, &TerminalPage::_HandleResetFontSize });
|
||||
_actionDispatch->ToggleFullscreen({ this, &TerminalPage::_HandleToggleFullscreen });
|
||||
_actionDispatch->ToggleCommandPalette({ this, &TerminalPage::_HandleToggleCommandPalette });
|
||||
_actionDispatch->ExecuteCommandline({ this, &TerminalPage::_HandleExecuteCommandline });
|
||||
_actionDispatch->SetTabColor({ this, &TerminalPage::_HandleSetTabColor });
|
||||
_actionDispatch->OpenTabColorPicker({ this, &TerminalPage::_HandleOpenTabColorPicker });
|
||||
_actionDispatch->RenameTab({ this, &TerminalPage::_HandleRenameTab });
|
||||
@@ -1315,22 +1314,21 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
const auto controlConnection = _CreateConnectionFromSettings(realGuid, controlSettings);
|
||||
|
||||
float contentWidth = gsl::narrow_cast<float>(_tabContent.ActualWidth());
|
||||
float contentHeight = gsl::narrow_cast<float>(_tabContent.ActualHeight());
|
||||
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
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace winrt::TerminalApp::implementation
|
||||
StartupState _startupState{ StartupState::NotInitialized };
|
||||
|
||||
std::deque<winrt::TerminalApp::ActionAndArgs> _startupActions;
|
||||
winrt::fire_and_forget _ProcessStartupActions(const bool initial);
|
||||
winrt::fire_and_forget _ProcessStartupActions();
|
||||
|
||||
void _ShowAboutDialog();
|
||||
void _ShowCloseWarningDialog();
|
||||
@@ -204,7 +204,6 @@ namespace winrt::TerminalApp::implementation
|
||||
void _HandleOpenTabColorPicker(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandleRenameTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandleToggleCommandPalette(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
void _HandleExecuteCommandline(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||
// Make sure to hook new actions up in _RegisterActionCallbacks!
|
||||
#pragma endregion
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
{
|
||||
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
|
||||
"name": "Windows PowerShell",
|
||||
"commandline": "powershell.exe",
|
||||
"commandline": "%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
|
||||
"icon": "ms-appx:///ProfileIcons/{61c54bbd-c2c6-5271-96e7-009a87ff44bf}.png",
|
||||
"colorScheme": "Campbell",
|
||||
"antialiasingMode": "grayscale",
|
||||
@@ -49,7 +49,7 @@
|
||||
{
|
||||
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
|
||||
"name": "Command Prompt",
|
||||
"commandline": "cmd.exe",
|
||||
"commandline": "%SystemRoot%\\System32\\cmd.exe",
|
||||
"icon": "ms-appx:///ProfileIcons/{0caa0dad-35be-5f56-a8ff-afceeeaa6101}.png",
|
||||
"colorScheme": "Campbell",
|
||||
"antialiasingMode": "grayscale",
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -383,6 +383,40 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
|
||||
//static ConptyConnection* obj = nullptr;
|
||||
//static std::condition_variable condvar;
|
||||
//static std::mutex bufflock;
|
||||
//static std::queue<std::wstring> buff;
|
||||
//static void terminalOutputHandlerMethod()
|
||||
//{
|
||||
// std::unique_lock<std::mutex> lk(bufflock, std::defer_lock);
|
||||
// std::wstring str;
|
||||
// while (true)
|
||||
// {
|
||||
// lk.lock();
|
||||
// condvar.wait(lk, [&] {
|
||||
// if (!buff.empty())
|
||||
// {
|
||||
// str = buff.front();
|
||||
// buff.pop();
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// });
|
||||
// lk.unlock();
|
||||
|
||||
// obj->_DoOutputThreadWork(str);
|
||||
// }
|
||||
//}
|
||||
|
||||
//static std::thread th(terminalOutputHandlerMethod);
|
||||
|
||||
//void ConptyConnection::_DoOutputThreadWork(std::wstring& str)
|
||||
//{
|
||||
// _TerminalOutputHandlers(str);
|
||||
//}
|
||||
|
||||
DWORD ConptyConnection::_OutputThread()
|
||||
{
|
||||
// Keep us alive until the output thread terminates; the destructor
|
||||
@@ -445,6 +479,15 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
|
||||
// Pass the output to our registered event handlers
|
||||
/*bufflock.lock();
|
||||
if (!obj)
|
||||
{
|
||||
obj = this;
|
||||
}
|
||||
buff.emplace(_u16Str);
|
||||
bufflock.unlock();
|
||||
condvar.notify_one();*/
|
||||
|
||||
_TerminalOutputHandlers(_u16Str);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
std::array<char, 4096> _buffer;
|
||||
|
||||
DWORD _OutputThread();
|
||||
|
||||
public:
|
||||
void _DoOutputThreadWork(std::wstring& str);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -622,7 +621,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());
|
||||
@@ -2243,68 +2242,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>(fontSize);
|
||||
// const auto fontWeight = settings.FontWeight();
|
||||
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.
|
||||
@@ -2324,13 +2283,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);
|
||||
@@ -2363,41 +2322,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 = SwapChainPanel().Margin();
|
||||
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 = SwapChainPanel().Margin();
|
||||
width += padding.Left + padding.Right;
|
||||
height += padding.Top + padding.Bottom;
|
||||
|
||||
return { gsl::narrow_cast<float>(width), gsl::narrow_cast<float>(height) };
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -98,14 +98,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())
|
||||
if (_isRunPending.test_and_set(std::memory_order_acquire))
|
||||
{
|
||||
// already pending
|
||||
return;
|
||||
@@ -44,7 +44,7 @@ void ThrottledFunc<>::Run()
|
||||
if (auto self{ weakThis.lock() })
|
||||
{
|
||||
timer.Stop();
|
||||
self->_isRunPending.clear();
|
||||
self->_isRunPending.clear(std::memory_order_release);
|
||||
self->_func();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -283,9 +283,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.
|
||||
|
||||
@@ -1062,10 +1062,10 @@ constexpr unsigned int LOCAL_BUFFER_SIZE = 100;
|
||||
// - S_OK if successful.
|
||||
// - S_OK if we need to wait (check if ppWaiter is not nullptr).
|
||||
// - Or a suitable HRESULT code for math/string/memory failures.
|
||||
[[nodiscard]] HRESULT ApiRoutines::WriteConsoleAImpl(IConsoleOutputObject& context,
|
||||
const std::string_view buffer,
|
||||
size_t& read,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
[[nodiscard]] HRESULT WriteConsoleAImplForReals(IConsoleOutputObject& context,
|
||||
const std::string_view buffer,
|
||||
size_t& read,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1238,6 +1238,62 @@ constexpr unsigned int LOCAL_BUFFER_SIZE = 100;
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
//static IConsoleOutputObject* obj = nullptr;
|
||||
//static std::condition_variable condvar;
|
||||
//static std::mutex bufflock;
|
||||
//static std::queue<std::string> buff;
|
||||
//static void ioWriteConsoleMethod()
|
||||
//{
|
||||
// size_t read = 0;
|
||||
// std::unique_ptr<IWaitRoutine> wait;
|
||||
//
|
||||
// std::unique_lock<std::mutex> lk(bufflock, std::defer_lock);
|
||||
//
|
||||
// std::string str;
|
||||
//
|
||||
// while (true)
|
||||
// {
|
||||
// lk.lock();
|
||||
// condvar.wait(lk, [&] {
|
||||
// if (!buff.empty())
|
||||
// {
|
||||
// str = buff.front();
|
||||
// buff.pop();
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// });
|
||||
// lk.unlock();
|
||||
//
|
||||
// LOG_IF_FAILED(WriteConsoleAImplForReals(*obj, str, read, wait));
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//static std::thread th(ioWriteConsoleMethod);
|
||||
|
||||
[[nodiscard]] HRESULT ApiRoutines::WriteConsoleAImpl(IConsoleOutputObject& context,
|
||||
const std::string_view buffer,
|
||||
size_t& read,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
try
|
||||
{
|
||||
/*read = buffer.size();
|
||||
waiter.reset();
|
||||
|
||||
bufflock.lock();
|
||||
if (!obj)
|
||||
{
|
||||
obj = &context;
|
||||
}
|
||||
buff.emplace(buffer);
|
||||
bufflock.unlock();
|
||||
condvar.notify_one();
|
||||
|
||||
return S_OK;*/
|
||||
return WriteConsoleAImplForReals(context, buffer, read, waiter);
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
// Routine Description:
|
||||
// - Writes Unicode formatted data into the given console output object.
|
||||
// - NOTE: This may be blocked for various console states and will return a wait context pointer if necessary.
|
||||
|
||||
@@ -29,10 +29,10 @@ Renderer::Renderer(IRenderData* pData,
|
||||
_pData(pData),
|
||||
_pThread{ std::move(thread) },
|
||||
_destructing{ false },
|
||||
_clusterBuffer{}
|
||||
_text{},
|
||||
_clusterMap{},
|
||||
_viewport{Viewport::Empty()}
|
||||
{
|
||||
_srViewportPrevious = { 0 };
|
||||
|
||||
for (size_t i = 0; i < cEngines; i++)
|
||||
{
|
||||
IRenderEngine* engine = rgpEngines[i];
|
||||
@@ -208,15 +208,16 @@ void Renderer::TriggerSystemRedraw(const RECT* const prcDirtyClient)
|
||||
// - <none>
|
||||
void Renderer::TriggerRedraw(const Viewport& region)
|
||||
{
|
||||
Viewport view = _pData->GetViewport();
|
||||
Viewport view = _viewport;
|
||||
SMALL_RECT srUpdateRegion = region.ToExclusive();
|
||||
|
||||
if (view.TrimToViewport(&srUpdateRegion))
|
||||
{
|
||||
view.ConvertToOrigin(&srUpdateRegion);
|
||||
std::for_each(_rgpEngines.begin(), _rgpEngines.end(), [&](IRenderEngine* const pEngine) {
|
||||
for (auto pEngine : _rgpEngines)
|
||||
{
|
||||
LOG_IF_FAILED(pEngine->Invalidate(&srUpdateRegion));
|
||||
});
|
||||
}
|
||||
|
||||
_NotifyPaintFrame();
|
||||
}
|
||||
@@ -357,7 +358,7 @@ void Renderer::TriggerSelection()
|
||||
// - True if something changed and we scrolled. False otherwise.
|
||||
bool Renderer::_CheckViewportAndScroll()
|
||||
{
|
||||
SMALL_RECT const srOldViewport = _srViewportPrevious;
|
||||
SMALL_RECT const srOldViewport = _viewport.ToInclusive();
|
||||
SMALL_RECT const srNewViewport = _pData->GetViewport().ToInclusive();
|
||||
|
||||
COORD coordDelta;
|
||||
@@ -369,13 +370,13 @@ bool Renderer::_CheckViewportAndScroll()
|
||||
LOG_IF_FAILED(engine->UpdateViewport(srNewViewport));
|
||||
}
|
||||
|
||||
_srViewportPrevious = srNewViewport;
|
||||
_viewport = Viewport::FromInclusive(srNewViewport);
|
||||
|
||||
// If we're keeping some buffers between calls, let them know about the viewport size
|
||||
// so they can prepare the buffers for changes to either preallocate memory at once
|
||||
// (instead of growing naturally) or shrink down to reduce usage as appropriate.
|
||||
const size_t lineLength = gsl::narrow_cast<size_t>(til::rectangle{ srNewViewport }.width());
|
||||
til::manage_vector(_clusterBuffer, lineLength, _shrinkThreshold);
|
||||
til::manage_vector(_clusterMap, lineLength, _shrinkThreshold);
|
||||
|
||||
if (coordDelta.X != 0 || coordDelta.Y != 0)
|
||||
{
|
||||
@@ -654,7 +655,8 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine)
|
||||
const auto screenLine = Viewport::Offset(bufferLine, -view.Origin());
|
||||
|
||||
// Retrieve the cell information iterator limited to just this line we want to redraw.
|
||||
auto it = buffer.GetCellDataAt(bufferLine.Origin(), bufferLine);
|
||||
auto& r = buffer.GetRowByOffset(bufferLine.Origin().Y);
|
||||
//auto it = buffer.GetCellDataAt(bufferLine.Origin(), bufferLine);
|
||||
|
||||
// Calculate if two things are true:
|
||||
// 1. this row wrapped
|
||||
@@ -664,27 +666,30 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine)
|
||||
(bufferLine.RightExclusive() == buffer.GetSize().Width());
|
||||
|
||||
// Ask the helper to paint through this specific line.
|
||||
_PaintBufferOutputHelper(pEngine, it, screenLine.Origin(), lineWrapped);
|
||||
_PaintBufferOutputHelper(pEngine, r, bufferLine.RightExclusive(), screenLine.Origin(), lineWrapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool _IsAllSpaces(const std::wstring_view v)
|
||||
{
|
||||
// first non-space char is not found (is npos)
|
||||
return v.find_first_not_of(L" ") == decltype(v)::npos;
|
||||
}
|
||||
//static bool _IsAllSpaces(const std::wstring_view v)
|
||||
//{
|
||||
// // first non-space char is not found (is npos)
|
||||
// return v.find_first_not_of(L" ") == decltype(v)::npos;
|
||||
//}
|
||||
|
||||
void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
TextBufferCellIterator it,
|
||||
const ROW& r,
|
||||
const SHORT limitRight,
|
||||
const COORD target,
|
||||
const bool lineWrapped)
|
||||
{
|
||||
auto globalInvert{ _pData->IsScreenReversed() };
|
||||
/*auto globalInvert{ _pData->IsScreenReversed() };*/
|
||||
|
||||
SHORT pos = target.X;
|
||||
|
||||
// If we have valid data, let's figure out how to draw it.
|
||||
if (it)
|
||||
if (pos < limitRight)
|
||||
{
|
||||
// TODO: MSFT: 20961091 - This is a perf issue. Instead of rebuilding this and allocing memory to hold the reinterpretation,
|
||||
// we should have an iterator/view adapter for the rendering.
|
||||
@@ -693,13 +698,18 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
size_t cols = 0;
|
||||
|
||||
// Retrieve the first color.
|
||||
auto color = it->TextAttr();
|
||||
|
||||
size_t colorApplies = 0;
|
||||
const auto& charRow = r.GetCharRow();
|
||||
const auto& attrRow = r.GetAttrRow();
|
||||
auto colorIdx = attrRow.FindAttrIndex(pos, &colorApplies);
|
||||
auto color = attrRow.GetAttrByIndex(colorIdx);
|
||||
|
||||
// And hold the point where we should start drawing.
|
||||
auto screenPoint = target;
|
||||
|
||||
// This outer loop will continue until we reach the end of the text we are trying to draw.
|
||||
while (it)
|
||||
while (pos < limitRight)
|
||||
{
|
||||
// Hold onto the current run color right here for the length of the outer loop.
|
||||
// We'll be changing the persistent one as we run through the inner loops to detect
|
||||
@@ -716,11 +726,12 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
|
||||
// Hold onto the start of this run iterator and the target location where we started
|
||||
// in case we need to do some special work to paint the line drawing characters.
|
||||
const auto currentRunItStart = it;
|
||||
const auto currentRunItStart = pos;
|
||||
const auto currentRunTargetStart = screenPoint;
|
||||
|
||||
// Ensure that our cluster vector is clear.
|
||||
_clusterBuffer.clear();
|
||||
_text.clear();
|
||||
_clusterMap.clear();
|
||||
|
||||
// Reset our flag to know when we're in the special circumstance
|
||||
// of attempting to draw only the right-half of a two-column character
|
||||
@@ -734,25 +745,32 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
// When the color changes, it will save the new color off and break.
|
||||
do
|
||||
{
|
||||
if (color != it->TextAttr())
|
||||
if (colorApplies <= 0)
|
||||
{
|
||||
auto newAttr{ it->TextAttr() };
|
||||
// foreground doesn't matter for runs of spaces (!)
|
||||
// if we trick it . . . we call Paint far fewer times for cmatrix
|
||||
if (!_IsAllSpaces(it->Chars()) || !newAttr.HasIdenticalVisualRepresentationForBlankSpace(color, globalInvert))
|
||||
{
|
||||
color = newAttr;
|
||||
break; // vend this run
|
||||
}
|
||||
colorIdx = attrRow.FindAttrIndex(pos, &colorApplies);
|
||||
color = attrRow.GetAttrByIndex(colorIdx);
|
||||
break;
|
||||
|
||||
//auto newAttr{ it->TextAttr() };
|
||||
//// foreground doesn't matter for runs of spaces (!)
|
||||
//// if we trick it . . . we call Paint far fewer times for cmatrix
|
||||
//if (!_IsAllSpaces(it->Chars()) || !newAttr.HasIdenticalVisualRepresentationForBlankSpace(color, globalInvert))
|
||||
//{
|
||||
// color = newAttr;
|
||||
// break; // vend this run
|
||||
//}
|
||||
}
|
||||
|
||||
// Walk through the text data and turn it into rendering clusters.
|
||||
// Keep the columnCount as we go to improve performance over digging it out of the vector at the end.
|
||||
size_t columnCount = 0;
|
||||
|
||||
const auto dbcsAttr = charRow.DbcsAttrAt(pos);
|
||||
const auto chars = (std::wstring_view)charRow.GlyphAt(pos);
|
||||
|
||||
// If we're on the first cluster to be added and it's marked as "trailing"
|
||||
// (a.k.a. the right half of a two column character), then we need some special handling.
|
||||
if (_clusterBuffer.empty() && it->DbcsAttr().IsTrailing())
|
||||
if (_text.empty() && dbcsAttr.IsTrailing())
|
||||
{
|
||||
// If we have room to move to the left to start drawing...
|
||||
if (screenPoint.X > 0)
|
||||
@@ -762,8 +780,12 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
// And tell the next function to trim off the left half of it.
|
||||
trimLeft = true;
|
||||
// And add one to the number of columns we expect it to take as we insert it.
|
||||
columnCount = it->Columns() + 1;
|
||||
_clusterBuffer.emplace_back(it->Chars(), columnCount);
|
||||
columnCount = 2;
|
||||
//columnCount = it->Columns() + 1;
|
||||
_text.append(chars);
|
||||
_clusterMap.push_back(2);
|
||||
_clusterMap.push_back(0);
|
||||
//_clusterBuffer.emplace_back(chars, columnCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -775,8 +797,14 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
// Otherwise if it's not a special case, just insert it as is.
|
||||
else
|
||||
{
|
||||
columnCount = it->Columns();
|
||||
_clusterBuffer.emplace_back(it->Chars(), columnCount);
|
||||
columnCount = dbcsAttr.IsLeading() ? 2 : 1;
|
||||
_text.append(chars);
|
||||
_clusterMap.push_back((UINT16)columnCount);
|
||||
if (columnCount > 1)
|
||||
{
|
||||
_clusterMap.push_back(0);
|
||||
}
|
||||
//_clusterBuffer.emplace_back(chars, columnCount);
|
||||
}
|
||||
|
||||
if (columnCount > 1)
|
||||
@@ -785,13 +813,15 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
}
|
||||
|
||||
// Advance the cluster and column counts.
|
||||
it += columnCount > 0 ? columnCount : 1; // prevent infinite loop for no visible columns
|
||||
const auto delta = (SHORT)(columnCount > 0 ? columnCount : 1); // prevent infinite loop for no visible columns
|
||||
pos += delta;
|
||||
colorApplies -= delta;
|
||||
cols += columnCount;
|
||||
|
||||
} while (it);
|
||||
} while (pos < limitRight);
|
||||
|
||||
// Do the painting.
|
||||
THROW_IF_FAILED(pEngine->PaintBufferLine({ _clusterBuffer.data(), _clusterBuffer.size() }, screenPoint, trimLeft, lineWrapped));
|
||||
THROW_IF_FAILED(pEngine->PaintBufferLine(_text, { _clusterMap.data(), _clusterMap.size() }, screenPoint, trimLeft, lineWrapped));
|
||||
|
||||
// If we're allowed to do grid drawing, draw that now too (since it will be coupled with the color data)
|
||||
// We're only allowed to draw the grid lines under certain circumstances.
|
||||
@@ -816,7 +846,7 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
// Do that in the future if some WPR trace points you to this spot as super bad.
|
||||
for (auto colsPainted = 0u; colsPainted < cols; ++colsPainted, ++lineIt, ++lineTarget.X)
|
||||
{
|
||||
auto lines = lineIt->TextAttr();
|
||||
auto lines = attrRow.GetAttrByColumn(lineIt);
|
||||
_PaintBufferOutputGridLineHelper(pEngine, lines, 1, lineTarget);
|
||||
}
|
||||
}
|
||||
@@ -1013,7 +1043,7 @@ void Renderer::_PaintOverlay(IRenderEngine& engine,
|
||||
|
||||
auto it = overlay.buffer.GetCellLineDataAt(source);
|
||||
|
||||
_PaintBufferOutputHelper(&engine, it, target, false);
|
||||
//_PaintBufferOutputHelper(&engine, it, target, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,10 +99,16 @@ namespace Microsoft::Console::Render
|
||||
void _PaintBufferOutput(_In_ IRenderEngine* const pEngine);
|
||||
|
||||
void _PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
TextBufferCellIterator it,
|
||||
const ROW& r,
|
||||
const SHORT limitRight,
|
||||
const COORD target,
|
||||
const bool lineWrapped);
|
||||
|
||||
//void _PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
// TextBufferCellIterator it,
|
||||
// const COORD target,
|
||||
// const bool lineWrapped);
|
||||
|
||||
static IRenderEngine::GridLines s_GetGridlines(const TextAttribute& textAttribute) noexcept;
|
||||
|
||||
void _PaintBufferOutputGridLineHelper(_In_ IRenderEngine* const pEngine,
|
||||
@@ -120,10 +126,12 @@ namespace Microsoft::Console::Render
|
||||
|
||||
[[nodiscard]] HRESULT _PerformScrolling(_In_ IRenderEngine* const pEngine);
|
||||
|
||||
SMALL_RECT _srViewportPrevious;
|
||||
Microsoft::Console::Types::Viewport _viewport;
|
||||
|
||||
static constexpr float _shrinkThreshold = 0.8f;
|
||||
std::vector<Cluster> _clusterBuffer;
|
||||
std::wstring _text;
|
||||
std::vector<UINT16> _clusterMap;
|
||||
//std::vector<Cluster> _clusterBuffer;
|
||||
|
||||
std::vector<SMALL_RECT> _GetSelectionRects() const;
|
||||
void _ScrollPreviousSelection(const til::point delta);
|
||||
|
||||
@@ -162,17 +162,17 @@ DWORD WINAPI RenderThread::_ThreadProc()
|
||||
{
|
||||
WaitForSingleObject(_hPaintEnabledEvent, INFINITE);
|
||||
|
||||
if (!_fNextFrameRequested.exchange(false))
|
||||
if (!_fNextFrameRequested.exchange(false, std::memory_order_acq_rel))
|
||||
{
|
||||
// <--
|
||||
// If `NotifyPaint` is called at this point, then it will not
|
||||
// set the event because `_fWaiting` is not `true` yet so we have
|
||||
// to check again below.
|
||||
|
||||
_fWaiting.store(true);
|
||||
_fWaiting.store(true, std::memory_order_release);
|
||||
|
||||
// check again now (see comment above)
|
||||
if (!_fNextFrameRequested.exchange(false))
|
||||
if (!_fNextFrameRequested.exchange(false, std::memory_order_acq_rel))
|
||||
{
|
||||
// Wait until a next frame is requested.
|
||||
WaitForSingleObject(_hEvent, INFINITE);
|
||||
@@ -193,7 +193,7 @@ DWORD WINAPI RenderThread::_ThreadProc()
|
||||
// expensive operation, we should reset the event to not render
|
||||
// again if nothing changed.
|
||||
|
||||
_fWaiting.store(false);
|
||||
_fWaiting.store(false, std::memory_order_release);
|
||||
|
||||
// see comment above
|
||||
ResetEvent(_hEvent);
|
||||
@@ -218,13 +218,13 @@ DWORD WINAPI RenderThread::_ThreadProc()
|
||||
|
||||
void RenderThread::NotifyPaint()
|
||||
{
|
||||
if (_fWaiting.load())
|
||||
if (_fWaiting.load(std::memory_order_acquire))
|
||||
{
|
||||
SetEvent(_hEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
_fNextFrameRequested.store(true);
|
||||
_fNextFrameRequested.store(true, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,25 +70,27 @@ CATCH_RETURN()
|
||||
// - clusters - From the backing buffer, the text to be displayed clustered by the columns it should consume.
|
||||
// Return Value:
|
||||
// - S_OK or suitable memory management issue.
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE CustomTextLayout::AppendClusters(const std::basic_string_view<::Microsoft::Console::Render::Cluster> clusters)
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE CustomTextLayout::AppendClusters(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap)
|
||||
try
|
||||
{
|
||||
_textClusterColumns.reserve(_textClusterColumns.size() + clusters.size());
|
||||
_text.append(text);
|
||||
_textClusterColumns.insert(_textClusterColumns.end(), clusterMap.cbegin(), clusterMap.cend());
|
||||
|
||||
for (const auto& cluster : clusters)
|
||||
{
|
||||
const auto cols = gsl::narrow<UINT16>(cluster.GetColumns());
|
||||
const auto text = cluster.GetText();
|
||||
//for (const auto& cluster : clusters)
|
||||
//{
|
||||
// const auto cols = gsl::narrow<UINT16>(cluster.GetColumns());
|
||||
// const auto text = cluster.GetText();
|
||||
|
||||
// Push back the number of columns for this bit of text.
|
||||
_textClusterColumns.push_back(cols);
|
||||
// // Push back the number of columns for this bit of text.
|
||||
// _textClusterColumns.push_back(cols);
|
||||
|
||||
// If there is more than one text character here, push 0s for the rest of the columns
|
||||
// of the text run.
|
||||
_textClusterColumns.resize(_textClusterColumns.size() + base::ClampSub(text.size(), 1u), gsl::narrow_cast<UINT16>(0u));
|
||||
// // If there is more than one text character here, push 0s for the rest of the columns
|
||||
// // of the text run.
|
||||
// _textClusterColumns.resize(_textClusterColumns.size() + base::ClampSub(text.size(), 1u), gsl::narrow_cast<UINT16>(0u));
|
||||
|
||||
_text += text;
|
||||
}
|
||||
// _text += text;
|
||||
//}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ namespace Microsoft::Console::Render
|
||||
size_t const width,
|
||||
IBoxDrawingEffect* const boxEffect);
|
||||
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE AppendClusters(const std::basic_string_view<::Microsoft::Console::Render::Cluster> clusters);
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE AppendClusters(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap);
|
||||
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE Reset() noexcept;
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ DxEngine::DxEngine() :
|
||||
_invalidateFullRows{ true },
|
||||
_invalidMap{},
|
||||
_invalidScroll{},
|
||||
_allInvalid{ false },
|
||||
_firstFrame{ true },
|
||||
_presentParams{ 0 },
|
||||
_presentReady{ false },
|
||||
@@ -842,6 +843,11 @@ void DxEngine::_InvalidateRectangle(const til::rectangle& rc)
|
||||
_invalidMap.set(invalidate);
|
||||
}
|
||||
|
||||
bool DxEngine::_IsAllInvalid() const noexcept
|
||||
{
|
||||
return std::llabs(_invalidScroll.y()) >= _invalidMap.size().height();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Invalidates a rectangle described in characters
|
||||
// Arguments:
|
||||
@@ -853,7 +859,10 @@ try
|
||||
{
|
||||
RETURN_HR_IF_NULL(E_INVALIDARG, psrRegion);
|
||||
|
||||
_InvalidateRectangle(Viewport::FromExclusive(*psrRegion).ToInclusive());
|
||||
if (!_allInvalid)
|
||||
{
|
||||
_InvalidateRectangle(Viewport::FromExclusive(*psrRegion).ToInclusive());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -870,7 +879,10 @@ try
|
||||
{
|
||||
RETURN_HR_IF_NULL(E_INVALIDARG, pcoordCursor);
|
||||
|
||||
_InvalidateRectangle(til::rectangle{ *pcoordCursor, til::size{ 1, 1 } });
|
||||
if (!_allInvalid)
|
||||
{
|
||||
/*_InvalidateRectangle(til::rectangle{ *pcoordCursor, til::size{ 1, 1 } });*/
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -887,9 +899,12 @@ try
|
||||
{
|
||||
RETURN_HR_IF_NULL(E_INVALIDARG, prcDirtyClient);
|
||||
|
||||
// Dirty client is in pixels. Use divide specialization against glyph factor to make conversion
|
||||
// to cells.
|
||||
_InvalidateRectangle(til::rectangle{ *prcDirtyClient }.scale_down(_glyphCell));
|
||||
if (!_allInvalid)
|
||||
{
|
||||
// Dirty client is in pixels. Use divide specialization against glyph factor to make conversion
|
||||
// to cells.
|
||||
_InvalidateRectangle(til::rectangle{ *prcDirtyClient }.scale_down(_glyphCell));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -903,9 +918,12 @@ CATCH_RETURN();
|
||||
// - S_OK
|
||||
[[nodiscard]] HRESULT DxEngine::InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept
|
||||
{
|
||||
for (const auto& rect : rectangles)
|
||||
if (!_allInvalid)
|
||||
{
|
||||
RETURN_IF_FAILED(Invalidate(&rect));
|
||||
for (const auto& rect : rectangles)
|
||||
{
|
||||
RETURN_IF_FAILED(Invalidate(&rect));
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@@ -925,11 +943,15 @@ try
|
||||
|
||||
const til::point deltaCells{ *pcoordDelta };
|
||||
|
||||
if (deltaCells != til::point{ 0, 0 })
|
||||
if (!_allInvalid)
|
||||
{
|
||||
// Shift the contents of the map and fill in revealed area.
|
||||
_invalidMap.translate(deltaCells, true);
|
||||
_invalidScroll += deltaCells;
|
||||
if (deltaCells != til::point{ 0, 0 })
|
||||
{
|
||||
// Shift the contents of the map and fill in revealed area.
|
||||
_invalidMap.translate(deltaCells, true);
|
||||
_invalidScroll += deltaCells;
|
||||
_allInvalid = _IsAllInvalid();
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
@@ -946,6 +968,7 @@ CATCH_RETURN();
|
||||
try
|
||||
{
|
||||
_invalidMap.set_all();
|
||||
_allInvalid = true;
|
||||
|
||||
// Since everything is invalidated here, mark this as a "first frame", so
|
||||
// that we won't use incremental drawing on it. The caller of this intended
|
||||
@@ -1204,6 +1227,7 @@ try
|
||||
}
|
||||
|
||||
_invalidMap.reset_all();
|
||||
_allInvalid = false;
|
||||
|
||||
_invalidScroll = {};
|
||||
|
||||
@@ -1414,7 +1438,8 @@ CATCH_RETURN()
|
||||
// - fTrimLeft - Whether or not to trim off the left half of a double wide character
|
||||
// Return Value:
|
||||
// - S_OK or relevant DirectX error
|
||||
[[nodiscard]] HRESULT DxEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT DxEngine::PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
COORD const coord,
|
||||
const bool /*trimLeft*/,
|
||||
const bool /*lineWrapped*/) noexcept
|
||||
@@ -1425,7 +1450,7 @@ try
|
||||
|
||||
// Create the text layout
|
||||
RETURN_IF_FAILED(_customLayout->Reset());
|
||||
RETURN_IF_FAILED(_customLayout->AppendClusters(clusters));
|
||||
RETURN_IF_FAILED(_customLayout->AppendClusters(text, clusterMap));
|
||||
|
||||
// Layout then render the text
|
||||
RETURN_IF_FAILED(_customLayout->Draw(_drawingContext.get(), _customRenderer.Get(), origin.x, origin.y));
|
||||
@@ -1815,10 +1840,12 @@ try
|
||||
{
|
||||
RETURN_HR_IF_NULL(E_INVALIDARG, pResult);
|
||||
|
||||
const Cluster cluster(glyph, 0); // columns don't matter, we're doing analysis not layout.
|
||||
//const Cluster cluster(glyph, 0); // columns don't matter, we're doing analysis not layout.
|
||||
|
||||
UINT16 col = 0;
|
||||
|
||||
RETURN_IF_FAILED(_customLayout->Reset());
|
||||
RETURN_IF_FAILED(_customLayout->AppendClusters({ &cluster, 1 }));
|
||||
RETURN_IF_FAILED(_customLayout->AppendClusters(glyph, { &col, 1 }));
|
||||
|
||||
UINT32 columns = 0;
|
||||
RETURN_IF_FAILED(_customLayout->GetColumns(&columns));
|
||||
|
||||
@@ -85,7 +85,8 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT PaintBackground() noexcept override;
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
COORD const coord,
|
||||
bool const fTrimLeft,
|
||||
const bool lineWrapped) noexcept override;
|
||||
@@ -158,6 +159,7 @@ namespace Microsoft::Console::Render
|
||||
bool _invalidateFullRows;
|
||||
til::bitmap _invalidMap;
|
||||
til::point _invalidScroll;
|
||||
bool _allInvalid;
|
||||
|
||||
bool _presentReady;
|
||||
std::vector<RECT> _presentDirty;
|
||||
@@ -272,6 +274,7 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] til::size _GetClientSize() const;
|
||||
|
||||
void _InvalidateRectangle(const til::rectangle& rc);
|
||||
bool _IsAllInvalid() const noexcept;
|
||||
|
||||
[[nodiscard]] D2D1_COLOR_F _ColorFFromColorRef(const COLORREF color) noexcept;
|
||||
|
||||
|
||||
@@ -42,7 +42,8 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] HRESULT ScrollFrame() noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT PaintBackground() noexcept override;
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool trimLeft,
|
||||
const bool lineWrapped) noexcept override;
|
||||
|
||||
@@ -284,14 +284,15 @@ using namespace Microsoft::Console::Render;
|
||||
// See: Win7: 390673, 447839 and then superseded by http://osgvsowi/638274 when FE/non-FE rendering condensed.
|
||||
//#define CONSOLE_EXTTEXTOUT_FLAGS ETO_OPAQUE | ETO_CLIPPED
|
||||
//#define MAX_POLY_LINES 80
|
||||
[[nodiscard]] HRESULT GdiEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT GdiEngine::PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool trimLeft,
|
||||
const bool /*lineWrapped*/) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto cchLine = clusters.size();
|
||||
const auto cchLine = text.size();
|
||||
|
||||
// Exit early if there are no lines to draw.
|
||||
RETURN_HR_IF(S_OK, 0 == cchLine);
|
||||
@@ -316,12 +317,13 @@ using namespace Microsoft::Console::Render;
|
||||
// Convert data from clusters into the text array and the widths array.
|
||||
for (size_t i = 0; i < cchLine; i++)
|
||||
{
|
||||
const auto& cluster = clusters.at(i);
|
||||
//const auto& cluster = clusters.at(i);
|
||||
|
||||
// Our GDI renderer hasn't and isn't going to handle things above U+FFFF or sequences.
|
||||
// So replace anything complicated with a replacement character for drawing purposes.
|
||||
pwsPoly[i] = cluster.GetTextAsSingle();
|
||||
rgdxPoly[i] = gsl::narrow<int>(cluster.GetColumns()) * coordFontSize.X;
|
||||
pwsPoly[i] = text[i];
|
||||
//cluster.GetTextAsSingle();
|
||||
rgdxPoly[i] = gsl::narrow<int>(clusterMap[i]) * coordFontSize.X;
|
||||
cchCharWidths += rgdxPoly[i];
|
||||
}
|
||||
|
||||
@@ -365,7 +367,7 @@ using namespace Microsoft::Console::Render;
|
||||
}
|
||||
|
||||
pPolyTextLine->lpstr = pwsPoly.release();
|
||||
pPolyTextLine->n = gsl::narrow<UINT>(clusters.size());
|
||||
pPolyTextLine->n = gsl::narrow<UINT>(text.size());
|
||||
pPolyTextLine->x = ptDraw.x;
|
||||
pPolyTextLine->y = ptDraw.y;
|
||||
pPolyTextLine->uiFlags = ETO_OPAQUE | ETO_CLIPPED;
|
||||
|
||||
@@ -70,7 +70,8 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] virtual HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept = 0;
|
||||
|
||||
[[nodiscard]] virtual HRESULT PaintBackground() noexcept = 0;
|
||||
[[nodiscard]] virtual HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] virtual HRESULT PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool fTrimLeft,
|
||||
const bool lineWrapped) noexcept = 0;
|
||||
|
||||
@@ -305,7 +305,8 @@ CATCH_RETURN();
|
||||
// - fTrimLeft - Whether or not to trim off the left half of a double wide character
|
||||
// Return Value:
|
||||
// - S_FALSE
|
||||
[[nodiscard]] HRESULT UiaEngine::PaintBufferLine(std::basic_string_view<Cluster> const /*clusters*/,
|
||||
[[nodiscard]] HRESULT UiaEngine::PaintBufferLine(std::wstring_view /*text*/,
|
||||
std::basic_string_view<UINT16> /*clusterMap*/,
|
||||
COORD const /*coord*/,
|
||||
const bool /*trimLeft*/,
|
||||
const bool /*lineWrapped*/) noexcept
|
||||
|
||||
@@ -51,7 +51,8 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT PaintBackground() noexcept override;
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
COORD const coord,
|
||||
bool const fTrimLeft,
|
||||
const bool lineWrapped) noexcept override;
|
||||
|
||||
@@ -529,14 +529,15 @@ CATCH_RETURN();
|
||||
// will be false.
|
||||
// Return Value:
|
||||
// - S_OK or suitable HRESULT error from writing pipe.
|
||||
[[nodiscard]] HRESULT XtermEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT XtermEngine::PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool /*trimLeft*/,
|
||||
const bool lineWrapped) noexcept
|
||||
{
|
||||
return _fUseAsciiOnly ?
|
||||
VtEngine::_PaintAsciiBufferLine(clusters, coord) :
|
||||
VtEngine::_PaintUtf8BufferLine(clusters, coord, lineWrapped);
|
||||
VtEngine::_PaintAsciiBufferLine(text, clusterMap, coord) :
|
||||
VtEngine::_PaintUtf8BufferLine(text, clusterMap, coord, lineWrapped);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -45,7 +45,8 @@ namespace Microsoft::Console::Render
|
||||
const WORD legacyColorAttribute,
|
||||
const ExtendedAttributes extendedAttrs,
|
||||
const bool isSettingDefaultBrushes) noexcept override;
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool trimLeft,
|
||||
const bool lineWrapped) noexcept override;
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
#include "vtrenderer.hpp"
|
||||
#include "../../inc/conattrs.hpp"
|
||||
#include "../../types/inc/convert.hpp"
|
||||
@@ -125,12 +128,13 @@ using namespace Microsoft::Console::Types;
|
||||
// will be false.
|
||||
// Return Value:
|
||||
// - S_OK or suitable HRESULT error from writing pipe.
|
||||
[[nodiscard]] HRESULT VtEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT VtEngine::PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool /*trimLeft*/,
|
||||
const bool /*lineWrapped*/) noexcept
|
||||
{
|
||||
return VtEngine::_PaintAsciiBufferLine(clusters, coord);
|
||||
return VtEngine::_PaintAsciiBufferLine(text, clusterMap, coord);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -342,27 +346,28 @@ using namespace Microsoft::Console::Types;
|
||||
// - coord - character coordinate target to render within viewport
|
||||
// Return Value:
|
||||
// - S_OK or suitable HRESULT error from writing pipe.
|
||||
[[nodiscard]] HRESULT VtEngine::_PaintAsciiBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT VtEngine::_PaintAsciiBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
RETURN_IF_FAILED(_MoveCursor(coord));
|
||||
|
||||
std::wstring wstr;
|
||||
wstr.reserve(clusters.size());
|
||||
/*_bufferLine.clear();*/
|
||||
//_bufferLine.reserve(clusters.size());
|
||||
|
||||
short totalWidth = 0;
|
||||
/*short totalWidth = 0;
|
||||
for (const auto& cluster : clusters)
|
||||
{
|
||||
wstr.append(cluster.GetText());
|
||||
_bufferLine.append(cluster.GetText());
|
||||
RETURN_IF_FAILED(ShortAdd(totalWidth, gsl::narrow<short>(cluster.GetColumns()), &totalWidth));
|
||||
}
|
||||
}*/
|
||||
|
||||
RETURN_IF_FAILED(VtEngine::_WriteTerminalAscii(wstr));
|
||||
RETURN_IF_FAILED(VtEngine::_WriteTerminalAscii(text));
|
||||
|
||||
// Update our internal tracker of the cursor's position
|
||||
_lastText.X += totalWidth;
|
||||
_lastText.X += (SHORT)std::accumulate(clusterMap.begin(), clusterMap.end(), 0);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -377,7 +382,8 @@ using namespace Microsoft::Console::Types;
|
||||
// - coord - character coordinate target to render within viewport
|
||||
// Return Value:
|
||||
// - S_OK or suitable HRESULT error from writing pipe.
|
||||
[[nodiscard]] HRESULT VtEngine::_PaintUtf8BufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT VtEngine::_PaintUtf8BufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool lineWrapped) noexcept
|
||||
{
|
||||
@@ -386,21 +392,21 @@ using namespace Microsoft::Console::Types;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
std::wstring unclusteredString;
|
||||
unclusteredString.reserve(clusters.size());
|
||||
short totalWidth = 0;
|
||||
for (const auto& cluster : clusters)
|
||||
/*_bufferLine.clear();
|
||||
_bufferLine.reserve(clusters.size());*/
|
||||
short totalWidth = (SHORT)std::accumulate(clusterMap.begin(), clusterMap.end(), 0);
|
||||
/*for (const auto& cluster : clusters)
|
||||
{
|
||||
unclusteredString.append(cluster.GetText());
|
||||
_bufferLine.append(cluster.GetText());
|
||||
RETURN_IF_FAILED(ShortAdd(totalWidth, static_cast<short>(cluster.GetColumns()), &totalWidth));
|
||||
}
|
||||
const size_t cchLine = unclusteredString.size();
|
||||
}*/
|
||||
const size_t cchLine = text.size();
|
||||
|
||||
bool foundNonspace = false;
|
||||
size_t lastNonSpace = 0;
|
||||
for (size_t i = 0; i < cchLine; i++)
|
||||
{
|
||||
if (unclusteredString.at(i) != L'\x20')
|
||||
if (text.at(i) != L'\x20')
|
||||
{
|
||||
lastNonSpace = i;
|
||||
foundNonspace = true;
|
||||
@@ -494,8 +500,7 @@ using namespace Microsoft::Console::Types;
|
||||
RETURN_IF_FAILED(_MoveCursor(coord));
|
||||
|
||||
// Write the actual text string
|
||||
std::wstring wstr = std::wstring(unclusteredString.data(), cchActual);
|
||||
RETURN_IF_FAILED(VtEngine::_WriteTerminalUtf8(wstr));
|
||||
RETURN_IF_FAILED(VtEngine::_WriteTerminalUtf8({ text.data(), cchActual }));
|
||||
|
||||
// GH#4415, GH#5181
|
||||
// If the renderer told us that this was a wrapped line, then mark
|
||||
|
||||
@@ -101,6 +101,51 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
|
||||
}
|
||||
CATCH_RETURN();
|
||||
}
|
||||
//
|
||||
//static HANDLE obj = nullptr;
|
||||
//static std::atomic<bool> awake = false;
|
||||
//static std::atomic<bool> moreData = false;
|
||||
//static std::condition_variable condvar;
|
||||
//static std::mutex bufflock;
|
||||
//static std::string buff;
|
||||
//static void vtRenderWriteMethod()
|
||||
//{
|
||||
// std::unique_lock<std::mutex> lk(bufflock, std::defer_lock);
|
||||
//
|
||||
// std::string str;
|
||||
//
|
||||
// while (true)
|
||||
// {
|
||||
// lk.lock();
|
||||
//
|
||||
// bool hasData = moreData.load();
|
||||
//
|
||||
// if (!hasData)
|
||||
// {
|
||||
// awake.store(false);
|
||||
// condvar.wait(lk, [&] {
|
||||
// if (!buff.empty())
|
||||
// {
|
||||
// str.swap(buff);
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// });
|
||||
// awake.store(true);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// str.swap(buff);
|
||||
// moreData.store(false);
|
||||
// }
|
||||
// lk.unlock();
|
||||
//
|
||||
// WriteFile(obj, str.data(), static_cast<DWORD>(str.size()), nullptr, nullptr);
|
||||
// str.clear();
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//static std::thread th(vtRenderWriteMethod);
|
||||
|
||||
[[nodiscard]] HRESULT VtEngine::_Flush() noexcept
|
||||
{
|
||||
@@ -112,6 +157,23 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
|
||||
}
|
||||
#endif
|
||||
|
||||
//bufflock.lock();
|
||||
//if (!obj)
|
||||
//{
|
||||
// obj = _hFile.get();
|
||||
//}
|
||||
//buff.append(_buffer);
|
||||
//moreData.store(true);
|
||||
//bool needToWake = !awake.load();
|
||||
//bufflock.unlock();
|
||||
//if (needToWake)
|
||||
//{
|
||||
// condvar.notify_one();
|
||||
//}
|
||||
//_buffer.clear();
|
||||
|
||||
//return S_OK;
|
||||
|
||||
if (!_pipeBroken)
|
||||
{
|
||||
bool fSuccess = !!WriteFile(_hFile.get(), _buffer.data(), static_cast<DWORD>(_buffer.size()), nullptr, nullptr);
|
||||
|
||||
@@ -145,7 +145,7 @@ void RenderTracing::TraceInvalidateScroll(const til::point scroll) const
|
||||
}
|
||||
|
||||
void RenderTracing::TraceStartPaint(const bool quickReturn,
|
||||
const til::bitmap invalidMap,
|
||||
const til::bitmap& invalidMap,
|
||||
const til::rectangle lastViewport,
|
||||
const til::point scrollDelt,
|
||||
const bool cursorMoved,
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
void TraceTriggerCircling(const bool newFrame) const;
|
||||
void TraceInvalidateScroll(const til::point scroll) const;
|
||||
void TraceStartPaint(const bool quickReturn,
|
||||
const til::bitmap invalidMap,
|
||||
const til::bitmap& invalidMap,
|
||||
const til::rectangle lastViewport,
|
||||
const til::point scrollDelta,
|
||||
const bool cursorMoved,
|
||||
|
||||
@@ -63,7 +63,8 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] virtual HRESULT ScrollFrame() noexcept = 0;
|
||||
|
||||
[[nodiscard]] HRESULT PaintBackground() noexcept override;
|
||||
[[nodiscard]] virtual HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] virtual HRESULT PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool trimLeft,
|
||||
const bool lineWrapped) noexcept override;
|
||||
@@ -224,11 +225,16 @@ namespace Microsoft::Console::Render
|
||||
|
||||
bool _WillWriteSingleChar() const;
|
||||
|
||||
[[nodiscard]] HRESULT _PaintUtf8BufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
// buffer space for these two functions to build their lines
|
||||
// so they don't have to alloc/free in a tight loop
|
||||
//std::wstring _bufferLine;
|
||||
[[nodiscard]] HRESULT _PaintUtf8BufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool lineWrapped) noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _PaintAsciiBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT _PaintAsciiBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord) noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _WriteTerminalUtf8(const std::wstring_view str) noexcept;
|
||||
|
||||
Reference in New Issue
Block a user