Compare commits

..

81 Commits

Author SHA1 Message Date
Dustin L. Howett
6e1ce8de26 Migrate spelling-0.0.21 changes from main 2020-06-26 14:39:45 -05:00
Dustin L. Howett
5e13c37217 Migrate spelling-0.0.19 changes from main 2020-06-26 14:39:45 -05:00
Mike Griese
6328b1adda Merge branch 'dev/migrie/f/2046-Command-Palette-with-autogen-action-names' into dev/migrie/f/execute-commandlines
# Conflicts:
#	src/cascadia/TerminalApp/ActionAndArgs.cpp
#	src/cascadia/TerminalApp/ActionArgs.cpp
#	src/cascadia/TerminalApp/ActionArgs.h
#	src/cascadia/TerminalApp/ActionArgs.idl
#	src/cascadia/TerminalApp/CommandPalette.cpp
#	src/cascadia/TerminalApp/ShortcutActionDispatch.cpp
#	src/cascadia/TerminalApp/ShortcutActionDispatch.h
#	src/cascadia/TerminalApp/ShortcutActionDispatch.idl
#	src/cascadia/TerminalApp/TerminalPage.cpp
#	src/cascadia/TerminalControl/TermControl.idl
2020-06-26 14:39:45 -05:00
Mike Griese
177cf1caae use a border instead of a grid 2020-06-26 08:37:22 -05:00
Mike Griese
75473c50fb Use the visibility changed event, not the ToggleVisibility function.
Also misc spellchecks, nits.
2020-06-26 07:51:48 -05:00
Mike Griese
76cb9654e1 hey, why not use keybindings directly from the command palette? 2020-06-25 12:33:05 -05:00
Mike Griese
e967801cdf actually, just do all of #6645 2020-06-25 11:54:51 -05:00
Mike Griese
50cfd84dd2 add a little message when no matches are found 2020-06-25 11:34:02 -05:00
Mike Griese
33860f7c1a good bot 2020-06-25 11:17:28 -05:00
Mike Griese
860a3c7b23 add support for clicking on individual items in the command palette 2020-06-25 11:16:29 -05:00
Mike Griese
eae88a9fdb light dismiss on click, better sizing 2020-06-25 10:33:48 -05:00
Mike Griese
137aea367a unordered_maps, mad genius sorting, and a good idea about ESC 2020-06-25 09:37:46 -05:00
Mike Griese
8a93b1dd5d Merge remote-tracking branch 'origin/master' into dev/migrie/f/2046-Command-Palette-with-autogen-action-names
# Conflicts:
#	src/cascadia/TerminalApp/ActionAndArgs.cpp
#	src/cascadia/TerminalApp/ActionArgs.cpp
#	src/cascadia/TerminalApp/AppActionHandlers.cpp
#	src/cascadia/TerminalApp/ShortcutActionDispatch.cpp
#	src/cascadia/TerminalApp/ShortcutActionDispatch.h
#	src/cascadia/TerminalApp/ShortcutActionDispatch.idl
#	src/cascadia/TerminalApp/TerminalPage.cpp
#	src/cascadia/TerminalApp/TerminalPage.h
2020-06-25 09:13:51 -05:00
Mike Griese
6ca7d0e054 use iterators, because this isn't 1999 2020-06-24 16:59:35 -05:00
Mike Griese
6f1dc5c9fa Make command fuzzy-searching heaps better
Weight consecutive matched chars heigher.
  Sort results with the same weight.
  Co-authored by: @greg904
2020-06-24 16:40:22 -05:00
Mike Griese
b5be04c3ae only the simplest remaining feedback 2020-06-24 14:33:24 -05:00
Mike Griese
48d4e248b7 misc fixes from PR 2020-06-23 16:54:42 -05:00
Mike Griese
264618ae88 a ton of code cleanup from review 2020-06-23 13:01:27 -05:00
Mike Griese
f892e52077 align visuals with the SearchBoxControl 2020-06-23 11:50:40 -05:00
Mike Griese
b90cc38f0f Merge remote-tracking branch 'origin/master' into dev/migrie/f/2046-Command-Palette-with-autogen-action-names 2020-06-22 11:03:32 -05:00
Mike Griese
92b3453119 clean up these tests 2020-06-22 11:03:14 -05:00
Mike Griese
e25da60775 fix the last case of CommandTests::LayerCommand 2020-06-22 10:49:12 -05:00
Mike Griese
cee5fc9226 This is a ton of new tests 2020-06-22 10:31:12 -05:00
Mike Griese
10e91a823d strings for every possible action, and args value 2020-06-19 16:55:41 -05:00
Mike Griese
d1a72613c7 Use resources for the majority of command names 2020-06-19 15:46:13 -05:00
Mike Griese
3e5eb73597 proof of concept - have the names auto-generated from actions 2020-06-19 14:17:23 -05:00
Mike Griese
cc2fd9b490 fix this build 2020-06-19 11:22:14 -05:00
Mike Griese
45243bbee6 Merge remote-tracking branch 'origin/master' into dev/migrie/f/2046-Command-Palette-v2
# Conflicts:
#	src/cascadia/TerminalApp/ActionAndArgs.cpp
2020-06-19 11:09:25 -05:00
Mike Griese
52eb2e5faa Merge commit '827cc42' into dev/migrie/f/2046-Command-Palette-v2
# Conflicts:
#	doc/specs/#2046 - Command Palette.md
2020-06-19 11:07:48 -05:00
Mike Griese
8b094fdfde Merge commit 'db518c0' into dev/migrie/f/2046-Command-Palette-v2 2020-06-19 10:59:07 -05:00
Mike Griese
7a94b8f725 stash these tests in progress 2020-06-11 16:29:06 -05:00
Mike Griese
e2f5f75471 start adding tests 2020-06-11 12:40:57 -05:00
Mike Griese
7ac7fd1de9 Merge remote-tracking branch 'origin/master' into dev/migrie/f/2046-Command-Palette-v2 2020-06-11 12:15:27 -05:00
Mike Griese
dd684cbca1 implement a weighted ordering for command palette entries 2020-06-10 09:59:55 -05:00
Mike Griese
edc8b557e1 Add much better key chord text to the command palette 2020-06-10 08:53:34 -05:00
Mike Griese
82f968d8d5 If a key is bound to that action, then display the keybinding in the palette 2020-06-09 16:58:51 -05:00
Mike Griese
67c7969879 I couldn't tell you how long this took 2020-06-09 16:30:55 -05:00
Mike Griese
b3d8f0e279 Merge remote-tracking branch 'origin/master' into dev/migrie/f/2046-Command-Palette-v2 2020-06-09 12:33:36 -05:00
Mike Griese
10ace041c3 Trim leading whitespace form the commandline 2020-06-05 15:37:31 -05:00
Mike Griese
4d23121a7e A bunch of cleanup for review 2020-06-05 15:30:32 -05:00
Mike Griese
414007fdd8 This works but it's dirty 2020-06-05 15:05:14 -05:00
Mike Griese
72c0601d00 split-pane ; split-pane at runtime doesn't work, pt2
This does work to split multiple panes at runtime. It definitely crashes
  when the panes get too small, we might be able to adapt Pane::CanSplit to
  be smart about when it's children don't quite have a size yet.
