From 428dec97028d3c9f8337c5f3c31ff7f485ac36e9 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Thu, 29 Jul 2021 08:44:43 -0700 Subject: [PATCH 01/10] Implement Keyboard Selection --- doc/cascadia/profiles.schema.json | 42 ++++ src/buffer/out/textBuffer.cpp | 10 +- src/buffer/out/textBuffer.hpp | 2 +- .../TerminalApp/AppActionHandlers.cpp | 15 ++ src/cascadia/TerminalControl/ControlCore.cpp | 25 +- src/cascadia/TerminalControl/ControlCore.h | 1 + src/cascadia/TerminalControl/ControlCore.idl | 1 + src/cascadia/TerminalControl/TermControl.cpp | 5 + src/cascadia/TerminalControl/TermControl.h | 1 + src/cascadia/TerminalControl/TermControl.idl | 1 + src/cascadia/TerminalCore/ICoreSettings.idl | 18 ++ src/cascadia/TerminalCore/Terminal.hpp | 19 +- .../TerminalCore/TerminalSelection.cpp | 215 ++++++++++++++++-- .../TerminalCore/terminalrenderdata.cpp | 2 +- .../TerminalSettingsModel/ActionAndArgs.cpp | 1 + .../TerminalSettingsModel/ActionArgs.cpp | 6 + .../TerminalSettingsModel/ActionArgs.h | 62 +++++ .../TerminalSettingsModel/ActionArgs.idl | 6 + .../AllShortcutActions.h | 6 +- .../TerminalSettingsSerializationHelpers.h | 20 ++ .../TerminalSettingsModel/defaults.json | 14 ++ .../UnitTests_TerminalCore/SelectionTest.cpp | 34 +-- src/host/ut_host/TextBufferTests.cpp | 2 +- src/types/UiaTextRangeBase.cpp | 2 +- 24 files changed, 454 insertions(+), 56 deletions(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index 07e584c6ba7..b74299ebf5f 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -304,6 +304,7 @@ "toggleSplitOrientation", "toggleReadOnlyMode", "toggleShaderEffects", + "updateSelection", "wt", "quit", "unbound" @@ -332,6 +333,24 @@ ], "type": "string" }, + "SelectionDirection": { + "enum": [ + "left", + "right", + "up", + "down" + ], + "type": "string" + }, + "SelectionMode": { + "enum": [ + "cell", + "word", + "view", + "buffer" + ], + "type": "string" + }, "MoveTabDirection": { "enum": [ "forward", @@ -586,6 +605,28 @@ ], "required": [ "direction" ] }, + "UpdateSelectionAction": { + "description": "Arguments corresponding to a Update Selection Action", + "allOf": [ + { "$ref": "#/definitions/ShortcutAction" }, + { + "properties": { + "action": { "type": "string", "pattern": "updateSelection" }, + "direction": { + "$ref": "#/definitions/SelectionDirection", + "default": "left", + "description": "The direction to move the selection endpoint in." + }, + "mode": { + "$ref": "#/definitions/SelectionMode", + "default": "cell", + "description": "The expansion mode to move the selection endpoint by." + } + } + } + ], + "required": [ "direction" ] + }, "ResizePaneAction": { "description": "Arguments corresponding to a Resize Pane Action", "allOf": [ @@ -1066,6 +1107,7 @@ { "$ref": "#/definitions/FocusPaneAction" }, { "$ref": "#/definitions/GlobalSummonAction" }, { "$ref": "#/definitions/QuakeModeAction" }, + { "$ref": "#/definitions/UpdateSelectionAction" }, { "type": "null" } ] }, diff --git a/src/buffer/out/textBuffer.cpp b/src/buffer/out/textBuffer.cpp index 466e38ecfc9..3fba7b0829b 100644 --- a/src/buffer/out/textBuffer.cpp +++ b/src/buffer/out/textBuffer.cpp @@ -1430,12 +1430,13 @@ const til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional limitOptional) const +const til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode, std::optional limitOptional) const { COORD resultPos = pos; const auto bufferSize = GetSize(); @@ -1453,7 +1454,10 @@ const til::point TextBuffer::GetGlyphEnd(const til::point pos, std::optional limitOptional = std::nullopt) const; - const til::point GetGlyphEnd(const til::point pos, std::optional limitOptional = std::nullopt) const; + const til::point GetGlyphEnd(const til::point pos, bool accessibilityMode = false, std::optional limitOptional = std::nullopt) const; bool MoveToNextGlyph(til::point& pos, bool allowBottomExclusive = false, std::optional limitOptional = std::nullopt) const; bool MoveToPreviousGlyph(til::point& pos, std::optional limitOptional = std::nullopt) const; diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 1ef4c0c8ab4..6dd3c8768ff 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -921,4 +921,19 @@ namespace winrt::TerminalApp::implementation } } } + + void TerminalPage::_HandleUpdateSelection(const IInspectable& /*sender*/, + const ActionEventArgs& args) + { + if (args) + { + if (const auto& realArgs = args.ActionArgs().try_as()) + { + if (const auto termControl{ _GetActiveControl() }) + { + args.Handled(termControl.UpdateSelection(realArgs.Direction(), realArgs.Mode())); + } + } + } + } } diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index eac350c2ac3..a813cb49dbc 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -927,6 +927,21 @@ namespace winrt::Microsoft::Terminal::Control::implementation _renderer->TriggerSelection(); } + bool ControlCore::UpdateSelection(Core::SelectionDirection direction, Core::SelectionExpansion mode) + { + // - SelectionDirection cannot be none + // - A selection must be active for us to update it + if (direction == Core::SelectionDirection::None || !HasSelection()) + { + return false; + } + + auto lock = _terminal->LockForWriting(); + _terminal->UpdateSelection(direction, mode); + _renderer->TriggerSelection(); + return true; + } + // Called when the Terminal wants to set something to the clipboard, i.e. // when an OSC 52 is emitted. void ControlCore::_terminalCopyToClipboard(std::wstring_view wstr) @@ -1422,18 +1437,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation // handle ALT key _terminal->SetBlockSelection(altEnabled); - ::Terminal::SelectionExpansionMode mode = ::Terminal::SelectionExpansionMode::Cell; + Core::SelectionExpansion mode = Core::SelectionExpansion::Cell; if (numberOfClicks == 1) { - mode = ::Terminal::SelectionExpansionMode::Cell; + mode = Core::SelectionExpansion::Cell; } else if (numberOfClicks == 2) { - mode = ::Terminal::SelectionExpansionMode::Word; + mode = Core::SelectionExpansion::Word; } else if (numberOfClicks == 3) { - mode = ::Terminal::SelectionExpansionMode::Line; + mode = Core::SelectionExpansion::Line; } // Update the selection appropriately @@ -1458,7 +1473,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation _terminal->SetSelectionEnd(terminalPosition, mode); selectionNeedsToBeCopied = true; } - else if (mode != ::Terminal::SelectionExpansionMode::Cell || shiftEnabled) + else if (mode != Core::SelectionExpansion::Cell || shiftEnabled) { // If we are handling a double / triple-click or shift+single click // we establish selection using the selected mode diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index a04032ef78e..3eedcad93f8 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -130,6 +130,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation Windows::Foundation::Collections::IVector SelectedText(bool trimTrailingWhitespace) const; void SetSelectionAnchor(til::point const& position); void SetEndSelectionPoint(til::point const& position); + bool UpdateSelection(Core::SelectionDirection direction, Core::SelectionExpansion mode); void Search(const winrt::hstring& text, const bool goForward, diff --git a/src/cascadia/TerminalControl/ControlCore.idl b/src/cascadia/TerminalControl/ControlCore.idl index 84cb83e80f2..467e30bbb76 100644 --- a/src/cascadia/TerminalControl/ControlCore.idl +++ b/src/cascadia/TerminalControl/ControlCore.idl @@ -80,6 +80,7 @@ namespace Microsoft.Terminal.Control Boolean HasSelection { get; }; IVector SelectedText(Boolean trimTrailingWhitespace); + Boolean UpdateSelection(Microsoft.Terminal.Core.SelectionDirection direction, Microsoft.Terminal.Core.SelectionExpansion mode); String HoveredUriText { get; }; Windows.Foundation.IReference HoveredCell { get; }; diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 115f9afc580..7686cd909d9 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -2577,4 +2577,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation { return _core.ReadEntireBuffer(); } + + bool TermControl::UpdateSelection(Core::SelectionDirection direction, Core::SelectionExpansion mode) + { + return _core.UpdateSelection(direction, mode); + } } diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index 9d0f22e339f..fbd573bae60 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -32,6 +32,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation hstring GetProfileName() const; + bool UpdateSelection(Core::SelectionDirection direction, Core::SelectionExpansion mode); bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference& formats); void PasteTextFromClipboard(); void Close(); diff --git a/src/cascadia/TerminalControl/TermControl.idl b/src/cascadia/TerminalControl/TermControl.idl index 26db0862cac..9b5b03d1a0f 100644 --- a/src/cascadia/TerminalControl/TermControl.idl +++ b/src/cascadia/TerminalControl/TermControl.idl @@ -45,6 +45,7 @@ namespace Microsoft.Terminal.Control // We expose this and ConnectionState here so that it might eventually be data bound. event Windows.Foundation.TypedEventHandler ConnectionStateChanged; + Boolean UpdateSelection(Microsoft.Terminal.Core.SelectionDirection direction, Microsoft.Terminal.Core.SelectionExpansion mode); Boolean CopySelectionToClipboard(Boolean singleLine, Windows.Foundation.IReference formats); void PasteTextFromClipboard(); void ClearBuffer(ClearBufferType clearType); diff --git a/src/cascadia/TerminalCore/ICoreSettings.idl b/src/cascadia/TerminalCore/ICoreSettings.idl index dd0b4939b3b..4d5f2ee5695 100644 --- a/src/cascadia/TerminalCore/ICoreSettings.idl +++ b/src/cascadia/TerminalCore/ICoreSettings.idl @@ -5,6 +5,24 @@ import "..\ICoreAppearance.idl"; namespace Microsoft.Terminal.Core { + enum SelectionDirection + { + None = 0, + Left, + Right, + Up, + Down, + }; + + enum SelectionExpansion + { + Cell, + Word, + Line, // Mouse selection only! Not a setting! + Viewport, + Buffer + }; + interface ICoreSettings requires ICoreAppearance { // TODO:MSFT:20642297 - define a sentinel for Infinite Scrollback diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 27e26b7f280..e4b242f97c0 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -227,16 +227,11 @@ class Microsoft::Terminal::Core::Terminal final : #pragma region TextSelection // These methods are defined in TerminalSelection.cpp - enum class SelectionExpansionMode - { - Cell, - Word, - Line - }; - void MultiClickSelection(const COORD viewportPos, SelectionExpansionMode expansionMode); + void MultiClickSelection(const COORD viewportPos, winrt::Microsoft::Terminal::Core::SelectionExpansion expansionMode); void SetSelectionAnchor(const COORD position); - void SetSelectionEnd(const COORD position, std::optional newExpansionMode = std::nullopt); + void SetSelectionEnd(const COORD position, std::optional newExpansionMode = std::nullopt); void SetBlockSelection(const bool isEnabled) noexcept; + void UpdateSelection(winrt::Microsoft::Terminal::Core::SelectionDirection direction, winrt::Microsoft::Terminal::Core::SelectionExpansion mode); const TextBuffer::TextAndColor RetrieveSelectedTextFromBuffer(bool trimTrailingWhitespace); #pragma endregion @@ -308,7 +303,7 @@ class Microsoft::Terminal::Core::Terminal final : std::optional _selection; bool _blockSelection; std::wstring _wordDelimiters; - SelectionExpansionMode _multiClickSelectionMode; + winrt::Microsoft::Terminal::Core::SelectionExpansion _multiClickSelectionMode; #pragma endregion // TODO: These members are not shared by an alt-buffer. They should be @@ -372,9 +367,13 @@ class Microsoft::Terminal::Core::Terminal final : #pragma region TextSelection // These methods are defined in TerminalSelection.cpp std::vector _GetSelectionRects() const noexcept; - std::pair _PivotSelection(const COORD targetPos, bool& targetStart) const; + std::tuple _PivotSelection(const COORD targetPos) const; std::pair _ExpandSelectionAnchors(std::pair anchors) const; COORD _ConvertToBufferCell(const COORD viewportPos) const; + void _MoveByChar(winrt::Microsoft::Terminal::Core::SelectionDirection direction, COORD& pos); + void _MoveByWord(winrt::Microsoft::Terminal::Core::SelectionDirection direction, COORD& pos); + void _MoveByViewport(winrt::Microsoft::Terminal::Core::SelectionDirection direction, COORD& pos); + void _MoveByBuffer(winrt::Microsoft::Terminal::Core::SelectionDirection direction, COORD& pos); #pragma endregion Microsoft::Console::VirtualTerminal::SgrStack _sgrStack; diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index c8c877032a7..3837f1ed3c2 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -5,7 +5,10 @@ #include "Terminal.hpp" #include "unicode.hpp" +#include + using namespace Microsoft::Terminal::Core; +using namespace winrt::Microsoft::Terminal::Core; /* Selection Pivot Description: * The pivot helps properly update the selection when a user moves a selection over itself @@ -100,8 +103,8 @@ const bool Terminal::IsBlockSelection() const noexcept // - Perform a multi-click selection at viewportPos expanding according to the expansionMode // Arguments: // - viewportPos: the (x,y) coordinate on the visible viewport -// - expansionMode: the SelectionExpansionMode to dictate the boundaries of the selection anchors -void Terminal::MultiClickSelection(const COORD viewportPos, SelectionExpansionMode expansionMode) +// - expansionMode: the SelectionExpansion to dictate the boundaries of the selection anchors +void Terminal::MultiClickSelection(const COORD viewportPos, SelectionExpansion expansionMode) { // set the selection pivot to expand the selection using SetSelectionEnd() _selection = SelectionAnchors{}; @@ -124,7 +127,7 @@ void Terminal::SetSelectionAnchor(const COORD viewportPos) _selection = SelectionAnchors{}; _selection->pivot = _ConvertToBufferCell(viewportPos); - _multiClickSelectionMode = SelectionExpansionMode::Cell; + _multiClickSelectionMode = SelectionExpansion::Cell; SetSelectionEnd(viewportPos); _selection->start = _selection->pivot; @@ -136,7 +139,7 @@ void Terminal::SetSelectionAnchor(const COORD viewportPos) // Arguments: // - viewportPos: the (x,y) coordinate on the visible viewport // - newExpansionMode: overwrites the _multiClickSelectionMode for this function call. Used for ShiftClick -void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional newExpansionMode) +void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional newExpansionMode) { if (!_selection.has_value()) { @@ -151,8 +154,9 @@ void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional anchors; + bool targetStart; + std::tie(anchors.first, anchors.second, targetStart) = _PivotSelection(textBufferPos); const auto expandedAnchors = _ExpandSelectionAnchors(anchors); if (newExpansionMode.has_value()) @@ -177,22 +181,24 @@ void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional Terminal::_PivotSelection(const COORD targetPos, bool& targetStart) const +// - COORD: the new start for a selection +// - COORD: the new end for a selection +// - bool: if true, target will be the new start. Otherwise, target will be the new end. +std::tuple Terminal::_PivotSelection(const COORD targetPos) const { - if (targetStart = _buffer->GetSize().CompareInBounds(targetPos, _selection->pivot) <= 0) + const bool targetStart{ _buffer->GetSize().CompareInBounds(targetPos, _selection->pivot) <= 0 }; + if (targetStart) { // target is before pivot // treat target as start - return std::make_pair(targetPos, _selection->pivot); + return { targetPos, _selection->pivot, targetStart }; } else { // target is after pivot // treat pivot as start - return std::make_pair(_selection->pivot, targetPos); + return { _selection->pivot, targetPos, targetStart }; } } @@ -210,15 +216,15 @@ std::pair Terminal::_ExpandSelectionAnchors(std::pairGetSize(); switch (_multiClickSelectionMode) { - case SelectionExpansionMode::Line: + case SelectionExpansion::Line: start = { bufferSize.Left(), start.Y }; end = { bufferSize.RightInclusive(), end.Y }; break; - case SelectionExpansionMode::Word: + case SelectionExpansion::Word: start = _buffer->GetWordStart(start, _wordDelimiters); end = _buffer->GetWordEnd(end, _wordDelimiters); break; - case SelectionExpansionMode::Cell: + case SelectionExpansion::Cell: default: // no expansion is necessary break; @@ -235,6 +241,185 @@ void Terminal::SetBlockSelection(const bool isEnabled) noexcept _blockSelection = isEnabled; } +bool Terminal::MovingStart() const noexcept +{ + // true --> we're moving start endpoint ("higher") + // false --> we're moving end endpoint ("lower") + return _selection->start == _selection->pivot ? false : true; +} + +void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode) +{ + // 1. Figure out which endpoint to update + // One of the endpoints is the pivot, signifying that the other endpoint is the one we want to move. + auto targetPos{ _selection->start == _selection->pivot ? _selection->end : _selection->start }; + + // 2. Perform the movement + switch (mode) + { + case SelectionExpansion::Cell: + _MoveByChar(direction, targetPos); + break; + case SelectionExpansion::Word: + _MoveByWord(direction, targetPos); + break; + case SelectionExpansion::Viewport: + _MoveByViewport(direction, targetPos); + break; + case SelectionExpansion::Buffer: + _MoveByBuffer(direction, targetPos); + break; + } + + // 3. Actually modify the selection + std::tie(_selection->start, _selection->end, std::ignore) = _PivotSelection(targetPos); + + // 4. Scroll (if necessary) + if (const auto viewport = _GetVisibleViewport(); !viewport.IsInBounds(targetPos)) + { + if (const auto amtAboveView = viewport.Top() - targetPos.Y; amtAboveView > 0) + { + // anchor is above visible viewport, scroll by that amount + _scrollOffset += amtAboveView; + } + else + { + // anchor is below visible viewport, scroll by that amount + const auto amtBelowView = targetPos.Y - viewport.BottomInclusive(); + _scrollOffset -= amtBelowView; + } + _NotifyScrollEvent(); + } +} + +void Terminal::_MoveByChar(SelectionDirection direction, COORD& pos) +{ + switch (direction) + { + case SelectionDirection::Left: + _buffer->GetSize().DecrementInBounds(pos); + pos = _buffer->GetGlyphStart(pos); + break; + case SelectionDirection::Right: + _buffer->GetSize().IncrementInBounds(pos); + pos = _buffer->GetGlyphEnd(pos); + break; + case SelectionDirection::Up: + { + const auto bufferSize{ _buffer->GetSize() }; + pos = { pos.X, std::clamp(base::ClampSub(pos.Y, 1).RawValue(), bufferSize.Top(), bufferSize.BottomInclusive()) }; + break; + } + case SelectionDirection::Down: + { + const auto bufferSize{ _buffer->GetSize() }; + pos = { pos.X, std::clamp(base::ClampAdd(pos.Y, 1).RawValue(), bufferSize.Top(), bufferSize.BottomInclusive()) }; + break; + } + } +} + +void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos) +{ + switch (direction) + { + case SelectionDirection::Left: + const auto wordStartPos{ _buffer->GetWordStart(pos, _wordDelimiters) }; + if (_buffer->GetSize().CompareInBounds(_selection->pivot, pos) < 0) + { + // If we're moving towards the pivot, move one more cell + pos = wordStartPos; + _buffer->GetSize().DecrementInBounds(pos); + } + else if (wordStartPos == pos) + { + // already at the beginning of the current word, + // move to the beginning of the previous word + _buffer->GetSize().DecrementInBounds(pos); + pos = _buffer->GetWordStart(pos, _wordDelimiters); + } + else + { + // move to the beginning of the current word + pos = wordStartPos; + } + break; + case SelectionDirection::Right: + const auto wordEndPos{ _buffer->GetWordEnd(pos, _wordDelimiters) }; + if (_buffer->GetSize().CompareInBounds(pos, _selection->pivot) < 0) + { + // If we're moving towards the pivot, move one more cell + pos = _buffer->GetWordEnd(pos, _wordDelimiters); + _buffer->GetSize().IncrementInBounds(pos); + } + else if (wordEndPos == pos) + { + // already at the end of the current word, + // move to the end of the next word + _buffer->GetSize().IncrementInBounds(pos); + pos = _buffer->GetWordEnd(pos, _wordDelimiters); + } + else + { + // move to the end of the current word + pos = wordEndPos; + } + break; + case SelectionDirection::Up: + _MoveByChar(direction, pos); + pos = _buffer->GetWordStart(pos, _wordDelimiters); + break; + case SelectionDirection::Down: + _MoveByChar(direction, pos); + pos = _buffer->GetWordEnd(pos, _wordDelimiters); + break; + } +} + +void Terminal::_MoveByViewport(SelectionDirection direction, COORD& pos) +{ + const auto bufferSize{ _buffer->GetSize() }; + switch (direction) + { + case SelectionDirection::Left: + pos = { bufferSize.Left(), pos.Y }; + break; + case SelectionDirection::Right: + pos = { bufferSize.RightInclusive(), pos.Y }; + break; + case SelectionDirection::Up: + { + const auto viewportHeight{ _mutableViewport.Height() }; + const auto newY{ base::ClampSub(pos.Y, viewportHeight) }; + pos = newY < bufferSize.Top() ? bufferSize.Origin() : COORD{ pos.X, newY }; + break; + } + case SelectionDirection::Down: + { + const auto viewportHeight{ _mutableViewport.Height() }; + const auto newY{ base::ClampAdd(pos.Y, viewportHeight) }; + pos = newY > bufferSize.BottomInclusive() ? COORD{ bufferSize.RightInclusive(), bufferSize.BottomInclusive() } : COORD{ pos.X, newY }; + break; + } + } +} + +void Terminal::_MoveByBuffer(SelectionDirection direction, COORD& pos) +{ + const auto bufferSize{ _buffer->GetSize() }; + switch (direction) + { + case SelectionDirection::Left: + case SelectionDirection::Up: + pos = bufferSize.Origin(); + break; + case SelectionDirection::Right: + case SelectionDirection::Down: + pos = { bufferSize.RightInclusive(), bufferSize.BottomInclusive() }; + break; + } +} + // Method Description: // - clear selection data and disable rendering it #pragma warning(disable : 26440) // changing this to noexcept would require a change to ConHost's selection model diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index 84b00eadfeb..489892be584 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -206,7 +206,7 @@ void Terminal::SelectNewRegion(const COORD coordStart, const COORD coordEnd) realCoordEnd.Y -= gsl::narrow(_VisibleStartIndex()); SetSelectionAnchor(realCoordStart); - SetSelectionEnd(realCoordEnd, SelectionExpansionMode::Cell); + SetSelectionEnd(realCoordEnd, winrt::Microsoft::Terminal::Core::SelectionExpansion::Cell); } const std::wstring_view Terminal::GetConsoleTitle() const noexcept diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp index 2ae6bb6da3b..dbdcb17466a 100644 --- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp @@ -69,6 +69,7 @@ static constexpr std::string_view OpenSystemMenuKey{ "openSystemMenu" }; static constexpr std::string_view ClearBufferKey{ "clearBuffer" }; static constexpr std::string_view MultipleActionsKey{ "multipleActions" }; static constexpr std::string_view QuitKey{ "quit" }; +static constexpr std::string_view UpdateSelectionKey{ "updateSelection" }; static constexpr std::string_view ActionKey{ "action" }; diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp index dd30f354726..cc052f90157 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp @@ -36,6 +36,7 @@ #include "FocusPaneArgs.g.cpp" #include "ClearBufferArgs.g.cpp" #include "MultipleActionsArgs.g.cpp" +#include "UpdateSelectionArgs.g.cpp" #include @@ -718,4 +719,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { return L""; } + + winrt::hstring UpdateSelectionArgs::GenerateName() const + { + return L""; + } } diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h index 94f7cebea7d..79774f9c39e 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h @@ -38,6 +38,7 @@ #include "FocusPaneArgs.g.h" #include "ClearBufferArgs.g.h" #include "MultipleActionsArgs.g.h" +#include "UpdateSelectionArgs.g.h" #include "../../cascadia/inc/cppwinrt_utils.h" #include "JsonUtils.h" @@ -1859,6 +1860,67 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(_Actions); } }; + + struct UpdateSelectionArgs : public UpdateSelectionArgsT + { + UpdateSelectionArgs() = default; + ACTION_ARG(Core::SelectionDirection, Direction, Core::SelectionDirection::None); + ACTION_ARG(Core::SelectionExpansion, Mode, Core::SelectionExpansion::Cell); + static constexpr std::string_view DirectionKey{ "direction" }; + static constexpr std::string_view ModeKey{ "mode" }; + + public: + hstring GenerateName() const; + + bool Equals(const IActionArgs& other) + { + auto otherAsUs = other.try_as(); + if (otherAsUs) + { + return otherAsUs->_Direction == _Direction && otherAsUs->_Mode == _Mode; + } + 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(); + JsonUtils::GetValueForKey(json, DirectionKey, args->_Direction); + JsonUtils::GetValueForKey(json, ModeKey, args->_Mode); + if (args->Direction() == Core::SelectionDirection::None) + { + return { nullptr, { SettingsLoadWarnings::MissingRequiredParameter } }; + } + else + { + return { *args, {} }; + } + } + static Json::Value ToJson(const IActionArgs& val) + { + if (!val) + { + return {}; + } + Json::Value json{ Json::ValueType::objectValue }; + const auto args{ get_self(val) }; + JsonUtils::SetValueForKey(json, DirectionKey, args->_Direction); + JsonUtils::SetValueForKey(json, ModeKey, args->_Mode); + return json; + } + IActionArgs Copy() const + { + auto copy{ winrt::make_self() }; + copy->_Direction = _Direction; + copy->_Mode = _Mode; + return *copy; + } + size_t Hash() const + { + return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(_Direction, _Mode); + } + }; + } namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl index 21b1b4b0bcb..5acf82fb0c5 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl @@ -323,4 +323,10 @@ namespace Microsoft.Terminal.Settings.Model MultipleActionsArgs(); Windows.Foundation.Collections.IVector Actions; }; + + [default_interface] runtimeclass UpdateSelectionArgs : IActionArgs + { + Microsoft.Terminal.Core.SelectionDirection Direction { get; }; + Microsoft.Terminal.Core.SelectionExpansion Mode { get; }; + }; } diff --git a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h index aa06ae70cda..801e8ece981 100644 --- a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h +++ b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h @@ -82,7 +82,8 @@ ON_ALL_ACTIONS(OpenSystemMenu) \ ON_ALL_ACTIONS(ClearBuffer) \ ON_ALL_ACTIONS(MultipleActions) \ - ON_ALL_ACTIONS(Quit) + ON_ALL_ACTIONS(Quit) \ + ON_ALL_ACTIONS(UpdateSelection) #define ALL_SHORTCUT_ACTIONS_WITH_ARGS \ ON_ALL_ACTIONS_WITH_ARGS(AdjustFontSize) \ @@ -115,4 +116,5 @@ ON_ALL_ACTIONS_WITH_ARGS(ToggleCommandPalette) \ ON_ALL_ACTIONS_WITH_ARGS(FocusPane) \ ON_ALL_ACTIONS_WITH_ARGS(ClearBuffer) \ - ON_ALL_ACTIONS_WITH_ARGS(MultipleActions) + ON_ALL_ACTIONS_WITH_ARGS(MultipleActions) \ + ON_ALL_ACTIONS_WITH_ARGS(UpdateSelection) diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h index 83c791f95ed..882d86ee22c 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h @@ -512,3 +512,23 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage) pair_type{ "keyboardServiceWarning", ValueType::KeyboardServiceWarning }, }; }; + +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Core::SelectionDirection) +{ + static constexpr std::array mappings = { + pair_type{ "left", ValueType::Left }, + pair_type{ "right", ValueType::Right }, + pair_type{ "up", ValueType::Up }, + pair_type{ "down", ValueType::Down } + }; +}; + +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Core::SelectionExpansion) +{ + static constexpr std::array mappings = { + pair_type{ "cell", ValueType::Cell }, + pair_type{ "word", ValueType::Word }, + pair_type{ "view", ValueType::Viewport }, + pair_type{ "buffer", ValueType::Buffer } + }; +}; diff --git a/src/cascadia/TerminalSettingsModel/defaults.json b/src/cascadia/TerminalSettingsModel/defaults.json index 6261e743a93..339d1aa44ee 100644 --- a/src/cascadia/TerminalSettingsModel/defaults.json +++ b/src/cascadia/TerminalSettingsModel/defaults.json @@ -380,6 +380,20 @@ { "command": "paste", "keys": "ctrl+shift+v" }, { "command": "paste", "keys": "shift+insert" }, + // Keyboard Selection + { "command": {"action": "updateSelection", "direction": "left", "mode": "cell" }, "keys": "shift+left" }, + { "command": {"action": "updateSelection", "direction": "right", "mode": "cell" }, "keys": "shift+right" }, + { "command": {"action": "updateSelection", "direction": "up", "mode": "cell" }, "keys": "shift+up" }, + { "command": {"action": "updateSelection", "direction": "down", "mode": "cell" }, "keys": "shift+down" }, + { "command": {"action": "updateSelection", "direction": "left", "mode": "word" }, "keys": "ctrl+shift+left" }, + { "command": {"action": "updateSelection", "direction": "right", "mode": "word" }, "keys": "ctrl+shift+right" }, + { "command": {"action": "updateSelection", "direction": "left", "mode": "view" }, "keys": "shift+home" }, + { "command": {"action": "updateSelection", "direction": "right", "mode": "view" }, "keys": "shift+end" }, + { "command": {"action": "updateSelection", "direction": "up", "mode": "view" }, "keys": "shift+pgup" }, + { "command": {"action": "updateSelection", "direction": "down", "mode": "view" }, "keys": "shift+pgdn" }, + { "command": {"action": "updateSelection", "direction": "up", "mode": "buffer" }, "keys": "ctrl+shift+home" }, + { "command": {"action": "updateSelection", "direction": "down", "mode": "buffer" }, "keys": "ctrl+shift+end" }, + // Scrollback { "command": "scrollDown", "keys": "ctrl+shift+down" }, { "command": "scrollDownPage", "keys": "ctrl+shift+pgdn" }, diff --git a/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp b/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp index d5e5a8f03d7..94b61f0944c 100644 --- a/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp +++ b/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp @@ -130,7 +130,7 @@ namespace TerminalCoreUnitTests DummyRenderTarget emptyRT; term.Create({ 10, 10 }, scrollback, emptyRT); - term.MultiClickSelection(maxCoord, Terminal::SelectionExpansionMode::Word); + term.MultiClickSelection(maxCoord, SelectionExpansion::Word); ValidateSingleRowSelection(term, expected); }; @@ -142,7 +142,7 @@ namespace TerminalCoreUnitTests DummyRenderTarget emptyRT; term.Create({ 10, 10 }, scrollback, emptyRT); - term.MultiClickSelection(maxCoord, Terminal::SelectionExpansionMode::Line); + term.MultiClickSelection(maxCoord, SelectionExpansion::Line); ValidateSingleRowSelection(term, expected); }; @@ -501,7 +501,7 @@ namespace TerminalCoreUnitTests // Simulate double click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, Terminal::SelectionExpansionMode::Word); + term.MultiClickSelection(clickPos, SelectionExpansion::Word); // Validate selection area ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, (4 + gsl::narrow(text.size()) - 1), 10 })); @@ -519,7 +519,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, Terminal::SelectionExpansionMode::Word); + term.MultiClickSelection(clickPos, SelectionExpansion::Word); // Simulate renderer calling TriggerSelection and acquiring selection area auto selectionRects = term.GetSelectionRects(); @@ -546,7 +546,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (15,10) // this is over the '>' char auto clickPos = COORD{ 15, 10 }; - term.MultiClickSelection(clickPos, Terminal::SelectionExpansionMode::Word); + term.MultiClickSelection(clickPos, SelectionExpansion::Word); // ---Validate selection area--- // "Terminal" is in class 2 @@ -572,7 +572,7 @@ namespace TerminalCoreUnitTests term.Write(text); // Simulate double click at (x,y) = (5,10) - term.MultiClickSelection({ 5, 10 }, Terminal::SelectionExpansionMode::Word); + term.MultiClickSelection({ 5, 10 }, SelectionExpansion::Word); // Simulate move to (x,y) = (21,10) // @@ -601,7 +601,7 @@ namespace TerminalCoreUnitTests term.Write(text); // Simulate double click at (x,y) = (21,10) - term.MultiClickSelection({ 21, 10 }, Terminal::SelectionExpansionMode::Word); + term.MultiClickSelection({ 21, 10 }, SelectionExpansion::Word); // Simulate move to (x,y) = (5,10) // @@ -622,7 +622,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, Terminal::SelectionExpansionMode::Line); + term.MultiClickSelection(clickPos, SelectionExpansion::Line); // Validate selection area ValidateSingleRowSelection(term, SMALL_RECT({ 0, 10, 99, 10 })); @@ -636,7 +636,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, Terminal::SelectionExpansionMode::Line); + term.MultiClickSelection(clickPos, SelectionExpansion::Line); // Simulate move to (x,y) = (7,10) term.SetSelectionEnd({ 7, 10 }); @@ -653,7 +653,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, Terminal::SelectionExpansionMode::Line); + term.MultiClickSelection(clickPos, SelectionExpansion::Line); // Simulate move to (x,y) = (5,11) term.SetSelectionEnd({ 5, 11 }); @@ -691,7 +691,7 @@ namespace TerminalCoreUnitTests // Step 1: Create a selection on "doubleClickMe" { // Simulate double click at (x,y) = (5,10) - term.MultiClickSelection({ 5, 10 }, Terminal::SelectionExpansionMode::Word); + term.MultiClickSelection({ 5, 10 }, SelectionExpansion::Word); // Validate selection area: "doubleClickMe" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 16, 10 })); @@ -704,7 +704,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere // ^ ^ // start finish - term.SetSelectionEnd({ 21, 10 }, ::Terminal::SelectionExpansionMode::Cell); + term.SetSelectionEnd({ 21, 10 }, SelectionExpansion::Cell); // Validate selection area: "doubleClickMe drag" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 21, 10 })); @@ -717,7 +717,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere // ^ ^ ^ // start click finish - term.SetSelectionEnd({ 21, 10 }, ::Terminal::SelectionExpansionMode::Word); + term.SetSelectionEnd({ 21, 10 }, SelectionExpansion::Word); // Validate selection area: "doubleClickMe dragThroughHere" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 32, 10 })); @@ -730,7 +730,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere | // ^ ^ ^ // start click finish (boundary) - term.SetSelectionEnd({ 21, 10 }, ::Terminal::SelectionExpansionMode::Line); + term.SetSelectionEnd({ 21, 10 }, SelectionExpansion::Line); // Validate selection area: "doubleClickMe dragThroughHere..." selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 99, 10 })); @@ -743,7 +743,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere // ^ ^ ^ // start click finish - term.SetSelectionEnd({ 21, 10 }, ::Terminal::SelectionExpansionMode::Word); + term.SetSelectionEnd({ 21, 10 }, SelectionExpansion::Word); // Validate selection area: "doubleClickMe dragThroughHere" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 32, 10 })); @@ -825,7 +825,7 @@ namespace TerminalCoreUnitTests // Step 4: Shift+Click at (5,10) { - term.SetSelectionEnd({ 5, 10 }, ::Terminal::SelectionExpansionMode::Cell); + term.SetSelectionEnd({ 5, 10 }, SelectionExpansion::Cell); // Validate selection area // NOTE: Pivot should still be (10, 10) @@ -834,7 +834,7 @@ namespace TerminalCoreUnitTests // Step 5: Shift+Click back at (20,10) { - term.SetSelectionEnd({ 20, 10 }, ::Terminal::SelectionExpansionMode::Cell); + term.SetSelectionEnd({ 20, 10 }, SelectionExpansion::Cell); // Validate selection area // NOTE: Pivot should still be (10, 10) diff --git a/src/host/ut_host/TextBufferTests.cpp b/src/host/ut_host/TextBufferTests.cpp index 92c07f85fd2..c8dd0679362 100644 --- a/src/host/ut_host/TextBufferTests.cpp +++ b/src/host/ut_host/TextBufferTests.cpp @@ -2253,7 +2253,7 @@ void TextBufferTests::GetGlyphBoundaries() _buffer->Write(iter, target); auto start = _buffer->GetGlyphStart(target); - auto end = _buffer->GetGlyphEnd(target); + auto end = _buffer->GetGlyphEnd(target, true); VERIFY_ARE_EQUAL(test.start, start); VERIFY_ARE_EQUAL(wideGlyph ? test.wideGlyphEnd : test.normalEnd, end); diff --git a/src/types/UiaTextRangeBase.cpp b/src/types/UiaTextRangeBase.cpp index ace7002c2a3..a38779be270 100644 --- a/src/types/UiaTextRangeBase.cpp +++ b/src/types/UiaTextRangeBase.cpp @@ -295,7 +295,7 @@ void UiaTextRangeBase::_expandToEnclosingUnit(TextUnit unit) if (unit == TextUnit_Character) { _start = buffer.GetGlyphStart(_start, documentEnd); - _end = buffer.GetGlyphEnd(_start, documentEnd); + _end = buffer.GetGlyphEnd(_start, documentEnd, true); } else if (unit <= TextUnit_Word) { From bcbf01e8cb3ac6127c74ddf737814b49ed2059be Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Wed, 18 Aug 2021 15:47:23 -0700 Subject: [PATCH 02/10] apply feedback from zadji --- src/cascadia/TerminalControl/ControlCore.cpp | 6 ++--- src/cascadia/TerminalCore/ICoreSettings.idl | 2 +- .../TerminalCore/TerminalSelection.cpp | 22 ++++++++----------- .../TerminalCore/terminalrenderdata.cpp | 2 +- .../TerminalSettingsModel/ActionArgs.h | 2 +- .../TerminalSettingsModel/defaults.json | 8 +++---- .../UnitTests_TerminalCore/SelectionTest.cpp | 6 ++--- 7 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index a813cb49dbc..b1e9136a01c 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -1437,10 +1437,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation // handle ALT key _terminal->SetBlockSelection(altEnabled); - Core::SelectionExpansion mode = Core::SelectionExpansion::Cell; + Core::SelectionExpansion mode = Core::SelectionExpansion::Char; if (numberOfClicks == 1) { - mode = Core::SelectionExpansion::Cell; + mode = Core::SelectionExpansion::Char; } else if (numberOfClicks == 2) { @@ -1473,7 +1473,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation _terminal->SetSelectionEnd(terminalPosition, mode); selectionNeedsToBeCopied = true; } - else if (mode != Core::SelectionExpansion::Cell || shiftEnabled) + else if (mode != Core::SelectionExpansion::Char || shiftEnabled) { // If we are handling a double / triple-click or shift+single click // we establish selection using the selected mode diff --git a/src/cascadia/TerminalCore/ICoreSettings.idl b/src/cascadia/TerminalCore/ICoreSettings.idl index 4d5f2ee5695..e03569414f2 100644 --- a/src/cascadia/TerminalCore/ICoreSettings.idl +++ b/src/cascadia/TerminalCore/ICoreSettings.idl @@ -16,7 +16,7 @@ namespace Microsoft.Terminal.Core enum SelectionExpansion { - Cell, + Char, Word, Line, // Mouse selection only! Not a setting! Viewport, diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index 3837f1ed3c2..0c15894ea60 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -127,7 +127,7 @@ void Terminal::SetSelectionAnchor(const COORD viewportPos) _selection = SelectionAnchors{}; _selection->pivot = _ConvertToBufferCell(viewportPos); - _multiClickSelectionMode = SelectionExpansion::Cell; + _multiClickSelectionMode = SelectionExpansion::Char; SetSelectionEnd(viewportPos); _selection->start = _selection->pivot; @@ -224,7 +224,7 @@ std::pair Terminal::_ExpandSelectionAnchors(std::pairGetWordStart(start, _wordDelimiters); end = _buffer->GetWordEnd(end, _wordDelimiters); break; - case SelectionExpansion::Cell: + case SelectionExpansion::Char: default: // no expansion is necessary break; @@ -241,23 +241,17 @@ void Terminal::SetBlockSelection(const bool isEnabled) noexcept _blockSelection = isEnabled; } -bool Terminal::MovingStart() const noexcept -{ - // true --> we're moving start endpoint ("higher") - // false --> we're moving end endpoint ("lower") - return _selection->start == _selection->pivot ? false : true; -} - void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode) { // 1. Figure out which endpoint to update // One of the endpoints is the pivot, signifying that the other endpoint is the one we want to move. - auto targetPos{ _selection->start == _selection->pivot ? _selection->end : _selection->start }; + const bool movingEnd{ _selection->start == _selection->pivot }; + auto targetPos{ movingEnd ? _selection->end : _selection->start }; // 2. Perform the movement switch (mode) { - case SelectionExpansion::Cell: + case SelectionExpansion::Char: _MoveByChar(direction, targetPos); break; case SelectionExpansion::Word: @@ -289,6 +283,7 @@ void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion _scrollOffset -= amtBelowView; } _NotifyScrollEvent(); + _buffer->GetRenderTarget().TriggerScroll(); } } @@ -397,8 +392,9 @@ void Terminal::_MoveByViewport(SelectionDirection direction, COORD& pos) case SelectionDirection::Down: { const auto viewportHeight{ _mutableViewport.Height() }; + const auto mutableBottom{ _mutableViewport.BottomInclusive() }; const auto newY{ base::ClampAdd(pos.Y, viewportHeight) }; - pos = newY > bufferSize.BottomInclusive() ? COORD{ bufferSize.RightInclusive(), bufferSize.BottomInclusive() } : COORD{ pos.X, newY }; + pos = newY > mutableBottom ? COORD{ bufferSize.RightInclusive(), mutableBottom } : COORD{ pos.X, newY }; break; } } @@ -415,7 +411,7 @@ void Terminal::_MoveByBuffer(SelectionDirection direction, COORD& pos) break; case SelectionDirection::Right: case SelectionDirection::Down: - pos = { bufferSize.RightInclusive(), bufferSize.BottomInclusive() }; + pos = { bufferSize.RightInclusive(), _mutableViewport.BottomInclusive() }; break; } } diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index 489892be584..75120af8dc5 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -206,7 +206,7 @@ void Terminal::SelectNewRegion(const COORD coordStart, const COORD coordEnd) realCoordEnd.Y -= gsl::narrow(_VisibleStartIndex()); SetSelectionAnchor(realCoordStart); - SetSelectionEnd(realCoordEnd, winrt::Microsoft::Terminal::Core::SelectionExpansion::Cell); + SetSelectionEnd(realCoordEnd, winrt::Microsoft::Terminal::Core::SelectionExpansion::Char); } const std::wstring_view Terminal::GetConsoleTitle() const noexcept diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h index 79774f9c39e..d05c7f9cb76 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h @@ -1865,7 +1865,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { UpdateSelectionArgs() = default; ACTION_ARG(Core::SelectionDirection, Direction, Core::SelectionDirection::None); - ACTION_ARG(Core::SelectionExpansion, Mode, Core::SelectionExpansion::Cell); + ACTION_ARG(Core::SelectionExpansion, Mode, Core::SelectionExpansion::Char); static constexpr std::string_view DirectionKey{ "direction" }; static constexpr std::string_view ModeKey{ "mode" }; diff --git a/src/cascadia/TerminalSettingsModel/defaults.json b/src/cascadia/TerminalSettingsModel/defaults.json index 339d1aa44ee..3e34f6c2c63 100644 --- a/src/cascadia/TerminalSettingsModel/defaults.json +++ b/src/cascadia/TerminalSettingsModel/defaults.json @@ -381,10 +381,10 @@ { "command": "paste", "keys": "shift+insert" }, // Keyboard Selection - { "command": {"action": "updateSelection", "direction": "left", "mode": "cell" }, "keys": "shift+left" }, - { "command": {"action": "updateSelection", "direction": "right", "mode": "cell" }, "keys": "shift+right" }, - { "command": {"action": "updateSelection", "direction": "up", "mode": "cell" }, "keys": "shift+up" }, - { "command": {"action": "updateSelection", "direction": "down", "mode": "cell" }, "keys": "shift+down" }, + { "command": {"action": "updateSelection", "direction": "left", "mode": "char" }, "keys": "shift+left" }, + { "command": {"action": "updateSelection", "direction": "right", "mode": "char" }, "keys": "shift+right" }, + { "command": {"action": "updateSelection", "direction": "up", "mode": "char" }, "keys": "shift+up" }, + { "command": {"action": "updateSelection", "direction": "down", "mode": "char" }, "keys": "shift+down" }, { "command": {"action": "updateSelection", "direction": "left", "mode": "word" }, "keys": "ctrl+shift+left" }, { "command": {"action": "updateSelection", "direction": "right", "mode": "word" }, "keys": "ctrl+shift+right" }, { "command": {"action": "updateSelection", "direction": "left", "mode": "view" }, "keys": "shift+home" }, diff --git a/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp b/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp index 94b61f0944c..4b125efd86a 100644 --- a/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp +++ b/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp @@ -704,7 +704,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere // ^ ^ // start finish - term.SetSelectionEnd({ 21, 10 }, SelectionExpansion::Cell); + term.SetSelectionEnd({ 21, 10 }, SelectionExpansion::Char); // Validate selection area: "doubleClickMe drag" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 21, 10 })); @@ -825,7 +825,7 @@ namespace TerminalCoreUnitTests // Step 4: Shift+Click at (5,10) { - term.SetSelectionEnd({ 5, 10 }, SelectionExpansion::Cell); + term.SetSelectionEnd({ 5, 10 }, SelectionExpansion::Char); // Validate selection area // NOTE: Pivot should still be (10, 10) @@ -834,7 +834,7 @@ namespace TerminalCoreUnitTests // Step 5: Shift+Click back at (20,10) { - term.SetSelectionEnd({ 20, 10 }, SelectionExpansion::Cell); + term.SetSelectionEnd({ 20, 10 }, SelectionExpansion::Char); // Validate selection area // NOTE: Pivot should still be (10, 10) From a0e4f2dd051f77bcb17b8494af80875107bf31c7 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Wed, 18 Aug 2021 16:21:49 -0700 Subject: [PATCH 03/10] fix schema --- doc/cascadia/profiles.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index b74299ebf5f..715ddb4d991 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -344,7 +344,7 @@ }, "SelectionMode": { "enum": [ - "cell", + "char", "word", "view", "buffer" From 8a646138f4216a4e6ca6d2676645f5c0059df21e Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Mon, 13 Sep 2021 16:27:11 -0700 Subject: [PATCH 04/10] fix build (primarily PublicTerminalCore) --- .../PublicTerminalCore/HwndTerminal.cpp | 4 +- src/cascadia/TerminalControl/ControlCore.cpp | 41 ++++++++++-- src/cascadia/TerminalCore/Terminal.cpp | 2 +- src/cascadia/TerminalCore/Terminal.hpp | 33 +++++++--- .../TerminalCore/TerminalSelection.cpp | 62 +++++++++---------- .../TerminalCore/terminalrenderdata.cpp | 2 +- .../UnitTests_TerminalCore/SelectionTest.cpp | 34 +++++----- 7 files changed, 114 insertions(+), 64 deletions(-) diff --git a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp index c86f5d62100..14df7c79464 100644 --- a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp +++ b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp @@ -549,11 +549,11 @@ try if (multiClickMapper == 3) { - _terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansionMode::Line); + _terminal->MultiClickSelection(cursorPosition / fontSize, InternalSelectionExpansion::Line); } else if (multiClickMapper == 2) { - _terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansionMode::Word); + _terminal->MultiClickSelection(cursorPosition / fontSize, InternalSelectionExpansion::Word); } else { diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index b1e9136a01c..9099a576871 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -33,6 +33,40 @@ constexpr const auto TsfRedrawInterval = std::chrono::milliseconds(100); // The minimum delay between updating the locations of regex patterns constexpr const auto UpdatePatternLocationsInterval = std::chrono::milliseconds(500); +static constexpr InternalSelectionDirection ConvertToInternalSelectionDirection(winrt::Microsoft::Terminal::Core::SelectionDirection dir) +{ + switch (dir) + { + default: + case winrt::Microsoft::Terminal::Core::SelectionDirection::Left: + return InternalSelectionDirection::Left; + case winrt::Microsoft::Terminal::Core::SelectionDirection::Right: + return InternalSelectionDirection::Right; + case winrt::Microsoft::Terminal::Core::SelectionDirection::Up: + return InternalSelectionDirection::Up; + case winrt::Microsoft::Terminal::Core::SelectionDirection::Down: + return InternalSelectionDirection::Down; + } +} + +static constexpr InternalSelectionExpansion ConvertToInternalSelectionExpansion(winrt::Microsoft::Terminal::Core::SelectionExpansion mode) +{ + switch (mode) + { + default: + case winrt::Microsoft::Terminal::Core::SelectionExpansion::Char: + return InternalSelectionExpansion::Char; + case winrt::Microsoft::Terminal::Core::SelectionExpansion::Word: + return InternalSelectionExpansion::Word; + case winrt::Microsoft::Terminal::Core::SelectionExpansion::Line: + return InternalSelectionExpansion::Line; + case winrt::Microsoft::Terminal::Core::SelectionExpansion::Viewport: + return InternalSelectionExpansion::Viewport; + case winrt::Microsoft::Terminal::Core::SelectionExpansion::Buffer: + return InternalSelectionExpansion::Buffer; + } +} + namespace winrt::Microsoft::Terminal::Control::implementation { // Helper static function to ensure that all ambiguous-width glyphs are reported as narrow. @@ -937,7 +971,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation } auto lock = _terminal->LockForWriting(); - _terminal->UpdateSelection(direction, mode); + _terminal->UpdateSelection(ConvertToInternalSelectionDirection(direction), ConvertToInternalSelectionExpansion(mode)); _renderer->TriggerSelection(); return true; } @@ -1470,7 +1504,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation { // If shift is pressed and there is a selection we extend it using // the selection mode (expand the "end" selection point) - _terminal->SetSelectionEnd(terminalPosition, mode); + _terminal->SetSelectionEnd(terminalPosition, ConvertToInternalSelectionExpansion(mode)); selectionNeedsToBeCopied = true; } else if (mode != Core::SelectionExpansion::Char || shiftEnabled) @@ -1478,7 +1512,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // If we are handling a double / triple-click or shift+single click // we establish selection using the selected mode // (expand both "start" and "end" selection points) - _terminal->MultiClickSelection(terminalPosition, mode); + _terminal->MultiClickSelection(terminalPosition, ConvertToInternalSelectionExpansion(mode)); selectionNeedsToBeCopied = true; } @@ -1572,5 +1606,4 @@ namespace winrt::Microsoft::Terminal::Control::implementation return hstring(ss.str()); } - } diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index aba4d68de66..79ad756b59a 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -862,7 +862,7 @@ WORD Terminal::_TakeVirtualKeyFromLastKeyEvent(const WORD scanCode) noexcept return std::unique_lock{ _readWriteLock }; } -Viewport Terminal::_GetMutableViewport() const noexcept +Microsoft::Console::Types::Viewport Terminal::_GetMutableViewport() const noexcept { return _mutableViewport; } diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index e4b242f97c0..3b80fafc652 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -35,6 +35,23 @@ namespace winrt::Microsoft::Terminal::Core namespace Microsoft::Terminal::Core { class Terminal; + + enum class InternalSelectionDirection + { + Left, + Right, + Up, + Down + }; + + enum class InternalSelectionExpansion + { + Char, + Word, + Line, // Mouse selection only! Not a setting! + Viewport, + Buffer + }; } // fwdecl unittest classes @@ -227,11 +244,11 @@ class Microsoft::Terminal::Core::Terminal final : #pragma region TextSelection // These methods are defined in TerminalSelection.cpp - void MultiClickSelection(const COORD viewportPos, winrt::Microsoft::Terminal::Core::SelectionExpansion expansionMode); + void MultiClickSelection(const COORD viewportPos, InternalSelectionExpansion expansionMode); void SetSelectionAnchor(const COORD position); - void SetSelectionEnd(const COORD position, std::optional newExpansionMode = std::nullopt); + void SetSelectionEnd(const COORD position, std::optional newExpansionMode = std::nullopt); void SetBlockSelection(const bool isEnabled) noexcept; - void UpdateSelection(winrt::Microsoft::Terminal::Core::SelectionDirection direction, winrt::Microsoft::Terminal::Core::SelectionExpansion mode); + void UpdateSelection(InternalSelectionDirection direction, InternalSelectionExpansion mode); const TextBuffer::TextAndColor RetrieveSelectedTextFromBuffer(bool trimTrailingWhitespace); #pragma endregion @@ -303,7 +320,7 @@ class Microsoft::Terminal::Core::Terminal final : std::optional _selection; bool _blockSelection; std::wstring _wordDelimiters; - winrt::Microsoft::Terminal::Core::SelectionExpansion _multiClickSelectionMode; + InternalSelectionExpansion _multiClickSelectionMode; #pragma endregion // TODO: These members are not shared by an alt-buffer. They should be @@ -370,10 +387,10 @@ class Microsoft::Terminal::Core::Terminal final : std::tuple _PivotSelection(const COORD targetPos) const; std::pair _ExpandSelectionAnchors(std::pair anchors) const; COORD _ConvertToBufferCell(const COORD viewportPos) const; - void _MoveByChar(winrt::Microsoft::Terminal::Core::SelectionDirection direction, COORD& pos); - void _MoveByWord(winrt::Microsoft::Terminal::Core::SelectionDirection direction, COORD& pos); - void _MoveByViewport(winrt::Microsoft::Terminal::Core::SelectionDirection direction, COORD& pos); - void _MoveByBuffer(winrt::Microsoft::Terminal::Core::SelectionDirection direction, COORD& pos); + void _MoveByChar(InternalSelectionDirection direction, COORD& pos); + void _MoveByWord(InternalSelectionDirection direction, COORD& pos); + void _MoveByViewport(InternalSelectionDirection direction, COORD& pos); + void _MoveByBuffer(InternalSelectionDirection direction, COORD& pos); #pragma endregion Microsoft::Console::VirtualTerminal::SgrStack _sgrStack; diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index 0c15894ea60..f49916a66c9 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -104,7 +104,7 @@ const bool Terminal::IsBlockSelection() const noexcept // Arguments: // - viewportPos: the (x,y) coordinate on the visible viewport // - expansionMode: the SelectionExpansion to dictate the boundaries of the selection anchors -void Terminal::MultiClickSelection(const COORD viewportPos, SelectionExpansion expansionMode) +void Terminal::MultiClickSelection(const COORD viewportPos, InternalSelectionExpansion expansionMode) { // set the selection pivot to expand the selection using SetSelectionEnd() _selection = SelectionAnchors{}; @@ -127,7 +127,7 @@ void Terminal::SetSelectionAnchor(const COORD viewportPos) _selection = SelectionAnchors{}; _selection->pivot = _ConvertToBufferCell(viewportPos); - _multiClickSelectionMode = SelectionExpansion::Char; + _multiClickSelectionMode = InternalSelectionExpansion::Char; SetSelectionEnd(viewportPos); _selection->start = _selection->pivot; @@ -139,7 +139,7 @@ void Terminal::SetSelectionAnchor(const COORD viewportPos) // Arguments: // - viewportPos: the (x,y) coordinate on the visible viewport // - newExpansionMode: overwrites the _multiClickSelectionMode for this function call. Used for ShiftClick -void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional newExpansionMode) +void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional newExpansionMode) { if (!_selection.has_value()) { @@ -216,15 +216,15 @@ std::pair Terminal::_ExpandSelectionAnchors(std::pairGetSize(); switch (_multiClickSelectionMode) { - case SelectionExpansion::Line: + case InternalSelectionExpansion::Line: start = { bufferSize.Left(), start.Y }; end = { bufferSize.RightInclusive(), end.Y }; break; - case SelectionExpansion::Word: + case InternalSelectionExpansion::Word: start = _buffer->GetWordStart(start, _wordDelimiters); end = _buffer->GetWordEnd(end, _wordDelimiters); break; - case SelectionExpansion::Char: + case InternalSelectionExpansion::Char: default: // no expansion is necessary break; @@ -241,7 +241,7 @@ void Terminal::SetBlockSelection(const bool isEnabled) noexcept _blockSelection = isEnabled; } -void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode) +void Terminal::UpdateSelection(InternalSelectionDirection direction, InternalSelectionExpansion mode) { // 1. Figure out which endpoint to update // One of the endpoints is the pivot, signifying that the other endpoint is the one we want to move. @@ -251,16 +251,16 @@ void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion // 2. Perform the movement switch (mode) { - case SelectionExpansion::Char: + case InternalSelectionExpansion::Char: _MoveByChar(direction, targetPos); break; - case SelectionExpansion::Word: + case InternalSelectionExpansion::Word: _MoveByWord(direction, targetPos); break; - case SelectionExpansion::Viewport: + case InternalSelectionExpansion::Viewport: _MoveByViewport(direction, targetPos); break; - case SelectionExpansion::Buffer: + case InternalSelectionExpansion::Buffer: _MoveByBuffer(direction, targetPos); break; } @@ -287,25 +287,25 @@ void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion } } -void Terminal::_MoveByChar(SelectionDirection direction, COORD& pos) +void Terminal::_MoveByChar(InternalSelectionDirection direction, COORD& pos) { switch (direction) { - case SelectionDirection::Left: + case InternalSelectionDirection::Left: _buffer->GetSize().DecrementInBounds(pos); pos = _buffer->GetGlyphStart(pos); break; - case SelectionDirection::Right: + case InternalSelectionDirection::Right: _buffer->GetSize().IncrementInBounds(pos); pos = _buffer->GetGlyphEnd(pos); break; - case SelectionDirection::Up: + case InternalSelectionDirection::Up: { const auto bufferSize{ _buffer->GetSize() }; pos = { pos.X, std::clamp(base::ClampSub(pos.Y, 1).RawValue(), bufferSize.Top(), bufferSize.BottomInclusive()) }; break; } - case SelectionDirection::Down: + case InternalSelectionDirection::Down: { const auto bufferSize{ _buffer->GetSize() }; pos = { pos.X, std::clamp(base::ClampAdd(pos.Y, 1).RawValue(), bufferSize.Top(), bufferSize.BottomInclusive()) }; @@ -314,11 +314,11 @@ void Terminal::_MoveByChar(SelectionDirection direction, COORD& pos) } } -void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos) +void Terminal::_MoveByWord(InternalSelectionDirection direction, COORD& pos) { switch (direction) { - case SelectionDirection::Left: + case InternalSelectionDirection::Left: const auto wordStartPos{ _buffer->GetWordStart(pos, _wordDelimiters) }; if (_buffer->GetSize().CompareInBounds(_selection->pivot, pos) < 0) { @@ -339,7 +339,7 @@ void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos) pos = wordStartPos; } break; - case SelectionDirection::Right: + case InternalSelectionDirection::Right: const auto wordEndPos{ _buffer->GetWordEnd(pos, _wordDelimiters) }; if (_buffer->GetSize().CompareInBounds(pos, _selection->pivot) < 0) { @@ -360,36 +360,36 @@ void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos) pos = wordEndPos; } break; - case SelectionDirection::Up: + case InternalSelectionDirection::Up: _MoveByChar(direction, pos); pos = _buffer->GetWordStart(pos, _wordDelimiters); break; - case SelectionDirection::Down: + case InternalSelectionDirection::Down: _MoveByChar(direction, pos); pos = _buffer->GetWordEnd(pos, _wordDelimiters); break; } } -void Terminal::_MoveByViewport(SelectionDirection direction, COORD& pos) +void Terminal::_MoveByViewport(InternalSelectionDirection direction, COORD& pos) { const auto bufferSize{ _buffer->GetSize() }; switch (direction) { - case SelectionDirection::Left: + case InternalSelectionDirection::Left: pos = { bufferSize.Left(), pos.Y }; break; - case SelectionDirection::Right: + case InternalSelectionDirection::Right: pos = { bufferSize.RightInclusive(), pos.Y }; break; - case SelectionDirection::Up: + case InternalSelectionDirection::Up: { const auto viewportHeight{ _mutableViewport.Height() }; const auto newY{ base::ClampSub(pos.Y, viewportHeight) }; pos = newY < bufferSize.Top() ? bufferSize.Origin() : COORD{ pos.X, newY }; break; } - case SelectionDirection::Down: + case InternalSelectionDirection::Down: { const auto viewportHeight{ _mutableViewport.Height() }; const auto mutableBottom{ _mutableViewport.BottomInclusive() }; @@ -400,17 +400,17 @@ void Terminal::_MoveByViewport(SelectionDirection direction, COORD& pos) } } -void Terminal::_MoveByBuffer(SelectionDirection direction, COORD& pos) +void Terminal::_MoveByBuffer(InternalSelectionDirection direction, COORD& pos) { const auto bufferSize{ _buffer->GetSize() }; switch (direction) { - case SelectionDirection::Left: - case SelectionDirection::Up: + case InternalSelectionDirection::Left: + case InternalSelectionDirection::Up: pos = bufferSize.Origin(); break; - case SelectionDirection::Right: - case SelectionDirection::Down: + case InternalSelectionDirection::Right: + case InternalSelectionDirection::Down: pos = { bufferSize.RightInclusive(), _mutableViewport.BottomInclusive() }; break; } diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index 75120af8dc5..f919d06a17d 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -206,7 +206,7 @@ void Terminal::SelectNewRegion(const COORD coordStart, const COORD coordEnd) realCoordEnd.Y -= gsl::narrow(_VisibleStartIndex()); SetSelectionAnchor(realCoordStart); - SetSelectionEnd(realCoordEnd, winrt::Microsoft::Terminal::Core::SelectionExpansion::Char); + SetSelectionEnd(realCoordEnd, InternalSelectionExpansion::Char); } const std::wstring_view Terminal::GetConsoleTitle() const noexcept diff --git a/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp b/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp index 4b125efd86a..8929eb7d9ba 100644 --- a/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp +++ b/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp @@ -130,7 +130,7 @@ namespace TerminalCoreUnitTests DummyRenderTarget emptyRT; term.Create({ 10, 10 }, scrollback, emptyRT); - term.MultiClickSelection(maxCoord, SelectionExpansion::Word); + term.MultiClickSelection(maxCoord, InternalSelectionExpansion::Word); ValidateSingleRowSelection(term, expected); }; @@ -142,7 +142,7 @@ namespace TerminalCoreUnitTests DummyRenderTarget emptyRT; term.Create({ 10, 10 }, scrollback, emptyRT); - term.MultiClickSelection(maxCoord, SelectionExpansion::Line); + term.MultiClickSelection(maxCoord, InternalSelectionExpansion::Line); ValidateSingleRowSelection(term, expected); }; @@ -501,7 +501,7 @@ namespace TerminalCoreUnitTests // Simulate double click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, SelectionExpansion::Word); + term.MultiClickSelection(clickPos, InternalSelectionExpansion::Word); // Validate selection area ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, (4 + gsl::narrow(text.size()) - 1), 10 })); @@ -519,7 +519,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, SelectionExpansion::Word); + term.MultiClickSelection(clickPos, InternalSelectionExpansion::Word); // Simulate renderer calling TriggerSelection and acquiring selection area auto selectionRects = term.GetSelectionRects(); @@ -546,7 +546,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (15,10) // this is over the '>' char auto clickPos = COORD{ 15, 10 }; - term.MultiClickSelection(clickPos, SelectionExpansion::Word); + term.MultiClickSelection(clickPos, InternalSelectionExpansion::Word); // ---Validate selection area--- // "Terminal" is in class 2 @@ -572,7 +572,7 @@ namespace TerminalCoreUnitTests term.Write(text); // Simulate double click at (x,y) = (5,10) - term.MultiClickSelection({ 5, 10 }, SelectionExpansion::Word); + term.MultiClickSelection({ 5, 10 }, InternalSelectionExpansion::Word); // Simulate move to (x,y) = (21,10) // @@ -601,7 +601,7 @@ namespace TerminalCoreUnitTests term.Write(text); // Simulate double click at (x,y) = (21,10) - term.MultiClickSelection({ 21, 10 }, SelectionExpansion::Word); + term.MultiClickSelection({ 21, 10 }, InternalSelectionExpansion::Word); // Simulate move to (x,y) = (5,10) // @@ -622,7 +622,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, SelectionExpansion::Line); + term.MultiClickSelection(clickPos, InternalSelectionExpansion::Line); // Validate selection area ValidateSingleRowSelection(term, SMALL_RECT({ 0, 10, 99, 10 })); @@ -636,7 +636,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, SelectionExpansion::Line); + term.MultiClickSelection(clickPos, InternalSelectionExpansion::Line); // Simulate move to (x,y) = (7,10) term.SetSelectionEnd({ 7, 10 }); @@ -653,7 +653,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, SelectionExpansion::Line); + term.MultiClickSelection(clickPos, InternalSelectionExpansion::Line); // Simulate move to (x,y) = (5,11) term.SetSelectionEnd({ 5, 11 }); @@ -691,7 +691,7 @@ namespace TerminalCoreUnitTests // Step 1: Create a selection on "doubleClickMe" { // Simulate double click at (x,y) = (5,10) - term.MultiClickSelection({ 5, 10 }, SelectionExpansion::Word); + term.MultiClickSelection({ 5, 10 }, InternalSelectionExpansion::Word); // Validate selection area: "doubleClickMe" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 16, 10 })); @@ -704,7 +704,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere // ^ ^ // start finish - term.SetSelectionEnd({ 21, 10 }, SelectionExpansion::Char); + term.SetSelectionEnd({ 21, 10 }, InternalSelectionExpansion::Char); // Validate selection area: "doubleClickMe drag" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 21, 10 })); @@ -717,7 +717,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere // ^ ^ ^ // start click finish - term.SetSelectionEnd({ 21, 10 }, SelectionExpansion::Word); + term.SetSelectionEnd({ 21, 10 }, InternalSelectionExpansion::Word); // Validate selection area: "doubleClickMe dragThroughHere" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 32, 10 })); @@ -730,7 +730,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere | // ^ ^ ^ // start click finish (boundary) - term.SetSelectionEnd({ 21, 10 }, SelectionExpansion::Line); + term.SetSelectionEnd({ 21, 10 }, InternalSelectionExpansion::Line); // Validate selection area: "doubleClickMe dragThroughHere..." selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 99, 10 })); @@ -743,7 +743,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere // ^ ^ ^ // start click finish - term.SetSelectionEnd({ 21, 10 }, SelectionExpansion::Word); + term.SetSelectionEnd({ 21, 10 }, InternalSelectionExpansion::Word); // Validate selection area: "doubleClickMe dragThroughHere" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 32, 10 })); @@ -825,7 +825,7 @@ namespace TerminalCoreUnitTests // Step 4: Shift+Click at (5,10) { - term.SetSelectionEnd({ 5, 10 }, SelectionExpansion::Char); + term.SetSelectionEnd({ 5, 10 }, InternalSelectionExpansion::Char); // Validate selection area // NOTE: Pivot should still be (10, 10) @@ -834,7 +834,7 @@ namespace TerminalCoreUnitTests // Step 5: Shift+Click back at (20,10) { - term.SetSelectionEnd({ 20, 10 }, SelectionExpansion::Char); + term.SetSelectionEnd({ 20, 10 }, InternalSelectionExpansion::Char); // Validate selection area // NOTE: Pivot should still be (10, 10) From 724cd2c2ca7e09c9559532441f37901dcc27fc06 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Mon, 13 Sep 2021 17:06:18 -0700 Subject: [PATCH 05/10] fix build --- .../TerminalSettingsSerializationHelpers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h index 882d86ee22c..db96440a842 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h @@ -526,7 +526,7 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Core::SelectionDirection) JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Core::SelectionExpansion) { static constexpr std::array mappings = { - pair_type{ "cell", ValueType::Cell }, + pair_type{ "char", ValueType::Char }, pair_type{ "word", ValueType::Word }, pair_type{ "view", ValueType::Viewport }, pair_type{ "buffer", ValueType::Buffer } From bf0cf5f0d25da02da329069a4fc9f4111fd8b641 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Tue, 14 Sep 2021 09:49:00 -0700 Subject: [PATCH 06/10] add TODO GH behind for duplicate enum --- src/cascadia/TerminalCore/Terminal.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 3b80fafc652..e066da3da88 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -36,6 +36,9 @@ namespace Microsoft::Terminal::Core { class Terminal; + // TODO GH#6999: We need to convert winrt::Microsoft::Terminal::Core::SelectionDirection/Expansion + // into an equivalent enum class because PublicTerminalCore doesn't consume winrt. Once we introduce + // an interactivity layer, we'll be able to remove this duplicate enum and directly use the winrt enums. enum class InternalSelectionDirection { Left, From b13b8a78964f43d45c34e5a504ac0f1e003fc710 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Tue, 14 Sep 2021 12:39:17 -0700 Subject: [PATCH 07/10] remove unnecessary explicit namespace --- src/cascadia/TerminalCore/Terminal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 79ad756b59a..aba4d68de66 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -862,7 +862,7 @@ WORD Terminal::_TakeVirtualKeyFromLastKeyEvent(const WORD scanCode) noexcept return std::unique_lock{ _readWriteLock }; } -Microsoft::Console::Types::Viewport Terminal::_GetMutableViewport() const noexcept +Viewport Terminal::_GetMutableViewport() const noexcept { return _mutableViewport; } From 118d1cdc023f33a06fb88e160d8f4defb5b14e39 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Thu, 16 Sep 2021 19:58:42 -0700 Subject: [PATCH 08/10] remove configurability --- doc/cascadia/profiles.schema.json | 44 +----- .../TerminalApp/AppActionHandlers.cpp | 15 -- src/cascadia/TerminalControl/ControlCore.cpp | 131 +++++++++++------- src/cascadia/TerminalControl/ControlCore.h | 1 - src/cascadia/TerminalControl/ControlCore.idl | 1 - src/cascadia/TerminalControl/TermControl.cpp | 5 - src/cascadia/TerminalControl/TermControl.h | 1 - src/cascadia/TerminalControl/TermControl.idl | 1 - src/cascadia/TerminalCore/ICoreSettings.idl | 18 --- src/cascadia/TerminalCore/Terminal.hpp | 52 ++++--- .../TerminalCore/TerminalSelection.cpp | 62 ++++----- .../TerminalCore/terminalrenderdata.cpp | 2 +- .../TerminalSettingsModel/ActionAndArgs.cpp | 1 - .../TerminalSettingsModel/ActionArgs.cpp | 6 - .../TerminalSettingsModel/ActionArgs.h | 62 --------- .../TerminalSettingsModel/ActionArgs.idl | 6 - .../AllShortcutActions.h | 6 +- .../TerminalSettingsSerializationHelpers.h | 20 --- .../TerminalSettingsModel/defaults.json | 14 -- src/types/UiaTextRangeBase.cpp | 2 +- 20 files changed, 140 insertions(+), 310 deletions(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index 715ddb4d991..6a2c9147932 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -304,7 +304,6 @@ "toggleSplitOrientation", "toggleReadOnlyMode", "toggleShaderEffects", - "updateSelection", "wt", "quit", "unbound" @@ -333,24 +332,6 @@ ], "type": "string" }, - "SelectionDirection": { - "enum": [ - "left", - "right", - "up", - "down" - ], - "type": "string" - }, - "SelectionMode": { - "enum": [ - "char", - "word", - "view", - "buffer" - ], - "type": "string" - }, "MoveTabDirection": { "enum": [ "forward", @@ -605,28 +586,6 @@ ], "required": [ "direction" ] }, - "UpdateSelectionAction": { - "description": "Arguments corresponding to a Update Selection Action", - "allOf": [ - { "$ref": "#/definitions/ShortcutAction" }, - { - "properties": { - "action": { "type": "string", "pattern": "updateSelection" }, - "direction": { - "$ref": "#/definitions/SelectionDirection", - "default": "left", - "description": "The direction to move the selection endpoint in." - }, - "mode": { - "$ref": "#/definitions/SelectionMode", - "default": "cell", - "description": "The expansion mode to move the selection endpoint by." - } - } - } - ], - "required": [ "direction" ] - }, "ResizePaneAction": { "description": "Arguments corresponding to a Resize Pane Action", "allOf": [ @@ -888,7 +847,7 @@ } ], "required": [ "actions" ] - }, + }, "CommandPaletteAction": { "description": "Arguments for a commandPalette action", "allOf": [ @@ -1107,7 +1066,6 @@ { "$ref": "#/definitions/FocusPaneAction" }, { "$ref": "#/definitions/GlobalSummonAction" }, { "$ref": "#/definitions/QuakeModeAction" }, - { "$ref": "#/definitions/UpdateSelectionAction" }, { "type": "null" } ] }, diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 6dd3c8768ff..1ef4c0c8ab4 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -921,19 +921,4 @@ namespace winrt::TerminalApp::implementation } } } - - void TerminalPage::_HandleUpdateSelection(const IInspectable& /*sender*/, - const ActionEventArgs& args) - { - if (args) - { - if (const auto& realArgs = args.ActionArgs().try_as()) - { - if (const auto termControl{ _GetActiveControl() }) - { - args.Handled(termControl.UpdateSelection(realArgs.Direction(), realArgs.Mode())); - } - } - } - } } diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 9099a576871..ca0dd49d661 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -33,38 +33,72 @@ constexpr const auto TsfRedrawInterval = std::chrono::milliseconds(100); // The minimum delay between updating the locations of regex patterns constexpr const auto UpdatePatternLocationsInterval = std::chrono::milliseconds(500); -static constexpr InternalSelectionDirection ConvertToInternalSelectionDirection(winrt::Microsoft::Terminal::Core::SelectionDirection dir) +static constexpr std::optional ConvertVKeyToSelectionDirection(WORD vkey) { - switch (dir) - { + switch (vkey) + { + case VK_LEFT: + case VK_HOME: + return Terminal::SelectionDirection::Left; + case VK_RIGHT: + case VK_END: + return Terminal::SelectionDirection::Right; + case VK_UP: + case VK_PRIOR: + return Terminal::SelectionDirection::Up; + case VK_DOWN: + case VK_NEXT: + return Terminal::SelectionDirection::Down; default: - case winrt::Microsoft::Terminal::Core::SelectionDirection::Left: - return InternalSelectionDirection::Left; - case winrt::Microsoft::Terminal::Core::SelectionDirection::Right: - return InternalSelectionDirection::Right; - case winrt::Microsoft::Terminal::Core::SelectionDirection::Up: - return InternalSelectionDirection::Up; - case winrt::Microsoft::Terminal::Core::SelectionDirection::Down: - return InternalSelectionDirection::Down; + return std::nullopt; } } -static constexpr InternalSelectionExpansion ConvertToInternalSelectionExpansion(winrt::Microsoft::Terminal::Core::SelectionExpansion mode) +static constexpr std::optional> ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) { - switch (mode) + if (mods.IsShiftPressed() && !mods.IsAltPressed()) { - default: - case winrt::Microsoft::Terminal::Core::SelectionExpansion::Char: - return InternalSelectionExpansion::Char; - case winrt::Microsoft::Terminal::Core::SelectionExpansion::Word: - return InternalSelectionExpansion::Word; - case winrt::Microsoft::Terminal::Core::SelectionExpansion::Line: - return InternalSelectionExpansion::Line; - case winrt::Microsoft::Terminal::Core::SelectionExpansion::Viewport: - return InternalSelectionExpansion::Viewport; - case winrt::Microsoft::Terminal::Core::SelectionExpansion::Buffer: - return InternalSelectionExpansion::Buffer; + if (const auto dir{ ConvertVKeyToSelectionDirection(vkey) }) + { + if (mods.IsCtrlPressed()) + { + switch (vkey) + { + case VK_LEFT: + case VK_RIGHT: + // Move by word + return std::make_tuple(*dir, Terminal::SelectionExpansion::Word); + case VK_HOME: + case VK_END: + // Move by buffer + return std::make_tuple(*dir, Terminal::SelectionExpansion::Buffer); + default: + __fallthrough; + } + } + else + { + switch (vkey) + { + case VK_HOME: + case VK_END: + case VK_PRIOR: + case VK_NEXT: + // Move by viewport + return std::make_tuple(*dir, Terminal::SelectionExpansion::Viewport); + case VK_LEFT: + case VK_RIGHT: + case VK_UP: + case VK_DOWN: + // Move by character + return std::make_tuple(*dir, Terminal::SelectionExpansion::Char); + default: + __fallthrough; + } + } + } } + return std::nullopt; } namespace winrt::Microsoft::Terminal::Control::implementation @@ -393,21 +427,28 @@ namespace winrt::Microsoft::Terminal::Control::implementation const ControlKeyStates modifiers, const bool keyDown) { - // When there is a selection active, escape should clear it and NOT flow through - // to the terminal. With any other keypress, it should clear the selection AND - // flow through to the terminal. + // Update the selection, if it's present // GH#6423 - don't dismiss selection if the key that was pressed was a // modifier key. We'll wait for a real keystroke to dismiss the // GH #7395 - don't dismiss selection when taking PrintScreen // selection. - // GH#8522, GH#3758 - Only dismiss the selection on key _down_. If we - // dismiss on key up, then there's chance that we'll immediately dismiss + // GH#8522, GH#3758 - Only modify the selection on key _down_. If we + // modify on key up, then there's chance that we'll immediately dismiss // a selection created by an action bound to a keydown. if (HasSelection() && !KeyEvent::IsModifierKey(vkey) && vkey != VK_SNAPSHOT && keyDown) { + // try to update the selection + if (const auto updateSlnParams{ ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) }) + { + auto lock = _terminal->LockForWriting(); + _terminal->UpdateSelection(std::get<0>(*updateSlnParams), std::get<1>(*updateSlnParams)); + _renderer->TriggerSelection(); + return true; + } + // GH#8791 - don't dismiss selection if Windows key was also pressed as a key-combination. if (!modifiers.IsWinPressed()) { @@ -415,6 +456,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation _renderer->TriggerSelection(); } + // When there is a selection active, escape should clear it and NOT flow through + // to the terminal. With any other keypress, it should clear the selection AND + // flow through to the terminal. if (vkey == VK_ESCAPE) { return true; @@ -961,21 +1005,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation _renderer->TriggerSelection(); } - bool ControlCore::UpdateSelection(Core::SelectionDirection direction, Core::SelectionExpansion mode) - { - // - SelectionDirection cannot be none - // - A selection must be active for us to update it - if (direction == Core::SelectionDirection::None || !HasSelection()) - { - return false; - } - - auto lock = _terminal->LockForWriting(); - _terminal->UpdateSelection(ConvertToInternalSelectionDirection(direction), ConvertToInternalSelectionExpansion(mode)); - _renderer->TriggerSelection(); - return true; - } - // Called when the Terminal wants to set something to the clipboard, i.e. // when an OSC 52 is emitted. void ControlCore::_terminalCopyToClipboard(std::wstring_view wstr) @@ -1471,18 +1500,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation // handle ALT key _terminal->SetBlockSelection(altEnabled); - Core::SelectionExpansion mode = Core::SelectionExpansion::Char; + ::Terminal::SelectionExpansion mode = ::Terminal::SelectionExpansion::Char; if (numberOfClicks == 1) { - mode = Core::SelectionExpansion::Char; + mode = ::Terminal::SelectionExpansion::Char; } else if (numberOfClicks == 2) { - mode = Core::SelectionExpansion::Word; + mode = ::Terminal::SelectionExpansion::Word; } else if (numberOfClicks == 3) { - mode = Core::SelectionExpansion::Line; + mode = ::Terminal::SelectionExpansion::Line; } // Update the selection appropriately @@ -1504,15 +1533,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation { // If shift is pressed and there is a selection we extend it using // the selection mode (expand the "end" selection point) - _terminal->SetSelectionEnd(terminalPosition, ConvertToInternalSelectionExpansion(mode)); + _terminal->SetSelectionEnd(terminalPosition, mode); selectionNeedsToBeCopied = true; } - else if (mode != Core::SelectionExpansion::Char || shiftEnabled) + else if (mode != ::Terminal::SelectionExpansion::Char || shiftEnabled) { // If we are handling a double / triple-click or shift+single click // we establish selection using the selected mode // (expand both "start" and "end" selection points) - _terminal->MultiClickSelection(terminalPosition, ConvertToInternalSelectionExpansion(mode)); + _terminal->MultiClickSelection(terminalPosition, mode); selectionNeedsToBeCopied = true; } diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index 3eedcad93f8..a04032ef78e 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -130,7 +130,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation Windows::Foundation::Collections::IVector SelectedText(bool trimTrailingWhitespace) const; void SetSelectionAnchor(til::point const& position); void SetEndSelectionPoint(til::point const& position); - bool UpdateSelection(Core::SelectionDirection direction, Core::SelectionExpansion mode); void Search(const winrt::hstring& text, const bool goForward, diff --git a/src/cascadia/TerminalControl/ControlCore.idl b/src/cascadia/TerminalControl/ControlCore.idl index 467e30bbb76..84cb83e80f2 100644 --- a/src/cascadia/TerminalControl/ControlCore.idl +++ b/src/cascadia/TerminalControl/ControlCore.idl @@ -80,7 +80,6 @@ namespace Microsoft.Terminal.Control Boolean HasSelection { get; }; IVector SelectedText(Boolean trimTrailingWhitespace); - Boolean UpdateSelection(Microsoft.Terminal.Core.SelectionDirection direction, Microsoft.Terminal.Core.SelectionExpansion mode); String HoveredUriText { get; }; Windows.Foundation.IReference HoveredCell { get; }; diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 7686cd909d9..115f9afc580 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -2577,9 +2577,4 @@ namespace winrt::Microsoft::Terminal::Control::implementation { return _core.ReadEntireBuffer(); } - - bool TermControl::UpdateSelection(Core::SelectionDirection direction, Core::SelectionExpansion mode) - { - return _core.UpdateSelection(direction, mode); - } } diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index fbd573bae60..9d0f22e339f 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -32,7 +32,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation hstring GetProfileName() const; - bool UpdateSelection(Core::SelectionDirection direction, Core::SelectionExpansion mode); bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference& formats); void PasteTextFromClipboard(); void Close(); diff --git a/src/cascadia/TerminalControl/TermControl.idl b/src/cascadia/TerminalControl/TermControl.idl index 9b5b03d1a0f..26db0862cac 100644 --- a/src/cascadia/TerminalControl/TermControl.idl +++ b/src/cascadia/TerminalControl/TermControl.idl @@ -45,7 +45,6 @@ namespace Microsoft.Terminal.Control // We expose this and ConnectionState here so that it might eventually be data bound. event Windows.Foundation.TypedEventHandler ConnectionStateChanged; - Boolean UpdateSelection(Microsoft.Terminal.Core.SelectionDirection direction, Microsoft.Terminal.Core.SelectionExpansion mode); Boolean CopySelectionToClipboard(Boolean singleLine, Windows.Foundation.IReference formats); void PasteTextFromClipboard(); void ClearBuffer(ClearBufferType clearType); diff --git a/src/cascadia/TerminalCore/ICoreSettings.idl b/src/cascadia/TerminalCore/ICoreSettings.idl index e03569414f2..dd0b4939b3b 100644 --- a/src/cascadia/TerminalCore/ICoreSettings.idl +++ b/src/cascadia/TerminalCore/ICoreSettings.idl @@ -5,24 +5,6 @@ import "..\ICoreAppearance.idl"; namespace Microsoft.Terminal.Core { - enum SelectionDirection - { - None = 0, - Left, - Right, - Up, - Down, - }; - - enum SelectionExpansion - { - Char, - Word, - Line, // Mouse selection only! Not a setting! - Viewport, - Buffer - }; - interface ICoreSettings requires ICoreAppearance { // TODO:MSFT:20642297 - define a sentinel for Infinite Scrollback diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index e066da3da88..bc51241b9c9 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -35,26 +35,6 @@ namespace winrt::Microsoft::Terminal::Core namespace Microsoft::Terminal::Core { class Terminal; - - // TODO GH#6999: We need to convert winrt::Microsoft::Terminal::Core::SelectionDirection/Expansion - // into an equivalent enum class because PublicTerminalCore doesn't consume winrt. Once we introduce - // an interactivity layer, we'll be able to remove this duplicate enum and directly use the winrt enums. - enum class InternalSelectionDirection - { - Left, - Right, - Up, - Down - }; - - enum class InternalSelectionExpansion - { - Char, - Word, - Line, // Mouse selection only! Not a setting! - Viewport, - Buffer - }; } // fwdecl unittest classes @@ -247,11 +227,27 @@ class Microsoft::Terminal::Core::Terminal final : #pragma region TextSelection // These methods are defined in TerminalSelection.cpp - void MultiClickSelection(const COORD viewportPos, InternalSelectionExpansion expansionMode); + enum class SelectionDirection + { + Left, + Right, + Up, + Down + }; + + enum class SelectionExpansion + { + Char, + Word, + Line, // Mouse selection only! Not a setting! + Viewport, + Buffer + }; + void MultiClickSelection(const COORD viewportPos, SelectionExpansion expansionMode); void SetSelectionAnchor(const COORD position); - void SetSelectionEnd(const COORD position, std::optional newExpansionMode = std::nullopt); + void SetSelectionEnd(const COORD position, std::optional newExpansionMode = std::nullopt); void SetBlockSelection(const bool isEnabled) noexcept; - void UpdateSelection(InternalSelectionDirection direction, InternalSelectionExpansion mode); + void UpdateSelection(SelectionDirection direction, SelectionExpansion mode); const TextBuffer::TextAndColor RetrieveSelectedTextFromBuffer(bool trimTrailingWhitespace); #pragma endregion @@ -323,7 +319,7 @@ class Microsoft::Terminal::Core::Terminal final : std::optional _selection; bool _blockSelection; std::wstring _wordDelimiters; - InternalSelectionExpansion _multiClickSelectionMode; + SelectionExpansion _multiClickSelectionMode; #pragma endregion // TODO: These members are not shared by an alt-buffer. They should be @@ -390,10 +386,10 @@ class Microsoft::Terminal::Core::Terminal final : std::tuple _PivotSelection(const COORD targetPos) const; std::pair _ExpandSelectionAnchors(std::pair anchors) const; COORD _ConvertToBufferCell(const COORD viewportPos) const; - void _MoveByChar(InternalSelectionDirection direction, COORD& pos); - void _MoveByWord(InternalSelectionDirection direction, COORD& pos); - void _MoveByViewport(InternalSelectionDirection direction, COORD& pos); - void _MoveByBuffer(InternalSelectionDirection direction, COORD& pos); + void _MoveByChar(SelectionDirection direction, COORD& pos); + void _MoveByWord(SelectionDirection direction, COORD& pos); + void _MoveByViewport(SelectionDirection direction, COORD& pos); + void _MoveByBuffer(SelectionDirection direction, COORD& pos); #pragma endregion Microsoft::Console::VirtualTerminal::SgrStack _sgrStack; diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index f49916a66c9..0c15894ea60 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -104,7 +104,7 @@ const bool Terminal::IsBlockSelection() const noexcept // Arguments: // - viewportPos: the (x,y) coordinate on the visible viewport // - expansionMode: the SelectionExpansion to dictate the boundaries of the selection anchors -void Terminal::MultiClickSelection(const COORD viewportPos, InternalSelectionExpansion expansionMode) +void Terminal::MultiClickSelection(const COORD viewportPos, SelectionExpansion expansionMode) { // set the selection pivot to expand the selection using SetSelectionEnd() _selection = SelectionAnchors{}; @@ -127,7 +127,7 @@ void Terminal::SetSelectionAnchor(const COORD viewportPos) _selection = SelectionAnchors{}; _selection->pivot = _ConvertToBufferCell(viewportPos); - _multiClickSelectionMode = InternalSelectionExpansion::Char; + _multiClickSelectionMode = SelectionExpansion::Char; SetSelectionEnd(viewportPos); _selection->start = _selection->pivot; @@ -139,7 +139,7 @@ void Terminal::SetSelectionAnchor(const COORD viewportPos) // Arguments: // - viewportPos: the (x,y) coordinate on the visible viewport // - newExpansionMode: overwrites the _multiClickSelectionMode for this function call. Used for ShiftClick -void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional newExpansionMode) +void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional newExpansionMode) { if (!_selection.has_value()) { @@ -216,15 +216,15 @@ std::pair Terminal::_ExpandSelectionAnchors(std::pairGetSize(); switch (_multiClickSelectionMode) { - case InternalSelectionExpansion::Line: + case SelectionExpansion::Line: start = { bufferSize.Left(), start.Y }; end = { bufferSize.RightInclusive(), end.Y }; break; - case InternalSelectionExpansion::Word: + case SelectionExpansion::Word: start = _buffer->GetWordStart(start, _wordDelimiters); end = _buffer->GetWordEnd(end, _wordDelimiters); break; - case InternalSelectionExpansion::Char: + case SelectionExpansion::Char: default: // no expansion is necessary break; @@ -241,7 +241,7 @@ void Terminal::SetBlockSelection(const bool isEnabled) noexcept _blockSelection = isEnabled; } -void Terminal::UpdateSelection(InternalSelectionDirection direction, InternalSelectionExpansion mode) +void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode) { // 1. Figure out which endpoint to update // One of the endpoints is the pivot, signifying that the other endpoint is the one we want to move. @@ -251,16 +251,16 @@ void Terminal::UpdateSelection(InternalSelectionDirection direction, InternalSel // 2. Perform the movement switch (mode) { - case InternalSelectionExpansion::Char: + case SelectionExpansion::Char: _MoveByChar(direction, targetPos); break; - case InternalSelectionExpansion::Word: + case SelectionExpansion::Word: _MoveByWord(direction, targetPos); break; - case InternalSelectionExpansion::Viewport: + case SelectionExpansion::Viewport: _MoveByViewport(direction, targetPos); break; - case InternalSelectionExpansion::Buffer: + case SelectionExpansion::Buffer: _MoveByBuffer(direction, targetPos); break; } @@ -287,25 +287,25 @@ void Terminal::UpdateSelection(InternalSelectionDirection direction, InternalSel } } -void Terminal::_MoveByChar(InternalSelectionDirection direction, COORD& pos) +void Terminal::_MoveByChar(SelectionDirection direction, COORD& pos) { switch (direction) { - case InternalSelectionDirection::Left: + case SelectionDirection::Left: _buffer->GetSize().DecrementInBounds(pos); pos = _buffer->GetGlyphStart(pos); break; - case InternalSelectionDirection::Right: + case SelectionDirection::Right: _buffer->GetSize().IncrementInBounds(pos); pos = _buffer->GetGlyphEnd(pos); break; - case InternalSelectionDirection::Up: + case SelectionDirection::Up: { const auto bufferSize{ _buffer->GetSize() }; pos = { pos.X, std::clamp(base::ClampSub(pos.Y, 1).RawValue(), bufferSize.Top(), bufferSize.BottomInclusive()) }; break; } - case InternalSelectionDirection::Down: + case SelectionDirection::Down: { const auto bufferSize{ _buffer->GetSize() }; pos = { pos.X, std::clamp(base::ClampAdd(pos.Y, 1).RawValue(), bufferSize.Top(), bufferSize.BottomInclusive()) }; @@ -314,11 +314,11 @@ void Terminal::_MoveByChar(InternalSelectionDirection direction, COORD& pos) } } -void Terminal::_MoveByWord(InternalSelectionDirection direction, COORD& pos) +void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos) { switch (direction) { - case InternalSelectionDirection::Left: + case SelectionDirection::Left: const auto wordStartPos{ _buffer->GetWordStart(pos, _wordDelimiters) }; if (_buffer->GetSize().CompareInBounds(_selection->pivot, pos) < 0) { @@ -339,7 +339,7 @@ void Terminal::_MoveByWord(InternalSelectionDirection direction, COORD& pos) pos = wordStartPos; } break; - case InternalSelectionDirection::Right: + case SelectionDirection::Right: const auto wordEndPos{ _buffer->GetWordEnd(pos, _wordDelimiters) }; if (_buffer->GetSize().CompareInBounds(pos, _selection->pivot) < 0) { @@ -360,36 +360,36 @@ void Terminal::_MoveByWord(InternalSelectionDirection direction, COORD& pos) pos = wordEndPos; } break; - case InternalSelectionDirection::Up: + case SelectionDirection::Up: _MoveByChar(direction, pos); pos = _buffer->GetWordStart(pos, _wordDelimiters); break; - case InternalSelectionDirection::Down: + case SelectionDirection::Down: _MoveByChar(direction, pos); pos = _buffer->GetWordEnd(pos, _wordDelimiters); break; } } -void Terminal::_MoveByViewport(InternalSelectionDirection direction, COORD& pos) +void Terminal::_MoveByViewport(SelectionDirection direction, COORD& pos) { const auto bufferSize{ _buffer->GetSize() }; switch (direction) { - case InternalSelectionDirection::Left: + case SelectionDirection::Left: pos = { bufferSize.Left(), pos.Y }; break; - case InternalSelectionDirection::Right: + case SelectionDirection::Right: pos = { bufferSize.RightInclusive(), pos.Y }; break; - case InternalSelectionDirection::Up: + case SelectionDirection::Up: { const auto viewportHeight{ _mutableViewport.Height() }; const auto newY{ base::ClampSub(pos.Y, viewportHeight) }; pos = newY < bufferSize.Top() ? bufferSize.Origin() : COORD{ pos.X, newY }; break; } - case InternalSelectionDirection::Down: + case SelectionDirection::Down: { const auto viewportHeight{ _mutableViewport.Height() }; const auto mutableBottom{ _mutableViewport.BottomInclusive() }; @@ -400,17 +400,17 @@ void Terminal::_MoveByViewport(InternalSelectionDirection direction, COORD& pos) } } -void Terminal::_MoveByBuffer(InternalSelectionDirection direction, COORD& pos) +void Terminal::_MoveByBuffer(SelectionDirection direction, COORD& pos) { const auto bufferSize{ _buffer->GetSize() }; switch (direction) { - case InternalSelectionDirection::Left: - case InternalSelectionDirection::Up: + case SelectionDirection::Left: + case SelectionDirection::Up: pos = bufferSize.Origin(); break; - case InternalSelectionDirection::Right: - case InternalSelectionDirection::Down: + case SelectionDirection::Right: + case SelectionDirection::Down: pos = { bufferSize.RightInclusive(), _mutableViewport.BottomInclusive() }; break; } diff --git a/src/cascadia/TerminalCore/terminalrenderdata.cpp b/src/cascadia/TerminalCore/terminalrenderdata.cpp index f919d06a17d..6ccb5791d22 100644 --- a/src/cascadia/TerminalCore/terminalrenderdata.cpp +++ b/src/cascadia/TerminalCore/terminalrenderdata.cpp @@ -206,7 +206,7 @@ void Terminal::SelectNewRegion(const COORD coordStart, const COORD coordEnd) realCoordEnd.Y -= gsl::narrow(_VisibleStartIndex()); SetSelectionAnchor(realCoordStart); - SetSelectionEnd(realCoordEnd, InternalSelectionExpansion::Char); + SetSelectionEnd(realCoordEnd, SelectionExpansion::Char); } const std::wstring_view Terminal::GetConsoleTitle() const noexcept diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp index dbdcb17466a..2ae6bb6da3b 100644 --- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp @@ -69,7 +69,6 @@ static constexpr std::string_view OpenSystemMenuKey{ "openSystemMenu" }; static constexpr std::string_view ClearBufferKey{ "clearBuffer" }; static constexpr std::string_view MultipleActionsKey{ "multipleActions" }; static constexpr std::string_view QuitKey{ "quit" }; -static constexpr std::string_view UpdateSelectionKey{ "updateSelection" }; static constexpr std::string_view ActionKey{ "action" }; diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp index cc052f90157..dd30f354726 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp @@ -36,7 +36,6 @@ #include "FocusPaneArgs.g.cpp" #include "ClearBufferArgs.g.cpp" #include "MultipleActionsArgs.g.cpp" -#include "UpdateSelectionArgs.g.cpp" #include @@ -719,9 +718,4 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { return L""; } - - winrt::hstring UpdateSelectionArgs::GenerateName() const - { - return L""; - } } diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h index d05c7f9cb76..94f7cebea7d 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h @@ -38,7 +38,6 @@ #include "FocusPaneArgs.g.h" #include "ClearBufferArgs.g.h" #include "MultipleActionsArgs.g.h" -#include "UpdateSelectionArgs.g.h" #include "../../cascadia/inc/cppwinrt_utils.h" #include "JsonUtils.h" @@ -1860,67 +1859,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(_Actions); } }; - - struct UpdateSelectionArgs : public UpdateSelectionArgsT - { - UpdateSelectionArgs() = default; - ACTION_ARG(Core::SelectionDirection, Direction, Core::SelectionDirection::None); - ACTION_ARG(Core::SelectionExpansion, Mode, Core::SelectionExpansion::Char); - static constexpr std::string_view DirectionKey{ "direction" }; - static constexpr std::string_view ModeKey{ "mode" }; - - public: - hstring GenerateName() const; - - bool Equals(const IActionArgs& other) - { - auto otherAsUs = other.try_as(); - if (otherAsUs) - { - return otherAsUs->_Direction == _Direction && otherAsUs->_Mode == _Mode; - } - 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(); - JsonUtils::GetValueForKey(json, DirectionKey, args->_Direction); - JsonUtils::GetValueForKey(json, ModeKey, args->_Mode); - if (args->Direction() == Core::SelectionDirection::None) - { - return { nullptr, { SettingsLoadWarnings::MissingRequiredParameter } }; - } - else - { - return { *args, {} }; - } - } - static Json::Value ToJson(const IActionArgs& val) - { - if (!val) - { - return {}; - } - Json::Value json{ Json::ValueType::objectValue }; - const auto args{ get_self(val) }; - JsonUtils::SetValueForKey(json, DirectionKey, args->_Direction); - JsonUtils::SetValueForKey(json, ModeKey, args->_Mode); - return json; - } - IActionArgs Copy() const - { - auto copy{ winrt::make_self() }; - copy->_Direction = _Direction; - copy->_Mode = _Mode; - return *copy; - } - size_t Hash() const - { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(_Direction, _Mode); - } - }; - } namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl index 5acf82fb0c5..21b1b4b0bcb 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl @@ -323,10 +323,4 @@ namespace Microsoft.Terminal.Settings.Model MultipleActionsArgs(); Windows.Foundation.Collections.IVector Actions; }; - - [default_interface] runtimeclass UpdateSelectionArgs : IActionArgs - { - Microsoft.Terminal.Core.SelectionDirection Direction { get; }; - Microsoft.Terminal.Core.SelectionExpansion Mode { get; }; - }; } diff --git a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h index 801e8ece981..aa06ae70cda 100644 --- a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h +++ b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h @@ -82,8 +82,7 @@ ON_ALL_ACTIONS(OpenSystemMenu) \ ON_ALL_ACTIONS(ClearBuffer) \ ON_ALL_ACTIONS(MultipleActions) \ - ON_ALL_ACTIONS(Quit) \ - ON_ALL_ACTIONS(UpdateSelection) + ON_ALL_ACTIONS(Quit) #define ALL_SHORTCUT_ACTIONS_WITH_ARGS \ ON_ALL_ACTIONS_WITH_ARGS(AdjustFontSize) \ @@ -116,5 +115,4 @@ ON_ALL_ACTIONS_WITH_ARGS(ToggleCommandPalette) \ ON_ALL_ACTIONS_WITH_ARGS(FocusPane) \ ON_ALL_ACTIONS_WITH_ARGS(ClearBuffer) \ - ON_ALL_ACTIONS_WITH_ARGS(MultipleActions) \ - ON_ALL_ACTIONS_WITH_ARGS(UpdateSelection) + ON_ALL_ACTIONS_WITH_ARGS(MultipleActions) diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h index db96440a842..83c791f95ed 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h @@ -512,23 +512,3 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage) pair_type{ "keyboardServiceWarning", ValueType::KeyboardServiceWarning }, }; }; - -JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Core::SelectionDirection) -{ - static constexpr std::array mappings = { - pair_type{ "left", ValueType::Left }, - pair_type{ "right", ValueType::Right }, - pair_type{ "up", ValueType::Up }, - pair_type{ "down", ValueType::Down } - }; -}; - -JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Core::SelectionExpansion) -{ - static constexpr std::array mappings = { - pair_type{ "char", ValueType::Char }, - pair_type{ "word", ValueType::Word }, - pair_type{ "view", ValueType::Viewport }, - pair_type{ "buffer", ValueType::Buffer } - }; -}; diff --git a/src/cascadia/TerminalSettingsModel/defaults.json b/src/cascadia/TerminalSettingsModel/defaults.json index 3e34f6c2c63..6261e743a93 100644 --- a/src/cascadia/TerminalSettingsModel/defaults.json +++ b/src/cascadia/TerminalSettingsModel/defaults.json @@ -380,20 +380,6 @@ { "command": "paste", "keys": "ctrl+shift+v" }, { "command": "paste", "keys": "shift+insert" }, - // Keyboard Selection - { "command": {"action": "updateSelection", "direction": "left", "mode": "char" }, "keys": "shift+left" }, - { "command": {"action": "updateSelection", "direction": "right", "mode": "char" }, "keys": "shift+right" }, - { "command": {"action": "updateSelection", "direction": "up", "mode": "char" }, "keys": "shift+up" }, - { "command": {"action": "updateSelection", "direction": "down", "mode": "char" }, "keys": "shift+down" }, - { "command": {"action": "updateSelection", "direction": "left", "mode": "word" }, "keys": "ctrl+shift+left" }, - { "command": {"action": "updateSelection", "direction": "right", "mode": "word" }, "keys": "ctrl+shift+right" }, - { "command": {"action": "updateSelection", "direction": "left", "mode": "view" }, "keys": "shift+home" }, - { "command": {"action": "updateSelection", "direction": "right", "mode": "view" }, "keys": "shift+end" }, - { "command": {"action": "updateSelection", "direction": "up", "mode": "view" }, "keys": "shift+pgup" }, - { "command": {"action": "updateSelection", "direction": "down", "mode": "view" }, "keys": "shift+pgdn" }, - { "command": {"action": "updateSelection", "direction": "up", "mode": "buffer" }, "keys": "ctrl+shift+home" }, - { "command": {"action": "updateSelection", "direction": "down", "mode": "buffer" }, "keys": "ctrl+shift+end" }, - // Scrollback { "command": "scrollDown", "keys": "ctrl+shift+down" }, { "command": "scrollDownPage", "keys": "ctrl+shift+pgdn" }, diff --git a/src/types/UiaTextRangeBase.cpp b/src/types/UiaTextRangeBase.cpp index a38779be270..464dffa02e2 100644 --- a/src/types/UiaTextRangeBase.cpp +++ b/src/types/UiaTextRangeBase.cpp @@ -295,7 +295,7 @@ void UiaTextRangeBase::_expandToEnclosingUnit(TextUnit unit) if (unit == TextUnit_Character) { _start = buffer.GetGlyphStart(_start, documentEnd); - _end = buffer.GetGlyphEnd(_start, documentEnd, true); + _end = buffer.GetGlyphEnd(_start, true, documentEnd); } else if (unit <= TextUnit_Word) { From 30009eb0eb278a432c23a30b0dfa493eb4cd87bc Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Thu, 16 Sep 2021 20:13:28 -0700 Subject: [PATCH 09/10] polish and fix build --- .../PublicTerminalCore/HwndTerminal.cpp | 4 +-- src/cascadia/TerminalCore/Terminal.hpp | 2 +- .../TerminalCore/TerminalSelection.cpp | 3 -- .../UnitTests_TerminalCore/SelectionTest.cpp | 34 +++++++++---------- 4 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp index 14df7c79464..02025be813e 100644 --- a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp +++ b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp @@ -549,11 +549,11 @@ try if (multiClickMapper == 3) { - _terminal->MultiClickSelection(cursorPosition / fontSize, InternalSelectionExpansion::Line); + _terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansion::Line); } else if (multiClickMapper == 2) { - _terminal->MultiClickSelection(cursorPosition / fontSize, InternalSelectionExpansion::Word); + _terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansion::Word); } else { diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index bc51241b9c9..8fb9ca03a5d 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -239,7 +239,7 @@ class Microsoft::Terminal::Core::Terminal final : { Char, Word, - Line, // Mouse selection only! Not a setting! + Line, // Mouse selection only! Viewport, Buffer }; diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index 0c15894ea60..c29ffeb0c90 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -5,10 +5,7 @@ #include "Terminal.hpp" #include "unicode.hpp" -#include - using namespace Microsoft::Terminal::Core; -using namespace winrt::Microsoft::Terminal::Core; /* Selection Pivot Description: * The pivot helps properly update the selection when a user moves a selection over itself diff --git a/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp b/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp index 8929eb7d9ba..e0dc7acc5bf 100644 --- a/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp +++ b/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp @@ -130,7 +130,7 @@ namespace TerminalCoreUnitTests DummyRenderTarget emptyRT; term.Create({ 10, 10 }, scrollback, emptyRT); - term.MultiClickSelection(maxCoord, InternalSelectionExpansion::Word); + term.MultiClickSelection(maxCoord, Terminal::SelectionExpansion::Word); ValidateSingleRowSelection(term, expected); }; @@ -142,7 +142,7 @@ namespace TerminalCoreUnitTests DummyRenderTarget emptyRT; term.Create({ 10, 10 }, scrollback, emptyRT); - term.MultiClickSelection(maxCoord, InternalSelectionExpansion::Line); + term.MultiClickSelection(maxCoord, Terminal::SelectionExpansion::Line); ValidateSingleRowSelection(term, expected); }; @@ -501,7 +501,7 @@ namespace TerminalCoreUnitTests // Simulate double click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, InternalSelectionExpansion::Word); + term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Word); // Validate selection area ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, (4 + gsl::narrow(text.size()) - 1), 10 })); @@ -519,7 +519,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, InternalSelectionExpansion::Word); + term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Word); // Simulate renderer calling TriggerSelection and acquiring selection area auto selectionRects = term.GetSelectionRects(); @@ -546,7 +546,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (15,10) // this is over the '>' char auto clickPos = COORD{ 15, 10 }; - term.MultiClickSelection(clickPos, InternalSelectionExpansion::Word); + term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Word); // ---Validate selection area--- // "Terminal" is in class 2 @@ -572,7 +572,7 @@ namespace TerminalCoreUnitTests term.Write(text); // Simulate double click at (x,y) = (5,10) - term.MultiClickSelection({ 5, 10 }, InternalSelectionExpansion::Word); + term.MultiClickSelection({ 5, 10 }, Terminal::SelectionExpansion::Word); // Simulate move to (x,y) = (21,10) // @@ -601,7 +601,7 @@ namespace TerminalCoreUnitTests term.Write(text); // Simulate double click at (x,y) = (21,10) - term.MultiClickSelection({ 21, 10 }, InternalSelectionExpansion::Word); + term.MultiClickSelection({ 21, 10 }, Terminal::SelectionExpansion::Word); // Simulate move to (x,y) = (5,10) // @@ -622,7 +622,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, InternalSelectionExpansion::Line); + term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Line); // Validate selection area ValidateSingleRowSelection(term, SMALL_RECT({ 0, 10, 99, 10 })); @@ -636,7 +636,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, InternalSelectionExpansion::Line); + term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Line); // Simulate move to (x,y) = (7,10) term.SetSelectionEnd({ 7, 10 }); @@ -653,7 +653,7 @@ namespace TerminalCoreUnitTests // Simulate click at (x,y) = (5,10) auto clickPos = COORD{ 5, 10 }; - term.MultiClickSelection(clickPos, InternalSelectionExpansion::Line); + term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Line); // Simulate move to (x,y) = (5,11) term.SetSelectionEnd({ 5, 11 }); @@ -691,7 +691,7 @@ namespace TerminalCoreUnitTests // Step 1: Create a selection on "doubleClickMe" { // Simulate double click at (x,y) = (5,10) - term.MultiClickSelection({ 5, 10 }, InternalSelectionExpansion::Word); + term.MultiClickSelection({ 5, 10 }, Terminal::SelectionExpansion::Word); // Validate selection area: "doubleClickMe" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 16, 10 })); @@ -704,7 +704,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere // ^ ^ // start finish - term.SetSelectionEnd({ 21, 10 }, InternalSelectionExpansion::Char); + term.SetSelectionEnd({ 21, 10 }, Terminal::SelectionExpansion::Char); // Validate selection area: "doubleClickMe drag" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 21, 10 })); @@ -717,7 +717,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere // ^ ^ ^ // start click finish - term.SetSelectionEnd({ 21, 10 }, InternalSelectionExpansion::Word); + term.SetSelectionEnd({ 21, 10 }, Terminal::SelectionExpansion::Word); // Validate selection area: "doubleClickMe dragThroughHere" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 32, 10 })); @@ -730,7 +730,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere | // ^ ^ ^ // start click finish (boundary) - term.SetSelectionEnd({ 21, 10 }, InternalSelectionExpansion::Line); + term.SetSelectionEnd({ 21, 10 }, Terminal::SelectionExpansion::Line); // Validate selection area: "doubleClickMe dragThroughHere..." selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 99, 10 })); @@ -743,7 +743,7 @@ namespace TerminalCoreUnitTests // buffer: doubleClickMe dragThroughHere // ^ ^ ^ // start click finish - term.SetSelectionEnd({ 21, 10 }, InternalSelectionExpansion::Word); + term.SetSelectionEnd({ 21, 10 }, Terminal::SelectionExpansion::Word); // Validate selection area: "doubleClickMe dragThroughHere" selected ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 32, 10 })); @@ -825,7 +825,7 @@ namespace TerminalCoreUnitTests // Step 4: Shift+Click at (5,10) { - term.SetSelectionEnd({ 5, 10 }, InternalSelectionExpansion::Char); + term.SetSelectionEnd({ 5, 10 }, Terminal::SelectionExpansion::Char); // Validate selection area // NOTE: Pivot should still be (10, 10) @@ -834,7 +834,7 @@ namespace TerminalCoreUnitTests // Step 5: Shift+Click back at (20,10) { - term.SetSelectionEnd({ 20, 10 }, InternalSelectionExpansion::Char); + term.SetSelectionEnd({ 20, 10 }, Terminal::SelectionExpansion::Char); // Validate selection area // NOTE: Pivot should still be (10, 10) From b7842624a05d54b8af488c74cbb2326ca8ff797f Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Thu, 23 Sep 2021 10:54:18 -0700 Subject: [PATCH 10/10] address Leonard's comments --- src/cascadia/TerminalControl/ControlCore.cpp | 72 +------------------ src/cascadia/TerminalCore/Terminal.hpp | 5 +- .../TerminalCore/TerminalSelection.cpp | 69 ++++++++++++++---- src/renderer/dx/DxRenderer.cpp | 1 + 4 files changed, 64 insertions(+), 83 deletions(-) diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index ca0dd49d661..d1e26804d39 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -33,74 +33,6 @@ constexpr const auto TsfRedrawInterval = std::chrono::milliseconds(100); // The minimum delay between updating the locations of regex patterns constexpr const auto UpdatePatternLocationsInterval = std::chrono::milliseconds(500); -static constexpr std::optional ConvertVKeyToSelectionDirection(WORD vkey) -{ - switch (vkey) - { - case VK_LEFT: - case VK_HOME: - return Terminal::SelectionDirection::Left; - case VK_RIGHT: - case VK_END: - return Terminal::SelectionDirection::Right; - case VK_UP: - case VK_PRIOR: - return Terminal::SelectionDirection::Up; - case VK_DOWN: - case VK_NEXT: - return Terminal::SelectionDirection::Down; - default: - return std::nullopt; - } -} - -static constexpr std::optional> ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) -{ - if (mods.IsShiftPressed() && !mods.IsAltPressed()) - { - if (const auto dir{ ConvertVKeyToSelectionDirection(vkey) }) - { - if (mods.IsCtrlPressed()) - { - switch (vkey) - { - case VK_LEFT: - case VK_RIGHT: - // Move by word - return std::make_tuple(*dir, Terminal::SelectionExpansion::Word); - case VK_HOME: - case VK_END: - // Move by buffer - return std::make_tuple(*dir, Terminal::SelectionExpansion::Buffer); - default: - __fallthrough; - } - } - else - { - switch (vkey) - { - case VK_HOME: - case VK_END: - case VK_PRIOR: - case VK_NEXT: - // Move by viewport - return std::make_tuple(*dir, Terminal::SelectionExpansion::Viewport); - case VK_LEFT: - case VK_RIGHT: - case VK_UP: - case VK_DOWN: - // Move by character - return std::make_tuple(*dir, Terminal::SelectionExpansion::Char); - default: - __fallthrough; - } - } - } - } - return std::nullopt; -} - namespace winrt::Microsoft::Terminal::Control::implementation { // Helper static function to ensure that all ambiguous-width glyphs are reported as narrow. @@ -441,10 +373,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation keyDown) { // try to update the selection - if (const auto updateSlnParams{ ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) }) + if (const auto updateSlnParams{ ::Terminal::ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) }) { auto lock = _terminal->LockForWriting(); - _terminal->UpdateSelection(std::get<0>(*updateSlnParams), std::get<1>(*updateSlnParams)); + _terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second); _renderer->TriggerSelection(); return true; } diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 8fb9ca03a5d..d3b5f14403f 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -249,6 +249,9 @@ class Microsoft::Terminal::Core::Terminal final : void SetBlockSelection(const bool isEnabled) noexcept; void UpdateSelection(SelectionDirection direction, SelectionExpansion mode); + using UpdateSelectionParams = std::optional>; + static UpdateSelectionParams ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey); + const TextBuffer::TextAndColor RetrieveSelectedTextFromBuffer(bool trimTrailingWhitespace); #pragma endregion @@ -383,7 +386,7 @@ class Microsoft::Terminal::Core::Terminal final : #pragma region TextSelection // These methods are defined in TerminalSelection.cpp std::vector _GetSelectionRects() const noexcept; - std::tuple _PivotSelection(const COORD targetPos) const; + std::pair _PivotSelection(const COORD targetPos, bool& targetStart) const; std::pair _ExpandSelectionAnchors(std::pair anchors) const; COORD _ConvertToBufferCell(const COORD viewportPos) const; void _MoveByChar(SelectionDirection direction, COORD& pos); diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index c29ffeb0c90..367a8365a56 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -151,9 +151,8 @@ void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional anchors; - bool targetStart; - std::tie(anchors.first, anchors.second, targetStart) = _PivotSelection(textBufferPos); + bool targetStart = false; + const auto anchors = _PivotSelection(textBufferPos, targetStart); const auto expandedAnchors = _ExpandSelectionAnchors(anchors); if (newExpansionMode.has_value()) @@ -178,24 +177,22 @@ void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional Terminal::_PivotSelection(const COORD targetPos) const +// - the new start/end for a selection +std::pair Terminal::_PivotSelection(const COORD targetPos, bool& targetStart) const { - const bool targetStart{ _buffer->GetSize().CompareInBounds(targetPos, _selection->pivot) <= 0 }; - if (targetStart) + if (targetStart = _buffer->GetSize().CompareInBounds(targetPos, _selection->pivot) <= 0) { // target is before pivot // treat target as start - return { targetPos, _selection->pivot, targetStart }; + return std::make_pair(targetPos, _selection->pivot); } else { // target is after pivot // treat pivot as start - return { _selection->pivot, targetPos, targetStart }; + return std::make_pair(_selection->pivot, targetPos); } } @@ -238,6 +235,52 @@ void Terminal::SetBlockSelection(const bool isEnabled) noexcept _blockSelection = isEnabled; } +Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) +{ + if (mods.IsShiftPressed() && !mods.IsAltPressed()) + { + if (mods.IsCtrlPressed()) + { + // Ctrl + Shift + _ + switch (vkey) + { + case VK_LEFT: + return UpdateSelectionParams{ std::in_place, SelectionDirection::Left, SelectionExpansion::Word }; + case VK_RIGHT: + return UpdateSelectionParams{ std::in_place, SelectionDirection::Right, SelectionExpansion::Word }; + case VK_HOME: + return UpdateSelectionParams{ std::in_place, SelectionDirection::Left, SelectionExpansion::Buffer }; + case VK_END: + return UpdateSelectionParams{ std::in_place, SelectionDirection::Right, SelectionExpansion::Buffer }; + } + } + else + { + // Shift + _ + switch (vkey) + { + case VK_HOME: + return UpdateSelectionParams{ std::in_place, SelectionDirection::Left, SelectionExpansion::Viewport }; + case VK_END: + return UpdateSelectionParams{ std::in_place, SelectionDirection::Right, SelectionExpansion::Viewport }; + case VK_PRIOR: + return UpdateSelectionParams{ std::in_place, SelectionDirection::Up, SelectionExpansion::Viewport }; + case VK_NEXT: + return UpdateSelectionParams{ std::in_place, SelectionDirection::Down, SelectionExpansion::Viewport }; + case VK_LEFT: + return UpdateSelectionParams{ std::in_place, SelectionDirection::Left, SelectionExpansion::Char }; + case VK_RIGHT: + return UpdateSelectionParams{ std::in_place, SelectionDirection::Right, SelectionExpansion::Char }; + case VK_UP: + return UpdateSelectionParams{ std::in_place, SelectionDirection::Up, SelectionExpansion::Char }; + case VK_DOWN: + return UpdateSelectionParams{ std::in_place, SelectionDirection::Down, SelectionExpansion::Char }; + } + } + } + return std::nullopt; +} + void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode) { // 1. Figure out which endpoint to update @@ -263,7 +306,9 @@ void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion } // 3. Actually modify the selection - std::tie(_selection->start, _selection->end, std::ignore) = _PivotSelection(targetPos); + // NOTE: targetStart doesn't matter here + bool targetStart = false; + std::tie(_selection->start, _selection->end) = _PivotSelection(targetPos, targetStart); // 4. Scroll (if necessary) if (const auto viewport = _GetVisibleViewport(); !viewport.IsInBounds(targetPos)) diff --git a/src/renderer/dx/DxRenderer.cpp b/src/renderer/dx/DxRenderer.cpp index d01d99364ad..de33cd00c79 100644 --- a/src/renderer/dx/DxRenderer.cpp +++ b/src/renderer/dx/DxRenderer.cpp @@ -493,6 +493,7 @@ void DxEngine::_ComputePixelShaderSettings() noexcept // actual failure from the API itself. [[nodiscard]] HRESULT DxEngine::_CreateSurfaceHandle() noexcept { +#pragma warning(suppress : 26447) wil::unique_hmodule hDComp{ LoadLibraryEx(L"Dcomp.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) }; RETURN_LAST_ERROR_IF(hDComp.get() == nullptr);