Compare commits

..

26 Commits

Author SHA1 Message Date
Dustin L. Howett
aa11bd1d9d Migrate spelling-0.0.21 changes from main 2020-07-14 13:05:42 -07:00
Dustin L. Howett
bd4216f926 Migrate spelling-0.0.19 changes from main 2020-07-14 13:05:42 -07:00
Michael Niksa
a8be923688 Only check char row reference out of bounds in debug. 2020-07-14 13:05:42 -07:00
Michael Niksa
1eea75e3e7 Get cell with array notation to skip verificaton on release build. we're already checking this all over the place. 2020-07-14 12:56:13 -07:00
Michael Niksa
ad723f9671 use release/acquire over seq cst on the atomic flag in throttledfunc 2020-07-14 12:03:48 -07:00
Michael Niksa
4db39a6f55 Don't use checked lookups when we already know we're in bounds for AttrRow 2020-07-14 12:03:33 -07:00
Michael Niksa
d7255fdbef Dump this try/catch block. Everything is noexcept except for the failfast which is legitimate so don't waste time setting up and tearing down that whole fence. 2020-07-14 11:40:54 -07:00
Michael Niksa
23aef43c81 commit attr runs less frequently. accumulate lengths. 2020-07-14 11:33:19 -07:00
Michael Niksa
8c1a45f6f0 The check for RowByOffset in bounds is quite expensive on massive output. Drop it. Use the array notation so it will still work in debug mode for development but not on release. We are already restricting the row all over the place on input/output so this should be mostly redundant anyway. 2020-07-14 11:06:00 -07:00
Michael Niksa
ebe9016356 use acquire/release instead of seq_cst for single producer single consumer situation. 2020-07-14 10:16:59 -07:00
Michael Niksa
d4885149ae cache the viewport to make invalidation faster. 2020-07-14 10:04:13 -07:00
Michael Niksa
ee5c5a474b change interface to not use Clusters. Just build a string and a clustermap vector. 2020-07-13 16:59:33 -07:00
Michael Niksa
4aa62f9edd Go at the buffer a bit more directly and get some perf. 2020-07-13 16:29:11 -07:00
Michael Niksa
cc6ad0b99b Nerf the queues and go back to synchronous. 2020-07-13 15:38:19 -07:00
Michael Niksa
28e1e226ad don't waste time invalidating something that is already fully invalid. 2020-07-13 15:25:20 -07:00
Michael Niksa
6f23280011 Revert "NOT FASTER: Make the bitmap smaller and blow up the rectangles on the way out."
This reverts commit 37dab43af0.
2020-07-13 15:24:09 -07:00
Michael Niksa
37dab43af0 NOT FASTER: Make the bitmap smaller and blow up the rectangles on the way out. 2020-07-08 14:00:46 -07:00
Michael Niksa
d77e55596b Also gross but it breaks the conpty connection into a read step and a write step. 2020-07-08 13:24:10 -07:00
Michael Niksa
0be1c9deef This is gross but it sort of breaks the VtEngine::_Flush off into its own thread. 2020-07-08 13:10:33 -07:00
Michael Niksa
5f9321310f cache the size viewport structure inside TextBuffer to cut down on lookup time. 2020-07-06 16:17:31 -07:00
Michael Niksa
061e636163 don't copy the bitmap on the way into the tracing function. 2020-07-01 16:27:05 -07:00
Michael Niksa
8aaa93f139 Hold the buffer line string in the object so we save all the alloc/dealloc time. 2020-07-01 15:58:44 -07:00
Michael Niksa
90a24b20b8 Wow. Much fast. Very zoom. 2020-06-29 16:29:04 -07:00
Mike Griese
aa1ed0a19c Add support for the Command Palette (#6635)
## Summary of the Pull Request

![command-palette-001](https://user-images.githubusercontent.com/18356694/85313480-b6dbef00-b47d-11ea-8a8f-a802d26c2f9b.gif)


This adds a first iteration on the command palette. Notable missing features are:
* Commandline mode: This will be a follow-up PR, following the merge of #6537
* nested and iterable commands: These will additionally be a follow-up PR.

This is also additionally based off the addenda in #6532. 

This does not bind a key for the palette by default. That will be done when the above follow-ups are completed.

## References
* #2046 - The original command palette thread
* #5400 - This is the megathread for all command palette issues, which is tracking a bunch of additional follow up work 
* #5674 and #6532 - specs
* #6537 - related

## PR Checklist
* [x] Closes #2046
  - incidentally also closes #6645
* [x] I work here
* [x] Tests added/passed
* [ ] Requires documentation to be updated - delaying this until it's more polished.


## Detailed Description of the Pull Request / Additional comments

* There's a lot of code for autogenerating command names. That's all in `ActionArgs.cpp`, because each case is so _not_ boilerplate, unlike the rest of the code in `ActionArgs.h`.

## Validation Steps Performed

* I've been playing with this for months.
* Tests
* Selfhost with the team
2020-06-26 20:38:02 +00:00
Dustin L. Howett
2fc1ef04ce Hardcode the paths to Windows PowerShell and CMD (#6684)
Occasionally, we get users with corrupt PATH environment variables: they
can't lauch PowerShell, because for some reason it's dropped off their
PATH. We also get users who have stray applications named
`powershell.exe` just lying around in random system directories.

We can combat both of these issues by simply hardcoding where we expect
PowerShell and CMD to live. %SystemRoot% was chosen over %WINDIR%
because apparently (according to Stack Overflow), SystemPath is
read-only and WINDIR isn't.

Refs #6039, #4390, #4228 (powershell was not found)
Refs #4682, Fixes #6082 (stray powershell.exe)
2020-06-26 17:33:38 +00:00
Dustin L. Howett
fefd1408f2 When we add a new tab in compact mode, re-enforce Compact mode (#6670)
This workaround was suggested by @chingucoding in
microsoft/microsoft-ui-xaml#2711

Fixes #6570

## References

microsoft/microsoft-ui-xaml#2711
#6570

## PR Checklist
* [x] Closes an issue
* [x] CLA
* [x] Tested
* [x] Docs not required
* [x] Schema not required
2020-06-25 21:21:48 +00:00
60 changed files with 656 additions and 720 deletions

View File

@@ -108,7 +108,12 @@ TextAttribute ATTR_ROW::GetAttrByColumn(const size_t column,
{
THROW_HR_IF(E_INVALIDARG, column >= _cchRowWidth);
const auto runPos = FindAttrIndex(column, pApplies);
return _list.at(runPos).GetAttributes();
return GetAttrByIndex(runPos);
}
TextAttribute ATTR_ROW::GetAttrByIndex(const size_t index) const
{
return _list.at(index).GetAttributes();
}
// Routine Description:
@@ -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;
}

View File

@@ -36,6 +36,8 @@ public:
TextAttribute GetAttrByColumn(const size_t column,
size_t* const pApplies) const;
TextAttribute GetAttrByIndex(const size_t index) const;
size_t GetNumberOfRuns() const noexcept;
size_t FindAttrIndex(const size_t index,

View File

@@ -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 };
}

View File

@@ -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:

View File

@@ -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())

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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());

View File

@@ -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") },

View File

@@ -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"

View File

@@ -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" };

View File

@@ -101,11 +101,6 @@ namespace TerminalApp
SplitType SplitMode { get; };
};
[default_interface] runtimeclass ExecuteCommandlineArgs : IActionArgs
{
String Commandline;
}
[default_interface] runtimeclass OpenSettingsArgs : IActionArgs
{
SettingsTarget Target { get; };

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();
}
}
}