2020-06-05 09:30:57 -05:00
Mike Griese
b3225db167 split-pane ; split-pane at runtime doesn't work, pt1
I thought maybe breaking up the dispatcher calls would just magic fix this for me. It doesn't.
2020-06-05 09:29:04 -05:00
Mike Griese
2517183b63 Add incredible support for commandline mode
easy_button.jpg
2020-06-05 09:27:57 -05:00
Mike Griese
9fbcbcc9d8 Cleanup for review 2020-06-05 08:39:03 -05:00
Mike Griese
73aefc18e8 do it with multiple args 2020-06-05 08:01:39 -05:00
Mike Griese
a02585da35 Whoop, this works for parsing a single command! This code's horribly dirty, but _it works_ 2020-06-04 17:00:24 -05:00
Mike Griese
2cf69338cd Add an ExecuteCommandline ShortcutAction, don't implement quite yet 2020-06-04 14:54:03 -05:00
Mike Griese
d71d8d7b32 Ready for review. 2020-06-04 12:29:22 -05:00
Mike Griese
9d411d405c Make the commands a map, so we can override on "name" 2020-06-04 11:48:38 -05:00
Mike Griese
58be8cd117 Tons of commenting 2020-06-04 11:21:46 -05:00
Mike Griese
487f33ee89 Merge commit '6e6979abe' into dev/migrie/f/2046-Command-Palette-v2
# Conflicts:
#	src/cascadia/TerminalApp/ActionAndArgs.cpp
#	src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp
2020-06-04 10:15:40 -05:00
Mike Griese
829beda501 Merge remote-tracking branch 'origin/master' into dev/migrie/f/2046-Command-Palette-v2
# Conflicts:
#	src/cascadia/TerminalApp/GlobalAppSettings.cpp
#	src/cascadia/TerminalApp/GlobalAppSettings.h
2020-06-04 10:02:40 -05:00
Mike Griese
6e6979abe8 Extract ActionAndArgs::FromJson into it's own class, so it can be re-used later 2020-06-04 09:28:21 -05:00
Mike Griese
1fbe8e415d Turns out, the shadow on the menuflyout isn't my fault, it's on everything that uses MUX 2020-05-29 12:45:39 -05:00
Mike Griese
fa93fdc034 Well, this is neat, and works, but requires 18362 and also casts a shadow on the menuflyout??? 2020-05-29 12:19:04 -05:00
Mike Griese
cf6e1f273a Try to do this with a shadow, but it crashes inexplicably 2020-05-29 11:44:38 -05:00
Mike Griese
99059451d8 Return focus to the active control when closed 2020-05-29 11:29:01 -05:00
Mike Griese
a309191461 Rename private methods, fix wraparound logic 2020-05-29 11:14:56 -05:00
Mike Griese
e1be26b184 Do this in WinRTUtils instead of hackily doing it manually 2020-05-29 09:48:30 -05:00
Mike Griese
bc546dbdb0 Add some stability
Don't die when we encounter an unexpected key
  Reload successfully
2020-05-29 09:42:47 -05:00
Mike Griese
00763fda9e Add duplicate pane to the default commands 2020-05-29 07:47:29 -05:00
Mike Griese
b88be4534b Make sure to scroll the selected item into view 2020-05-29 07:43:12 -05:00
Mike Griese
207666e34d Add a ton of default commands 2020-05-29 07:32:43 -05:00
Mike Griese
62b9a0d1c0 Move the action into it's own sub-object 2020-05-28 16:44:38 -05:00
Mike Griese
02f47f49c3 Make the action names map public, so the ToJson in AKBSerialization can use it 2020-05-28 16:40:04 -05:00
Mike Griese
6905065fcf Merge remote-tracking branch 'origin/master' into dev/migrie/f/2046-Command-Palette-v2
# Conflicts:
#	src/cascadia/TerminalApp/TerminalPage.h
2020-05-28 15:29:23 -05:00
Mike Griese
0416a944a2 Hook up the parsing of ActionAndArgss to the command palette 2020-05-28 15:09:45 -05:00
Mike Griese
3627d8abd5 This should have been in the previous commit 2020-05-28 15:08:57 -05:00
Mike Griese
33a9e32736 Get names from the resources if provided as an object, not a string 2020-05-28 12:56:17 -05:00
Mike Griese
75af4cabbb Hook up all the parsing once again 2020-05-28 12:31:49 -05:00
Mike Griese
43bd483962 Blind port these files from the old branch 2020-05-28 11:26:25 -05:00
Mike Griese
0672812e6f good bot 2020-05-28 10:29:09 -05:00
Mike Griese
f53553f4e4 Merge remote-tracking branch 'origin/master' into dev/migrie/s/5400-CommandPalette-v1 2020-05-28 10:27:58 -05:00
Mike Griese
11130a4895 Add some notes about the advanced tab switcher and how that might interplay with this 2020-05-20 09:15:27 -05:00
Mike Griese
0886e8f12d Merge remote-tracking branch 'origin/master' into dev/migrie/s/5400-CommandPalette-v1 2020-05-20 08:47:50 -05:00
Mike Griese
2e564368c8 Move this section to 'future considerations' 2020-05-07 12:17:00 -05:00
Mike Griese
ead76d7f16 Merge remote-tracking branch 'origin/master' into dev/migrie/s/5400-CommandPalette-v1 2020-05-07 12:11:48 -05:00
Mike Griese
614d1b21d6 last little todos for review 2020-04-30 15:20:25 -05:00
Mike Griese
fe640ff894 move this spec out of drafts/ 2020-04-30 15:03:52 -05:00
Mike Griese
c56eb8fd93 Add a ton of text regarding Commandline Mode vs Action Mode 2020-04-30 15:02:59 -05:00
60 changed files with 718 additions and 654 deletions

View File

@@ -108,12 +108,7 @@ TextAttribute ATTR_ROW::GetAttrByColumn(const size_t column,
{
THROW_HR_IF(E_INVALIDARG, column >= _cchRowWidth);
const auto runPos = FindAttrIndex(column, pApplies);
return GetAttrByIndex(runPos);
}
TextAttribute ATTR_ROW::GetAttrByIndex(const size_t index) const
{
return _list.at(index).GetAttributes();
return _list.at(runPos).GetAttributes();
}
// Routine Description:
@@ -255,11 +250,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[0].GetAttributes();
const TextAttribute NewAttr = newAttrs.at(0).GetAttributes();
// If the existing run was only 1 element...
// ...and the new color is the same as the old, we don't have to do anything and can exit quick.
if (_list.size() == 1 && _list[0].GetAttributes() == NewAttr)
if (_list.size() == 1 && _list.at(0).GetAttributes() == NewAttr)
{
return S_OK;
}

View File

@@ -36,8 +36,6 @@ 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,9 +233,7 @@ 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 };
}
@@ -248,9 +246,7 @@ 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[_index];
return _parent._data.at(_index);
}
// Routine Description:
@@ -50,7 +50,7 @@ CharRowCell& CharRowCellReference::_cellData()
// - ref to the CharRowCell
const CharRowCell& CharRowCellReference::_cellData() const
{
return _parent._data[_index];
return _parent._data.at(_index);
}
// Routine Description:

View File

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

View File