View File

@@ -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();
};
}

View File

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

View File

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

View File

@@ -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>

View File

@@ -164,10 +164,6 @@ namespace winrt::TerminalApp::implementation
_ToggleCommandPaletteHandlers(*this, *eventArgs);
break;
}
case ShortcutAction::ExecuteCommandline:
{
_ExecuteCommandlineHandlers(*this, *eventArgs);
}
case ShortcutAction::SetTabColor:
{
_SetTabColorHandlers(*this, *eventArgs);

View File

@@ -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);

View File

@@ -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;

View File

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

View File

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

View File

@@ -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

View File

@@ -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

View File

@@ -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",

View File

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

View File

@@ -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);
}

View File

@@ -66,6 +66,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
std::array<char, 4096> _buffer;
DWORD _OutputThread();
public:
void _DoOutputThreadWork(std::wstring& str);
};
}

View File

@@ -17,7 +17,6 @@
using namespace ::Microsoft::Console::Types;
using namespace ::Microsoft::Terminal::Core;
using namespace winrt::Windows::Graphics::Display;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Input;
using namespace winrt::Windows::UI::Xaml::Automation::Peers;
@@ -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:

View File

@@ -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 ---------------------------------

View File

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

View File

@@ -29,7 +29,7 @@ ThrottledFunc<>::ThrottledFunc(ThrottledFunc::Func func, TimeSpan delay, CoreDis
// - <none>
void ThrottledFunc<>::Run()
{
if (_isRunPending.test_and_set())
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();
}
});

View File

@@ -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.

View File

@@ -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.

View File

@@ -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);
}
}
}

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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));

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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:

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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,

View File

@@ -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,

View File

@@ -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;