@@ -33,16 +33,13 @@ TextBuffer::TextBuffer(const COORD screenBufferSize,
_cursor{ cursorSize, *this },
_storage{},
_unicodeStorage{},
_renderTarget{ renderTarget },
_size{}
_renderTarget{ renderTarget }
{
// 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:
@@ -81,7 +78,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[offsetIndex];
return _storage.at(offsetIndex);
}
// Routine Description:
@@ -97,7 +94,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[offsetIndex];
return _storage.at(offsetIndex);
}
// Routine Description:
@@ -655,15 +652,9 @@ const SHORT TextBuffer::GetFirstRowIndex() const noexcept
{
return _firstRow;
}
const Viewport TextBuffer::GetSize() const noexcept
const Viewport TextBuffer::GetSize() const
{
return _size;
}
void TextBuffer::_UpdateSize()
{
_size = Viewport::FromDimensions({ 0, 0 }, { gsl::narrow<SHORT>(_storage.at(0).size()), gsl::narrow<SHORT>(_storage.size()) });
return Viewport::FromDimensions({ 0, 0 }, { gsl::narrow<SHORT>(_storage.at(0).size()), gsl::narrow<SHORT>(_storage.size()) });
}
void TextBuffer::_SetFirstRowIndex(const SHORT FirstRowIndex) noexcept
@@ -854,9 +845,6 @@ 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 noexcept;
const Microsoft::Console::Types::Viewport GetSize() const;
void ScrollRows(const SHORT firstRow, const SHORT size, const SHORT delta);
@@ -177,8 +177,6 @@ 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::unordered_map<winrt::hstring, Command> commands;
std::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::unordered_map<winrt::hstring, Command> commands;
std::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::unordered_map<winrt::hstring, Command> commands;
std::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::unordered_map<winrt::hstring, Command> commands;
std::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::unordered_map<winrt::hstring, Command> commands;
std::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::unordered_map<winrt::hstring, Command> commands;
std::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,6 +29,7 @@ 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" };
@@ -79,6 +80,7 @@ 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>>;
@@ -104,6 +106,8 @@ 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 },
@@ -252,6 +256,7 @@ 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,6 +14,7 @@
#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"
@@ -228,6 +229,14 @@ 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,6 +14,7 @@
#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"
@@ -403,6 +404,37 @@ 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,6 +101,11 @@ namespace TerminalApp
SplitType SplitMode { get; };
};
[default_interface] runtimeclass ExecuteCommandlineArgs : IActionArgs
{
String Commandline;
}
[default_interface] runtimeclass OpenSettingsArgs : IActionArgs
{
SettingsTarget Target { get; };

View File

@@ -312,4 +312,40 @@ 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,3 +637,52 @@ 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,7 +28,9 @@ 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::Point AppLogic::GetLaunchDimensions(uint32_t dpi)
winrt::Windows::Foundation::Size 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.Y += (titlebar.DesiredSize().Height) * scale;
proposedSize.Height += (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.Y += (tabControl.DesiredSize().Height + 6) * scale;
proposedSize.Width += (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 = _ParseArgs(args);
const auto result = _appArgs.ParseArgs(args);
if (result == 0)
{
_appArgs.ValidateStartupCommands();
@@ -982,53 +982,6 @@ 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::Point GetLaunchDimensions(uint32_t dpi);
Windows::Foundation::Size 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.Point GetLaunchDimensions(UInt32 dpi);
Windows.Foundation.Size GetLaunchDimensions(UInt32 dpi);
Windows.Foundation.Point GetLaunchInitialPositions(Int32 defaultInitialX, Int32 defaultInitialY);
Windows.UI.Xaml.ElementTheme GetRequestedTheme();
LaunchMode GetLaunchMode();

View File

@@ -3,6 +3,8 @@
#include "pch.h"
#include "CommandPalette.h"
#include "ActionArgs.h"
#include "ActionAndArgs.h"
#include "CommandPalette.g.cpp"
#include <winrt/Microsoft.Terminal.Settings.h>
@@ -97,17 +99,18 @@ namespace winrt::TerminalApp::implementation
}
else if (key == VirtualKey::Enter)
{
// Action Mode: Dispatch the action of the selected command.
if (const auto selectedItem = _filteredActionsView().SelectedItem())
if (_mode == PaletteMode::ActionMode)
{
if (const auto data = selectedItem.try_as<Command>())
// Action Mode: Dispatch the action of the selected command.
if (const auto selectedItem = _filteredActionsView().SelectedItem())
{
const auto actionAndArgs = data.Action();
_dispatch.DoAction(actionAndArgs);
_close();
_dispatchAction();
}
}
else
{
_dispatchCommandline();
}
e.Handled(true);
}
@@ -184,6 +187,7 @@ namespace winrt::TerminalApp::implementation
void CommandPalette::_filterTextChanged(IInspectable const& /*sender*/,
Windows::UI::Xaml::RoutedEventArgs const& /*args*/)
{
_checkMode();
_updateFilteredActions();
_filteredActionsView().SelectedIndex(0);
@@ -237,6 +241,12 @@ namespace winrt::TerminalApp::implementation
void CommandPalette::_updateFilteredActions()
{
_filteredActions.Clear();
if (_mode == PaletteMode::CommandlineMode)
{
return;
}
auto searchText = _searchBox().Text();
const bool addAll = searchText.empty();
@@ -411,4 +421,60 @@ 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,6 +8,12 @@
namespace winrt::TerminalApp::implementation
{
enum class PaletteMode : uint32_t
{
ActionMode = 0,
CommandlineMode
};
struct CommandPalette : CommandPaletteT<CommandPalette>
{
CommandPalette();
@@ -24,6 +30,8 @@ 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,
@@ -36,9 +44,14 @@ 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,6 +7,7 @@
#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;
@@ -921,6 +922,102 @@ 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,7 +64,9 @@ 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,6 +480,10 @@
<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,6 +164,10 @@ namespace winrt::TerminalApp::implementation
_ToggleCommandPaletteHandlers(*this, *eventArgs);
break;
}
case ShortcutAction::ExecuteCommandline:
{
_ExecuteCommandlineHandlers(*this, *eventArgs);
}
case ShortcutAction::SetTabColor:
{
_SetTabColorHandlers(*this, *eventArgs);

View File

@@ -48,6 +48,7 @@ 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,6 +35,7 @@ namespace TerminalApp
SetTabColor,
OpenTabColorPicker,
OpenSettings,
ExecuteCommandline,
RenameTab,
ToggleCommandPalette
};
@@ -75,6 +76,7 @@ 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,6 +875,10 @@ 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,6 +40,7 @@ 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();
_ProcessStartupActions(true);
}
}
}
@@ -239,10 +239,11 @@ namespace winrt::TerminalApp::implementation
// - Process all the startup actions in our list of startup actions. We'll
// do this all at once here.
// Arguments:
// - <none>
// - initial: if true, we're parsing these args during startup, and we
// should fire an Initialized event.
// Return Value:
// - <none>
winrt::fire_and_forget TerminalPage::_ProcessStartupActions()
winrt::fire_and_forget TerminalPage::_ProcessStartupActions(const bool initial)
{
// If there are no actions left, do nothing.
if (_startupActions.empty())
@@ -252,15 +253,24 @@ namespace winrt::TerminalApp::implementation
auto weakThis{ get_weak() };
// Handle it on a subsequent pass of the UI thread.
co_await winrt::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal);
if (auto page{ weakThis.get() })
for (const auto& action : _startupActions)
{
for (const auto& action : _startupActions)
co_await winrt::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal);
if (auto page{ weakThis.get() })
{
_actionDispatch->DoAction(action);
}
_CompleteInitialization();
else
{
return;
}
}
if (auto page{ weakThis.get() })
{
if (initial)
{
_CompleteInitialization();
}
}
}
@@ -595,16 +605,6 @@ 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,6 +804,7 @@ 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 });
@@ -1314,19 +1315,20 @@ namespace winrt::TerminalApp::implementation
const auto controlConnection = _CreateConnectionFromSettings(realGuid, controlSettings);
const auto canSplit = focusedTab->CanSplitPane(splitType);
if (!canSplit && _startupState == StartupState::Initialized)
{
return;
}
float contentWidth = gsl::narrow_cast<float>(_tabContent.ActualWidth());
float contentHeight = gsl::narrow_cast<float>(_tabContent.ActualHeight());
winrt::Windows::Foundation::Size availableSpace{ contentWidth, contentHeight };
auto realSplitType = splitType;
if (realSplitType == SplitState::Automatic && _startupState < StartupState::Initialized)
if (realSplitType == SplitState::Automatic)
{
float contentWidth = gsl::narrow_cast<float>(_tabContent.ActualWidth());
float contentHeight = gsl::narrow_cast<float>(_tabContent.ActualHeight());
realSplitType = focusedTab->PreCalculateAutoSplit({ contentWidth, contentHeight });
realSplitType = focusedTab->PreCalculateAutoSplit(availableSpace);
}
const auto canSplit = focusedTab->PreCalculateCanSplit(realSplitType, availableSpace);
if (!canSplit)
{
return;
}
TermControl newControl{ controlSettings, controlConnection };

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();
winrt::fire_and_forget _ProcessStartupActions(const bool initial);
void _ShowAboutDialog();
void _ShowCloseWarningDialog();
@@ -204,6 +204,7 @@ 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": "%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
"commandline": "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": "%SystemRoot%\\System32\\cmd.exe",
"commandline": "cmd.exe",
"icon": "ms-appx:///ProfileIcons/{0caa0dad-35be-5f56-a8ff-afceeeaa6101}.png",
"colorScheme": "Campbell",
"antialiasingMode": "grayscale",

View File

@@ -29,6 +29,7 @@
#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,40 +383,6 @@ 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
@@ -479,15 +445,6 @@ 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,9 +66,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
std::array<char, 4096> _buffer;
DWORD _OutputThread();
public:
void _DoOutputThreadWork(std::wstring& str);
};
}

View File

@@ -17,6 +17,7 @@
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;
@@ -621,7 +622,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);
THROW_IF_FAILED(dxEngine->SetWindowSize({ viewInPixels.Width(), viewInPixels.Height() }));
LOG_IF_FAILED(dxEngine->SetWindowSize({ viewInPixels.Width(), viewInPixels.Height() }));
// Update DxEngine's SelectionBackground
dxEngine->SetSelectionBackground(_settings.SelectionBackground());
@@ -2242,28 +2243,68 @@ 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 point containing the requested dimensions in pixels.
winrt::Windows::Foundation::Point TermControl::GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi)
// - a size containing the requested dimensions in pixels.
winrt::Windows::Foundation::Size TermControl::GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi)
{
// If the settings have negative or zero row or column counts, ignore those counts.
// (The lower TerminalCore layer also has upper bounds as well, but at this layer
// we may eventually impose different ones depending on how many pixels we can address.)
const auto cols = ::base::saturated_cast<float>(std::max(settings.InitialCols(), 1));
const auto rows = ::base::saturated_cast<float>(std::max(settings.InitialRows(), 1));
const winrt::Windows::Foundation::Size initialSize{ cols, rows };
return GetProposedDimensions(initialSize,
settings.FontSize(),
settings.FontWeight(),
settings.FontFace(),
settings.ScrollState(),
settings.Padding(),
dpi);
}
// Function Description:
// - Determines how much space (in pixels) an app would need to reserve to
// create a control with the settings stored in the settings param. This
// accounts for things like the font size and face, the initialRows and
// initialCols, and scrollbar visibility. The returned sized is based upon
// the provided DPI value
// Arguments:
// - initialSizeInChars: The size to get the proposed dimensions for.
// - fontHeight: The font height to use to calculate the proposed size for.
// - fontWeight: The font weight to use to calculate the proposed size for.
// - fontFace: The font name to use to calculate the proposed size for.
// - scrollState: The ScrollbarState to use to calculate the proposed size for.
// - padding: The padding to use to calculate the proposed size for.
// - dpi: The DPI we should create the terminal at. This affects things such
// as font size, scrollbar and other control scaling, etc. Make sure the
// caller knows what monitor the control is about to appear on.
// Return Value:
// - a size containing the requested dimensions in pixels.
winrt::Windows::Foundation::Size TermControl::GetProposedDimensions(const winrt::Windows::Foundation::Size& initialSizeInChars,
const int32_t& fontHeight,
const winrt::Windows::UI::Text::FontWeight& fontWeight,
const winrt::hstring& fontFace,
const Microsoft::Terminal::Settings::ScrollbarState& scrollState,
const winrt::hstring& padding,
const uint32_t dpi)
{
const auto cols = ::base::saturated_cast<int>(initialSizeInChars.Width);
const auto rows = ::base::saturated_cast<int>(initialSizeInChars.Height);
// Initialize our font information.
const auto fontFace = settings.FontFace();
const short fontHeight = gsl::narrow_cast<short>(settings.FontSize());
const auto fontWeight = settings.FontWeight();
// const auto fontFace = settings.FontFace();
// const short fontHeight = gsl::narrow_cast<short>(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, fontHeight }, CP_UTF8, false };
FontInfo actualFont = { fontFace, 0, fontWeight.Weight, { 0, gsl::narrow_cast<short>(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.
@@ -2283,13 +2324,13 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
double width = cols * fontSize.X;
// Reserve additional space if scrollbar is intended to be visible
if (settings.ScrollState() == ScrollbarState::Visible)
if (scrollState == ScrollbarState::Visible)
{
width += scrollbarSize;
}
double height = rows * fontSize.Y;
auto thickness = _ParseThicknessFromPadding(settings.Padding());
auto thickness = _ParseThicknessFromPadding(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);
@@ -2322,21 +2363,41 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
// have a visible character.
winrt::Windows::Foundation::Size TermControl::MinimumSize()
{
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)
if (_initializedTerminal)
{
width += ScrollBar().ActualWidth();
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);
}
// 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,7 +98,14 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
TerminalConnection::ConnectionState ConnectionState() const;
static Windows::Foundation::Point GetProposedDimensions(Microsoft::Terminal::Settings::IControlSettings const& settings, const uint32_t dpi);
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);
// 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.Point GetProposedDimensions(Microsoft.Terminal.Settings.IControlSettings settings, UInt32 dpi);
static Windows.Foundation.Size GetProposedDimensions(Microsoft.Terminal.Settings.IControlSettings settings, UInt32 dpi);
void UpdateSettings(Microsoft.Terminal.Settings.IControlSettings newSettings);

View File

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

View File

@@ -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.X)), 1);
static_cast<long>(ceil(initialSize.Width)), 1);
const short islandHeight = Utils::ClampToShortMax(
static_cast<long>(ceil(initialSize.Y)), 1);
static_cast<long>(ceil(initialSize.Height)), 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 WriteConsoleAImplForReals(IConsoleOutputObject& context,
const std::string_view buffer,
size_t& read,
std::unique_ptr<IWaitRoutine>& waiter) noexcept
[[nodiscard]] HRESULT ApiRoutines::WriteConsoleAImpl(IConsoleOutputObject& context,
const std::string_view buffer,
size_t& read,
std::unique_ptr<IWaitRoutine>& waiter) noexcept
{
try
{
@@ -1238,62 +1238,6 @@ 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 },
_text{},
_clusterMap{},
_viewport{Viewport::Empty()}
_clusterBuffer{}
{
_srViewportPrevious = { 0 };
for (size_t i = 0; i < cEngines; i++)
{
IRenderEngine* engine = rgpEngines[i];
@@ -208,16 +208,15 @@ void Renderer::TriggerSystemRedraw(const RECT* const prcDirtyClient)
// - <none>
void Renderer::TriggerRedraw(const Viewport& region)
{
Viewport view = _viewport;
Viewport view = _pData->GetViewport();
SMALL_RECT srUpdateRegion = region.ToExclusive();
if (view.TrimToViewport(&srUpdateRegion))
{
view.ConvertToOrigin(&srUpdateRegion);
for (auto pEngine : _rgpEngines)
{
std::for_each(_rgpEngines.begin(), _rgpEngines.end(), [&](IRenderEngine* const pEngine) {
LOG_IF_FAILED(pEngine->Invalidate(&srUpdateRegion));
}
});
_NotifyPaintFrame();
}
@@ -358,7 +357,7 @@ void Renderer::TriggerSelection()
// - True if something changed and we scrolled. False otherwise.
bool Renderer::_CheckViewportAndScroll()
{
SMALL_RECT const srOldViewport = _viewport.ToInclusive();
SMALL_RECT const srOldViewport = _srViewportPrevious;
SMALL_RECT const srNewViewport = _pData->GetViewport().ToInclusive();
COORD coordDelta;
@@ -370,13 +369,13 @@ bool Renderer::_CheckViewportAndScroll()
LOG_IF_FAILED(engine->UpdateViewport(srNewViewport));
}
_viewport = Viewport::FromInclusive(srNewViewport);
_srViewportPrevious = 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(_clusterMap, lineLength, _shrinkThreshold);
til::manage_vector(_clusterBuffer, lineLength, _shrinkThreshold);
if (coordDelta.X != 0 || coordDelta.Y != 0)
{
@@ -655,8 +654,7 @@ 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& r = buffer.GetRowByOffset(bufferLine.Origin().Y);
//auto it = buffer.GetCellDataAt(bufferLine.Origin(), bufferLine);
auto it = buffer.GetCellDataAt(bufferLine.Origin(), bufferLine);
// Calculate if two things are true:
// 1. this row wrapped
@@ -666,30 +664,27 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine)
(bufferLine.RightExclusive() == buffer.GetSize().Width());
// Ask the helper to paint through this specific line.
_PaintBufferOutputHelper(pEngine, r, bufferLine.RightExclusive(), screenLine.Origin(), lineWrapped);
_PaintBufferOutputHelper(pEngine, it, 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,
const ROW& r,
const SHORT limitRight,
TextBufferCellIterator it,
const COORD target,
const bool lineWrapped)
{
/*auto globalInvert{ _pData->IsScreenReversed() };*/
SHORT pos = target.X;
auto globalInvert{ _pData->IsScreenReversed() };
// If we have valid data, let's figure out how to draw it.
if (pos < limitRight)
if (it)
{
// 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.
@@ -698,18 +693,13 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
size_t cols = 0;
// Retrieve the first color.
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);
auto color = it->TextAttr();
// 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 (pos < limitRight)
while (it)
{
// 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
@@ -726,12 +716,11 @@ 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 = pos;
const auto currentRunItStart = it;
const auto currentRunTargetStart = screenPoint;
// Ensure that our cluster vector is clear.
_text.clear();
_clusterMap.clear();
_clusterBuffer.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
@@ -745,32 +734,25 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
// When the color changes, it will save the new color off and break.
do
{
if (colorApplies <= 0)
if (color != it->TextAttr())
{
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
//}
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 (_text.empty() && dbcsAttr.IsTrailing())
if (_clusterBuffer.empty() && it->DbcsAttr().IsTrailing())
{
// If we have room to move to the left to start drawing...
if (screenPoint.X > 0)
@@ -780,12 +762,8 @@ 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 = 2;
//columnCount = it->Columns() + 1;
_text.append(chars);
_clusterMap.push_back(2);
_clusterMap.push_back(0);
//_clusterBuffer.emplace_back(chars, columnCount);
columnCount = it->Columns() + 1;
_clusterBuffer.emplace_back(it->Chars(), columnCount);
}
else
{
@@ -797,14 +775,8 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
// Otherwise if it's not a special case, just insert it as is.
else
{
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);
columnCount = it->Columns();
_clusterBuffer.emplace_back(it->Chars(), columnCount);
}
if (columnCount > 1)
@@ -813,15 +785,13 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
}
// Advance the cluster and column counts.
const auto delta = (SHORT)(columnCount > 0 ? columnCount : 1); // prevent infinite loop for no visible columns
pos += delta;
colorApplies -= delta;
it += columnCount > 0 ? columnCount : 1; // prevent infinite loop for no visible columns
cols += columnCount;
} while (pos < limitRight);
} while (it);
// Do the painting.
THROW_IF_FAILED(pEngine->PaintBufferLine(_text, { _clusterMap.data(), _clusterMap.size() }, screenPoint, trimLeft, lineWrapped));
THROW_IF_FAILED(pEngine->PaintBufferLine({ _clusterBuffer.data(), _clusterBuffer.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.
@@ -846,7 +816,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 = attrRow.GetAttrByColumn(lineIt);
auto lines = lineIt->TextAttr();
_PaintBufferOutputGridLineHelper(pEngine, lines, 1, lineTarget);
}
}
@@ -1043,7 +1013,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,16 +99,10 @@ namespace Microsoft::Console::Render
void _PaintBufferOutput(_In_ IRenderEngine* const pEngine);
void _PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
const ROW& r,
const SHORT limitRight,
TextBufferCellIterator it,
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,
@@ -126,12 +120,10 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT _PerformScrolling(_In_ IRenderEngine* const pEngine);
Microsoft::Console::Types::Viewport _viewport;
SMALL_RECT _srViewportPrevious;
static constexpr float _shrinkThreshold = 0.8f;
std::wstring _text;
std::vector<UINT16> _clusterMap;
//std::vector<Cluster> _clusterBuffer;
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, std::memory_order_acq_rel))
if (!_fNextFrameRequested.exchange(false))
{
// <--
// 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, std::memory_order_release);
_fWaiting.store(true);
// check again now (see comment above)
if (!_fNextFrameRequested.exchange(false, std::memory_order_acq_rel))
if (!_fNextFrameRequested.exchange(false))
{
// 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, std::memory_order_release);
_fWaiting.store(false);
// see comment above
ResetEvent(_hEvent);
@@ -218,13 +218,13 @@ DWORD WINAPI RenderThread::_ThreadProc()
void RenderThread::NotifyPaint()
{
if (_fWaiting.load(std::memory_order_acquire))
if (_fWaiting.load())
{
SetEvent(_hEvent);
}
else
{
_fNextFrameRequested.store(true, std::memory_order_release);
_fNextFrameRequested.store(true);
}
}

View File

@@ -70,27 +70,25 @@ 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(std::wstring_view text,
std::basic_string_view<UINT16> clusterMap)
[[nodiscard]] HRESULT STDMETHODCALLTYPE CustomTextLayout::AppendClusters(const std::basic_string_view<::Microsoft::Console::Render::Cluster> clusters)
try
{
_text.append(text);
_textClusterColumns.insert(_textClusterColumns.end(), clusterMap.cbegin(), clusterMap.cend());
_textClusterColumns.reserve(_textClusterColumns.size() + clusters.size());
//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,8 +27,7 @@ namespace Microsoft::Console::Render
size_t const width,
IBoxDrawingEffect* const boxEffect);
[[nodiscard]] HRESULT STDMETHODCALLTYPE AppendClusters(std::wstring_view text,
std::basic_string_view<UINT16> clusterMap);
[[nodiscard]] HRESULT STDMETHODCALLTYPE AppendClusters(const std::basic_string_view<::Microsoft::Console::Render::Cluster> clusters);
[[nodiscard]] HRESULT STDMETHODCALLTYPE Reset() noexcept;

View File

@@ -68,7 +68,6 @@ DxEngine::DxEngine() :
_invalidateFullRows{ true },
_invalidMap{},
_invalidScroll{},
_allInvalid{ false },
_firstFrame{ true },
_presentParams{ 0 },
_presentReady{ false },
@@ -843,11 +842,6 @@ 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:
@@ -859,10 +853,7 @@ try
{
RETURN_HR_IF_NULL(E_INVALIDARG, psrRegion);
if (!_allInvalid)
{
_InvalidateRectangle(Viewport::FromExclusive(*psrRegion).ToInclusive());
}
_InvalidateRectangle(Viewport::FromExclusive(*psrRegion).ToInclusive());
return S_OK;
}
@@ -879,10 +870,7 @@ try
{
RETURN_HR_IF_NULL(E_INVALIDARG, pcoordCursor);
if (!_allInvalid)
{
/*_InvalidateRectangle(til::rectangle{ *pcoordCursor, til::size{ 1, 1 } });*/
}
_InvalidateRectangle(til::rectangle{ *pcoordCursor, til::size{ 1, 1 } });
return S_OK;
}
@@ -899,12 +887,9 @@ try
{
RETURN_HR_IF_NULL(E_INVALIDARG, prcDirtyClient);
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));
}
// 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;
}
@@ -918,12 +903,9 @@ CATCH_RETURN();
// - S_OK
[[nodiscard]] HRESULT DxEngine::InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept
{
if (!_allInvalid)
for (const auto& rect : rectangles)
{
for (const auto& rect : rectangles)
{
RETURN_IF_FAILED(Invalidate(&rect));
}
RETURN_IF_FAILED(Invalidate(&rect));
}
return S_OK;
}
@@ -943,15 +925,11 @@ try
const til::point deltaCells{ *pcoordDelta };
if (!_allInvalid)
if (deltaCells != til::point{ 0, 0 })
{
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();
}
// Shift the contents of the map and fill in revealed area.
_invalidMap.translate(deltaCells, true);
_invalidScroll += deltaCells;
}
return S_OK;
@@ -968,7 +946,6 @@ 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
@@ -1227,7 +1204,6 @@ try
}
_invalidMap.reset_all();
_allInvalid = false;
_invalidScroll = {};
@@ -1438,8 +1414,7 @@ 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::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] HRESULT DxEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
COORD const coord,
const bool /*trimLeft*/,
const bool /*lineWrapped*/) noexcept
@@ -1450,7 +1425,7 @@ try
// Create the text layout
RETURN_IF_FAILED(_customLayout->Reset());
RETURN_IF_FAILED(_customLayout->AppendClusters(text, clusterMap));
RETURN_IF_FAILED(_customLayout->AppendClusters(clusters));
// Layout then render the text
RETURN_IF_FAILED(_customLayout->Draw(_drawingContext.get(), _customRenderer.Get(), origin.x, origin.y));
@@ -1840,12 +1815,10 @@ try
{
RETURN_HR_IF_NULL(E_INVALIDARG, pResult);
//const Cluster cluster(glyph, 0); // columns don't matter, we're doing analysis not layout.
UINT16 col = 0;
const Cluster cluster(glyph, 0); // columns don't matter, we're doing analysis not layout.
RETURN_IF_FAILED(_customLayout->Reset());
RETURN_IF_FAILED(_customLayout->AppendClusters(glyph, { &col, 1 }));
RETURN_IF_FAILED(_customLayout->AppendClusters({ &cluster, 1 }));
UINT32 columns = 0;
RETURN_IF_FAILED(_customLayout->GetColumns(&columns));

View File

@@ -85,8 +85,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept override;
[[nodiscard]] HRESULT PaintBackground() noexcept override;
[[nodiscard]] HRESULT PaintBufferLine(std::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
COORD const coord,
bool const fTrimLeft,
const bool lineWrapped) noexcept override;
@@ -159,7 +158,6 @@ namespace Microsoft::Console::Render
bool _invalidateFullRows;
til::bitmap _invalidMap;
til::point _invalidScroll;
bool _allInvalid;
bool _presentReady;
std::vector<RECT> _presentDirty;
@@ -274,7 +272,6 @@ 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,8 +42,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT ScrollFrame() noexcept override;
[[nodiscard]] HRESULT PaintBackground() noexcept override;
[[nodiscard]] HRESULT PaintBufferLine(std::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
const COORD coord,
const bool trimLeft,
const bool lineWrapped) noexcept override;

View File

@@ -284,15 +284,14 @@ 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::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] HRESULT GdiEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
const COORD coord,
const bool trimLeft,
const bool /*lineWrapped*/) noexcept
{
try
{
const auto cchLine = text.size();
const auto cchLine = clusters.size();
// Exit early if there are no lines to draw.
RETURN_HR_IF(S_OK, 0 == cchLine);
@@ -317,13 +316,12 @@ 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] = text[i];
//cluster.GetTextAsSingle();
rgdxPoly[i] = gsl::narrow<int>(clusterMap[i]) * coordFontSize.X;
pwsPoly[i] = cluster.GetTextAsSingle();
rgdxPoly[i] = gsl::narrow<int>(cluster.GetColumns()) * coordFontSize.X;
cchCharWidths += rgdxPoly[i];
}
@@ -367,7 +365,7 @@ using namespace Microsoft::Console::Render;
}
pPolyTextLine->lpstr = pwsPoly.release();
pPolyTextLine->n = gsl::narrow<UINT>(text.size());
pPolyTextLine->n = gsl::narrow<UINT>(clusters.size());
pPolyTextLine->x = ptDraw.x;
pPolyTextLine->y = ptDraw.y;
pPolyTextLine->uiFlags = ETO_OPAQUE | ETO_CLIPPED;

View File

@@ -70,8 +70,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] virtual HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept = 0;
[[nodiscard]] virtual HRESULT PaintBackground() noexcept = 0;
[[nodiscard]] virtual HRESULT PaintBufferLine(std::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] virtual HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
const COORD coord,
const bool fTrimLeft,
const bool lineWrapped) noexcept = 0;

View File

@@ -305,8 +305,7 @@ 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::wstring_view /*text*/,
std::basic_string_view<UINT16> /*clusterMap*/,
[[nodiscard]] HRESULT UiaEngine::PaintBufferLine(std::basic_string_view<Cluster> const /*clusters*/,
COORD const /*coord*/,
const bool /*trimLeft*/,
const bool /*lineWrapped*/) noexcept

View File

@@ -51,8 +51,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT PaintBackground() noexcept override;
[[nodiscard]] HRESULT PaintBufferLine(std::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
COORD const coord,
bool const fTrimLeft,
const bool lineWrapped) noexcept override;

View File

@@ -529,15 +529,14 @@ CATCH_RETURN();
// will be false.
// Return Value:
// - S_OK or suitable HRESULT error from writing pipe.
[[nodiscard]] HRESULT XtermEngine::PaintBufferLine(std::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] HRESULT XtermEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
const COORD coord,
const bool /*trimLeft*/,
const bool lineWrapped) noexcept
{
return _fUseAsciiOnly ?
VtEngine::_PaintAsciiBufferLine(text, clusterMap, coord) :
VtEngine::_PaintUtf8BufferLine(text, clusterMap, coord, lineWrapped);
VtEngine::_PaintAsciiBufferLine(clusters, coord) :
VtEngine::_PaintUtf8BufferLine(clusters, coord, lineWrapped);
}
// Method Description:

View File

@@ -45,8 +45,7 @@ namespace Microsoft::Console::Render
const WORD legacyColorAttribute,
const ExtendedAttributes extendedAttrs,
const bool isSettingDefaultBrushes) noexcept override;
[[nodiscard]] HRESULT PaintBufferLine(std::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
const COORD coord,
const bool trimLeft,
const bool lineWrapped) noexcept override;

View File

@@ -3,9 +3,6 @@
#include "precomp.h"
#include <algorithm>
#include <numeric>
#include "vtrenderer.hpp"
#include "../../inc/conattrs.hpp"
#include "../../types/inc/convert.hpp"
@@ -128,13 +125,12 @@ using namespace Microsoft::Console::Types;
// will be false.
// Return Value:
// - S_OK or suitable HRESULT error from writing pipe.
[[nodiscard]] HRESULT VtEngine::PaintBufferLine(std::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] HRESULT VtEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
const COORD coord,
const bool /*trimLeft*/,
const bool /*lineWrapped*/) noexcept
{
return VtEngine::_PaintAsciiBufferLine(text, clusterMap, coord);
return VtEngine::_PaintAsciiBufferLine(clusters, coord);
}
// Method Description:
@@ -346,28 +342,27 @@ 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::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] HRESULT VtEngine::_PaintAsciiBufferLine(std::basic_string_view<Cluster> const clusters,
const COORD coord) noexcept
{
try
{
RETURN_IF_FAILED(_MoveCursor(coord));
/*_bufferLine.clear();*/
//_bufferLine.reserve(clusters.size());
std::wstring wstr;
wstr.reserve(clusters.size());
/*short totalWidth = 0;
short totalWidth = 0;
for (const auto& cluster : clusters)
{
_bufferLine.append(cluster.GetText());
wstr.append(cluster.GetText());
RETURN_IF_FAILED(ShortAdd(totalWidth, gsl::narrow<short>(cluster.GetColumns()), &totalWidth));
}*/
}
RETURN_IF_FAILED(VtEngine::_WriteTerminalAscii(text));
RETURN_IF_FAILED(VtEngine::_WriteTerminalAscii(wstr));
// Update our internal tracker of the cursor's position
_lastText.X += (SHORT)std::accumulate(clusterMap.begin(), clusterMap.end(), 0);
_lastText.X += totalWidth;
return S_OK;
}
@@ -382,8 +377,7 @@ 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::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] HRESULT VtEngine::_PaintUtf8BufferLine(std::basic_string_view<Cluster> const clusters,
const COORD coord,
const bool lineWrapped) noexcept
{
@@ -392,21 +386,21 @@ using namespace Microsoft::Console::Types;
return S_OK;
}
/*_bufferLine.clear();
_bufferLine.reserve(clusters.size());*/
short totalWidth = (SHORT)std::accumulate(clusterMap.begin(), clusterMap.end(), 0);
/*for (const auto& cluster : clusters)
std::wstring unclusteredString;
unclusteredString.reserve(clusters.size());
short totalWidth = 0;
for (const auto& cluster : clusters)
{
_bufferLine.append(cluster.GetText());
unclusteredString.append(cluster.GetText());
RETURN_IF_FAILED(ShortAdd(totalWidth, static_cast<short>(cluster.GetColumns()), &totalWidth));
}*/
const size_t cchLine = text.size();
}
const size_t cchLine = unclusteredString.size();
bool foundNonspace = false;
size_t lastNonSpace = 0;
for (size_t i = 0; i < cchLine; i++)
{
if (text.at(i) != L'\x20')
if (unclusteredString.at(i) != L'\x20')
{
lastNonSpace = i;
foundNonspace = true;
@@ -500,7 +494,8 @@ using namespace Microsoft::Console::Types;
RETURN_IF_FAILED(_MoveCursor(coord));
// Write the actual text string
RETURN_IF_FAILED(VtEngine::_WriteTerminalUtf8({ text.data(), cchActual }));
std::wstring wstr = std::wstring(unclusteredString.data(), cchActual);
RETURN_IF_FAILED(VtEngine::_WriteTerminalUtf8(wstr));
// GH#4415, GH#5181
// If the renderer told us that this was a wrapped line, then mark

View File

@@ -101,51 +101,6 @@ 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
{
@@ -157,23 +112,6 @@ 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,8 +63,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] virtual HRESULT ScrollFrame() noexcept = 0;
[[nodiscard]] HRESULT PaintBackground() noexcept override;
[[nodiscard]] virtual HRESULT PaintBufferLine(std::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] virtual HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
const COORD coord,
const bool trimLeft,
const bool lineWrapped) noexcept override;
@@ -225,16 +224,11 @@ namespace Microsoft::Console::Render
bool _WillWriteSingleChar() const;
// 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,
[[nodiscard]] HRESULT _PaintUtf8BufferLine(std::basic_string_view<Cluster> const clusters,
const COORD coord,
const bool lineWrapped) noexcept;
[[nodiscard]] HRESULT _PaintAsciiBufferLine(std::wstring_view text,
std::basic_string_view<UINT16> clusterMap,
[[nodiscard]] HRESULT _PaintAsciiBufferLine(std::basic_string_view<Cluster> const clusters,
const COORD coord) noexcept;
[[nodiscard]] HRESULT _WriteTerminalUtf8(const std::wstring_view str) noexcept;