From 2f4a1c5a5ecb55de2a97d69ecbc26e39b89bf394 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Fri, 6 May 2022 11:01:40 -0700 Subject: [PATCH 1/8] Introduce Mark Mode --- src/cascadia/TerminalControl/ControlCore.cpp | 64 +++++++++++++------ src/cascadia/TerminalControl/ControlCore.h | 1 + src/cascadia/TerminalControl/ControlCore.idl | 1 + src/cascadia/TerminalControl/TermControl.cpp | 4 +- src/cascadia/TerminalCore/Terminal.cpp | 3 +- src/cascadia/TerminalCore/Terminal.hpp | 7 +- .../TerminalCore/TerminalSelection.cpp | 52 +++++++++++++-- 7 files changed, 103 insertions(+), 29 deletions(-) diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index be5e7a70c1a..b2b7a7aba88 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -387,33 +387,56 @@ namespace winrt::Microsoft::Terminal::Control::implementation // 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) && + if (!KeyEvent::IsModifierKey(vkey) && vkey != VK_SNAPSHOT && keyDown) { - // try to update the selection - if (const auto updateSlnParams{ ::Terminal::ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) }) + // TODO CARLOS: should we make this ctrl+shift+m instead? + if (modifiers.IsCtrlPressed() && vkey == 'M') { - auto lock = _terminal->LockForWriting(); - _terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second); + _terminal->EnterMarkMode(); _renderer->TriggerSelection(); return true; } - - // GH#8791 - don't dismiss selection if Windows key was also pressed as a key-combination. - if (!modifiers.IsWinPressed()) + else if (HasSelection()) { - _terminal->ClearSelection(); - _renderer->TriggerSelection(); - } + if (modifiers.IsCtrlPressed() && vkey == 'A') + { + auto lock = _terminal->LockForWriting(); + _terminal->SelectAll(); + _renderer->TriggerSelection(); + return true; + } + else if (vkey == VK_RETURN) + { + CopySelectionToClipboard(false, nullptr); + return; + } - // 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; + // try to update the selection + if (const auto updateSlnParams{ _terminal->ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) }) + { + auto lock = _terminal->LockForWriting(); + const std::optional markModeOverride = _terminal->IsInMarkMode() ? modifiers.IsShiftPressed() : std::optional{}; + _terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second, markModeOverride); + _renderer->TriggerSelection(); + return true; + } + + // GH#8791 - don't dismiss selection if Windows key was also pressed as a key-combination. + if (!modifiers.IsWinPressed()) + { + _terminal->ClearSelection(); + _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; + } } } @@ -1001,6 +1024,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation _renderer->TriggerSelection(); } + bool ControlCore::IsInMarkMode() const + { + return _terminal->IsInMarkMode(); + } + // Method Description: // - Pre-process text pasted (presumably from the clipboard) // before sending it over the terminal's connection. diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index 1a8b744cb7f..a0b74021f18 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -81,6 +81,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation void PasteText(const winrt::hstring& hstr); bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference& formats); void SelectAll(); + bool IsInMarkMode() const; void GotFocus(); void LostFocus(); diff --git a/src/cascadia/TerminalControl/ControlCore.idl b/src/cascadia/TerminalControl/ControlCore.idl index 55b718d1fd1..dad89ac0764 100644 --- a/src/cascadia/TerminalControl/ControlCore.idl +++ b/src/cascadia/TerminalControl/ControlCore.idl @@ -67,6 +67,7 @@ namespace Microsoft.Terminal.Control void PasteText(String text); void SelectAll(); void ClearBuffer(ClearBufferType clearType); + Boolean IsInMarkMode(); void SetHoveredCell(Microsoft.Terminal.Core.Point terminalPosition); void ClearHoveredCell(); diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index f90a2a96bd1..a0dcf6e9b69 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -1123,7 +1123,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation { // Manually show the cursor when a key is pressed. Restarting // the timer prevents flickering. - _core.CursorOn(true); + _core.CursorOn(!_core.IsInMarkMode()); _cursorTimer->Start(); } @@ -1594,7 +1594,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation if (_cursorTimer) { // When the terminal focuses, show the cursor immediately - _core.CursorOn(true); + _core.CursorOn(!_core.IsInMarkMode()); _cursorTimer->Start(); } diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 648d7fff902..11f6f664362 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -45,6 +45,7 @@ Terminal::Terminal() : _snapOnInput{ true }, _altGrAliasing{ true }, _blockSelection{ false }, + _markMode{ false }, _selection{ std::nullopt }, _taskbarState{ 0 }, _taskbarProgress{ 0 }, @@ -1328,7 +1329,7 @@ void Terminal::SetCursorOn(const bool isOn) bool Terminal::IsCursorBlinkingAllowed() const noexcept { const auto& cursor = _activeBuffer().GetCursor(); - return cursor.IsBlinkingAllowed(); + return !_markMode && cursor.IsBlinkingAllowed(); } // Method Description: diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index e89e9167b47..439ca3413c4 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -239,11 +239,13 @@ class Microsoft::Terminal::Core::Terminal final : void SetSelectionAnchor(const COORD position); void SetSelectionEnd(const COORD position, std::optional newExpansionMode = std::nullopt); void SetBlockSelection(const bool isEnabled) noexcept; - void UpdateSelection(SelectionDirection direction, SelectionExpansion mode); + void UpdateSelection(SelectionDirection direction, SelectionExpansion mode, std::optional moveSelectionEnd = std::nullopt); void SelectAll(); + bool IsInMarkMode() const; + void EnterMarkMode(); using UpdateSelectionParams = std::optional>; - static UpdateSelectionParams ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey); + UpdateSelectionParams ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) const; const TextBuffer::TextAndColor RetrieveSelectedTextFromBuffer(bool trimTrailingWhitespace); #pragma endregion @@ -313,6 +315,7 @@ class Microsoft::Terminal::Core::Terminal final : bool _blockSelection; std::wstring _wordDelimiters; SelectionExpansion _multiClickSelectionMode; + bool _markMode; #pragma endregion std::unique_ptr _mainBuffer; diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index b730836f114..1bc326edee9 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -235,13 +235,30 @@ void Terminal::SetBlockSelection(const bool isEnabled) noexcept _blockSelection = isEnabled; } -Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) +bool Terminal::IsInMarkMode() const { - if (mods.IsShiftPressed() && !mods.IsAltPressed()) + return _markMode; +} + +void Terminal::EnterMarkMode() +{ + SetCursorOn(false); + const auto cursorPos{ _activeBuffer().GetCursor().GetPosition() }; + _selection = SelectionAnchors{}; + _selection->start = cursorPos; + _selection->end = cursorPos; + _selection->pivot = cursorPos; + _markMode = true; +} + +Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) const +{ + if ((_markMode || mods.IsShiftPressed()) && !mods.IsAltPressed()) { if (mods.IsCtrlPressed()) { // Ctrl + Shift + _ + // (Mark Mode) Ctrl + _ switch (vkey) { case VK_LEFT: @@ -257,6 +274,7 @@ Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams else { // Shift + _ + // (Mark Mode) Just the vkeys switch (vkey) { case VK_HOME: @@ -281,11 +299,17 @@ Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams return std::nullopt; } -void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode) +// Method Description: +// - updates the selection endpoints based on a direction and expansion mode. Primarily used for keyboard selection. +// Arguments: +// - direction: the direction to move the selection endpoint in +// - mode: the type of movement to be performed (i.e. move by word) +// - (optional) moveSelectionEnd: used by mark mode. Can be used to explicitly move a specific endpoint. If true, move the "end" endpoint. Otherwise, move the start endpoint. +void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode, std::optional moveSelectionEnd) { // 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. - const auto movingEnd{ _selection->start == _selection->pivot }; + const auto movingEnd{ (_markMode && moveSelectionEnd.has_value()) ? *moveSelectionEnd : _selection->start == _selection->pivot }; auto targetPos{ movingEnd ? _selection->end : _selection->start }; // 2. Perform the movement @@ -307,8 +331,23 @@ void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion // 3. Actually modify the selection // NOTE: targetStart doesn't matter here - auto targetStart = false; - std::tie(_selection->start, _selection->end) = _PivotSelection(targetPos, targetStart); + if (_markMode) + { + // [Mark Mode] + // - moveSelectionEnd --> just move end (i.e. shift + arrow keys) + // - !moveSelectionEnd --> move all three (i.e. just use arrow keys) + _selection->end = targetPos; + if (!*moveSelectionEnd) + { + _selection->start = targetPos; + _selection->pivot = targetPos; + } + } + else + { + auto targetStart = false; + std::tie(_selection->start, _selection->end) = _PivotSelection(targetPos, targetStart); + } // 4. Scroll (if necessary) if (const auto viewport = _GetVisibleViewport(); !viewport.IsInBounds(targetPos)) @@ -473,6 +512,7 @@ void Terminal::_MoveByBuffer(SelectionDirection direction, COORD& pos) void Terminal::ClearSelection() { _selection = std::nullopt; + _markMode = false; } // Method Description: From 262a6bb379faf606ab08537fc00ceae0f70d75cf Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Mon, 9 May 2022 16:53:44 -0700 Subject: [PATCH 2/8] make mark mode an action --- .../TerminalApp/AppActionHandlers.cpp | 10 +++ src/cascadia/TerminalControl/ControlCore.cpp | 76 +++++++++---------- 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/Terminal.hpp | 2 +- .../TerminalCore/TerminalSelection.cpp | 25 ++++-- .../TerminalSettingsModel/ActionAndArgs.cpp | 2 + .../AllShortcutActions.h | 3 +- .../Resources/en-US/Resources.resw | 3 + .../TerminalSettingsModel/defaults.json | 1 + 13 files changed, 82 insertions(+), 49 deletions(-) diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 3d61450e8c5..8c9a1638c6d 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -1043,4 +1043,14 @@ namespace winrt::TerminalApp::implementation args.Handled(true); } } + + void TerminalPage::_HandleMarkMode(const IInspectable& /*sender*/, + const ActionEventArgs& args) + { + if (const auto& control{ _GetActiveControl() }) + { + control.ToggleMarkMode(); + args.Handled(true); + } + } } diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index b2b7a7aba88..cb1779ff78c 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -387,56 +387,47 @@ namespace winrt::Microsoft::Terminal::Control::implementation // 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 (!KeyEvent::IsModifierKey(vkey) && + if (HasSelection() && + !KeyEvent::IsModifierKey(vkey) && vkey != VK_SNAPSHOT && keyDown) { - // TODO CARLOS: should we make this ctrl+shift+m instead? - if (modifiers.IsCtrlPressed() && vkey == 'M') + if (modifiers.IsCtrlPressed() && vkey == 'A') { - _terminal->EnterMarkMode(); + auto lock = _terminal->LockForWriting(); + _terminal->SelectAll(); _renderer->TriggerSelection(); return true; } - else if (HasSelection()) + else if (vkey == VK_RETURN) { - if (modifiers.IsCtrlPressed() && vkey == 'A') - { - auto lock = _terminal->LockForWriting(); - _terminal->SelectAll(); - _renderer->TriggerSelection(); - return true; - } - else if (vkey == VK_RETURN) - { - CopySelectionToClipboard(false, nullptr); - return; - } + CopySelectionToClipboard(false, nullptr); + return true; + } - // try to update the selection - if (const auto updateSlnParams{ _terminal->ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) }) - { - auto lock = _terminal->LockForWriting(); - const std::optional markModeOverride = _terminal->IsInMarkMode() ? modifiers.IsShiftPressed() : std::optional{}; - _terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second, markModeOverride); - _renderer->TriggerSelection(); - return true; - } + // try to update the selection + if (const auto updateSlnParams{ _terminal->ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) }) + { + auto lock = _terminal->LockForWriting(); + const std::optional markModeOverride = _terminal->IsInMarkMode() ? modifiers.IsShiftPressed() : std::optional{}; + _terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second, markModeOverride); + _renderer->TriggerSelection(); + return true; + } - // GH#8791 - don't dismiss selection if Windows key was also pressed as a key-combination. - if (!modifiers.IsWinPressed()) - { - _terminal->ClearSelection(); - _renderer->TriggerSelection(); - } + // GH#8791 - don't dismiss selection if Windows key was also pressed as a key-combination. + if (!modifiers.IsWinPressed()) + { + _terminal->ClearSelection(); + _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; - } + // 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; } } @@ -1024,6 +1015,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation _renderer->TriggerSelection(); } + void ControlCore::ToggleMarkMode() + { + auto lock = _terminal->LockForWriting(); + _terminal->ToggleMarkMode(); + _renderer->TriggerSelection(); + } + bool ControlCore::IsInMarkMode() const { return _terminal->IsInMarkMode(); diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index a0b74021f18..c2c0ef4f3d9 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -81,6 +81,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation void PasteText(const winrt::hstring& hstr); bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference& formats); void SelectAll(); + void ToggleMarkMode(); bool IsInMarkMode() const; void GotFocus(); diff --git a/src/cascadia/TerminalControl/ControlCore.idl b/src/cascadia/TerminalControl/ControlCore.idl index dad89ac0764..edcb9fb69b1 100644 --- a/src/cascadia/TerminalControl/ControlCore.idl +++ b/src/cascadia/TerminalControl/ControlCore.idl @@ -66,6 +66,7 @@ namespace Microsoft.Terminal.Control void SendInput(String text); void PasteText(String text); void SelectAll(); + void ToggleMarkMode(); void ClearBuffer(ClearBufferType clearType); Boolean IsInMarkMode(); diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index a0dcf6e9b69..786e5c39e3e 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -1845,6 +1845,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation _core.SelectAll(); } + void TermControl::ToggleMarkMode() + { + _core.ToggleMarkMode(); + } + void TermControl::Close() { if (!_IsClosing()) diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index c76c4b58703..87d336c4843 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -38,6 +38,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference& formats); void PasteTextFromClipboard(); void SelectAll(); + void ToggleMarkMode(); void Close(); Windows::Foundation::Size CharacterDimensions() const; Windows::Foundation::Size MinimumSize(); diff --git a/src/cascadia/TerminalControl/TermControl.idl b/src/cascadia/TerminalControl/TermControl.idl index b235962a73f..d11cbea9cfa 100644 --- a/src/cascadia/TerminalControl/TermControl.idl +++ b/src/cascadia/TerminalControl/TermControl.idl @@ -51,6 +51,7 @@ namespace Microsoft.Terminal.Control Boolean CopySelectionToClipboard(Boolean singleLine, Windows.Foundation.IReference formats); void PasteTextFromClipboard(); void SelectAll(); + void ToggleMarkMode(); void ClearBuffer(ClearBufferType clearType); void Close(); Windows.Foundation.Size CharacterDimensions { get; }; diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 439ca3413c4..b9b315607e4 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -242,7 +242,7 @@ class Microsoft::Terminal::Core::Terminal final : void UpdateSelection(SelectionDirection direction, SelectionExpansion mode, std::optional moveSelectionEnd = std::nullopt); void SelectAll(); bool IsInMarkMode() const; - void EnterMarkMode(); + void ToggleMarkMode(); using UpdateSelectionParams = std::optional>; UpdateSelectionParams ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) const; diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index 1bc326edee9..f5d512ab116 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -240,15 +240,24 @@ bool Terminal::IsInMarkMode() const return _markMode; } -void Terminal::EnterMarkMode() +void Terminal::ToggleMarkMode() { - SetCursorOn(false); - const auto cursorPos{ _activeBuffer().GetCursor().GetPosition() }; - _selection = SelectionAnchors{}; - _selection->start = cursorPos; - _selection->end = cursorPos; - _selection->pivot = cursorPos; - _markMode = true; + if (_markMode) + { + // Exit Mark Mode + ClearSelection(); + } + else + { + // Enter Mark Mode + SetCursorOn(false); + const auto cursorPos{ _activeBuffer().GetCursor().GetPosition() }; + _selection = SelectionAnchors{}; + _selection->start = cursorPos; + _selection->end = cursorPos; + _selection->pivot = cursorPos; + _markMode = true; + } } Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) const diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp index 15d48a51e50..517c85551df 100644 --- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp @@ -76,6 +76,7 @@ static constexpr std::string_view QuitKey{ "quit" }; static constexpr std::string_view AdjustOpacityKey{ "adjustOpacity" }; static constexpr std::string_view RestoreLastClosedKey{ "restoreLastClosed" }; static constexpr std::string_view SelectAllKey{ "selectAll" }; +static constexpr std::string_view MarkModeKey{ "markMode" }; static constexpr std::string_view ActionKey{ "action" }; @@ -388,6 +389,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { ShortcutAction::AdjustOpacity, L"" }, // Intentionally omitted, must be generated by GenerateName { ShortcutAction::RestoreLastClosed, RS_(L"RestoreLastClosedCommandKey") }, { ShortcutAction::SelectAll, RS_(L"SelectAllCommandKey") }, + { ShortcutAction::MarkMode, RS_(L"MarkModeCommandKey") }, }; }(); diff --git a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h index d988fc234a4..24f04b232a1 100644 --- a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h +++ b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h @@ -89,7 +89,8 @@ ON_ALL_ACTIONS(Quit) \ ON_ALL_ACTIONS(AdjustOpacity) \ ON_ALL_ACTIONS(RestoreLastClosed) \ - ON_ALL_ACTIONS(SelectAll) + ON_ALL_ACTIONS(SelectAll) \ + ON_ALL_ACTIONS(MarkMode) #define ALL_SHORTCUT_ACTIONS_WITH_ARGS \ ON_ALL_ACTIONS_WITH_ARGS(AdjustFontSize) \ diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw index 314ecf8f8bf..fd4bc24a502 100644 --- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -525,4 +525,7 @@ Select all text + + Toggle Mark Mode + \ No newline at end of file diff --git a/src/cascadia/TerminalSettingsModel/defaults.json b/src/cascadia/TerminalSettingsModel/defaults.json index 7a5c2d1f9d5..95118b5d884 100644 --- a/src/cascadia/TerminalSettingsModel/defaults.json +++ b/src/cascadia/TerminalSettingsModel/defaults.json @@ -385,6 +385,7 @@ { "command": "paste", "keys": "ctrl+shift+v" }, { "command": "paste", "keys": "shift+insert" }, { "command": "selectAll", "keys": "ctrl+shift+a" }, + { "command": "markMode", "keys": "ctrl+shift+m" }, // Scrollback { "command": "scrollDown", "keys": "ctrl+shift+down" }, From c9e28cb90a92700de3bf444b0dce8e6cc9153658 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Tue, 10 May 2022 10:26:27 -0700 Subject: [PATCH 3/8] update schema; fix deadlock --- doc/cascadia/profiles.schema.json | 2 ++ src/cascadia/TerminalApp/AppActionHandlers.cpp | 2 +- src/cascadia/TerminalCore/TerminalSelection.cpp | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index 9de676a965a..db0ac7feef8 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -318,6 +318,7 @@ "moveFocus", "movePane", "swapPane", + "markMode", "moveTab", "multipleActions", "newTab", @@ -345,6 +346,7 @@ "sendInput", "setColorScheme", "setTabColor", + "selectAll", "splitPane", "switchToTab", "tabSearch", diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 8c9a1638c6d..0cc395287a3 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -1045,7 +1045,7 @@ namespace winrt::TerminalApp::implementation } void TerminalPage::_HandleMarkMode(const IInspectable& /*sender*/, - const ActionEventArgs& args) + const ActionEventArgs& args) { if (const auto& control{ _GetActiveControl() }) { diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index f5d512ab116..e61450ee691 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -250,7 +250,8 @@ void Terminal::ToggleMarkMode() else { // Enter Mark Mode - SetCursorOn(false); + // NOTE: directly set cursor state. We already should have locked before calling this function. + _activeBuffer().GetCursor().SetIsOn(false); const auto cursorPos{ _activeBuffer().GetCursor().GetPosition() }; _selection = SelectionAnchors{}; _selection->start = cursorPos; From 2d71c2c0176278e008fb42fd6946ab17acd3a5b5 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Wed, 11 May 2022 12:56:31 -0700 Subject: [PATCH 4/8] fix a few nits --- doc/cascadia/profiles.schema.json | 1 - .../TerminalSettingsModel/Resources/en-US/Resources.resw | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index db0ac7feef8..17ab1f774cd 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -346,7 +346,6 @@ "sendInput", "setColorScheme", "setTabColor", - "selectAll", "splitPane", "switchToTab", "tabSearch", diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw index fd4bc24a502..f3baee86d2f 100644 --- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -527,5 +527,6 @@ Toggle Mark Mode + A command that will toggle "Mark Mode". This is a mode in the application where the user can mark the text by selecting portions of the text. \ No newline at end of file From 75faa5dd0815febf6989466c3659df9750df4278 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Mon, 16 May 2022 09:41:49 -0700 Subject: [PATCH 5/8] remove 'Enter' --> copy in Mark Mode --- src/cascadia/TerminalControl/ControlCore.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index cb1779ff78c..ab0b383b41d 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -399,11 +399,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation _renderer->TriggerSelection(); return true; } - else if (vkey == VK_RETURN) - { - CopySelectionToClipboard(false, nullptr); - return true; - } // try to update the selection if (const auto updateSlnParams{ _terminal->ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) }) From f302605ff487edcf7dc5c378dfa9da3ea65baafd Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Mon, 16 May 2022 14:32:40 -0700 Subject: [PATCH 6/8] address PR feedback --- src/cascadia/TerminalCore/TerminalSelection.cpp | 6 +++++- .../TerminalSettingsModel/Resources/en-US/Resources.resw | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index e61450ee691..fe7858646a3 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -318,7 +318,11 @@ Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode, std::optional moveSelectionEnd) { // 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. + // moveSelectionEnd has 3 possible values... + // - nullopt: we're just modifying an existing selection with the keyboard. So if you created a selection with a mouse, and now you're just using shift+arrows to update it. Codeflow requires you to pivot around the "start" if you cross the endpoints. + // if this is the case, one of the endpoints is the pivot, signifying that the other endpoint is the one we want to move. + // - true: only moving the "end" as if you're creating a selection in a text editor. "start" is anchored to the cursor, and "end" is moved; thus creating a selection. + // - false: moving both "start" and "end" together. This is when you're just moving the cursor in a text editor. const auto movingEnd{ (_markMode && moveSelectionEnd.has_value()) ? *moveSelectionEnd : _selection->start == _selection->pivot }; auto targetPos{ movingEnd ? _selection->end : _selection->start }; diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw index f3baee86d2f..7a23d7a111e 100644 --- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -526,7 +526,7 @@ Select all text - Toggle Mark Mode - A command that will toggle "Mark Mode". This is a mode in the application where the user can mark the text by selecting portions of the text. + Toggle mark mode + A command that will toggle "mark mode". This is a mode in the application where the user can mark the text by selecting portions of the text. \ No newline at end of file From 4a19d6b36eb8c8e3f0755b59cec601be26601b05 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Wed, 18 May 2022 15:31:25 -0700 Subject: [PATCH 7/8] apply Leonard's suggestions --- src/cascadia/TerminalControl/ControlCore.cpp | 3 +-- src/cascadia/TerminalCore/Terminal.hpp | 2 +- src/cascadia/TerminalCore/TerminalSelection.cpp | 16 +++++++--------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index ab0b383b41d..79c9a18d3ef 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -404,8 +404,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation if (const auto updateSlnParams{ _terminal->ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) }) { auto lock = _terminal->LockForWriting(); - const std::optional markModeOverride = _terminal->IsInMarkMode() ? modifiers.IsShiftPressed() : std::optional{}; - _terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second, markModeOverride); + _terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second, modifiers); _renderer->TriggerSelection(); return true; } diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index b9b315607e4..1a62d031a25 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -239,7 +239,7 @@ class Microsoft::Terminal::Core::Terminal final : void SetSelectionAnchor(const COORD position); void SetSelectionEnd(const COORD position, std::optional newExpansionMode = std::nullopt); void SetBlockSelection(const bool isEnabled) noexcept; - void UpdateSelection(SelectionDirection direction, SelectionExpansion mode, std::optional moveSelectionEnd = std::nullopt); + void UpdateSelection(SelectionDirection direction, SelectionExpansion mode, ControlKeyStates mods); void SelectAll(); bool IsInMarkMode() const; void ToggleMarkMode(); diff --git a/src/cascadia/TerminalCore/TerminalSelection.cpp b/src/cascadia/TerminalCore/TerminalSelection.cpp index fe7858646a3..6d75d6d20c5 100644 --- a/src/cascadia/TerminalCore/TerminalSelection.cpp +++ b/src/cascadia/TerminalCore/TerminalSelection.cpp @@ -314,16 +314,14 @@ Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams // Arguments: // - direction: the direction to move the selection endpoint in // - mode: the type of movement to be performed (i.e. move by word) -// - (optional) moveSelectionEnd: used by mark mode. Can be used to explicitly move a specific endpoint. If true, move the "end" endpoint. Otherwise, move the start endpoint. -void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode, std::optional moveSelectionEnd) +// - mods: the key modifiers pressed when performing this update +void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode, ControlKeyStates mods) { // 1. Figure out which endpoint to update - // moveSelectionEnd has 3 possible values... - // - nullopt: we're just modifying an existing selection with the keyboard. So if you created a selection with a mouse, and now you're just using shift+arrows to update it. Codeflow requires you to pivot around the "start" if you cross the endpoints. - // if this is the case, one of the endpoints is the pivot, signifying that the other endpoint is the one we want to move. - // - true: only moving the "end" as if you're creating a selection in a text editor. "start" is anchored to the cursor, and "end" is moved; thus creating a selection. - // - false: moving both "start" and "end" together. This is when you're just moving the cursor in a text editor. - const auto movingEnd{ (_markMode && moveSelectionEnd.has_value()) ? *moveSelectionEnd : _selection->start == _selection->pivot }; + // If we're in mark mode, shift dictates whether you are moving the end or not. + // Otherwise, we're updating an existing selection, so one of the endpoints is the pivot, + // signifying that the other endpoint is the one we want to move. + const auto movingEnd{ _markMode ? mods.IsShiftPressed() : _selection->start == _selection->pivot }; auto targetPos{ movingEnd ? _selection->end : _selection->start }; // 2. Perform the movement @@ -351,7 +349,7 @@ void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion // - moveSelectionEnd --> just move end (i.e. shift + arrow keys) // - !moveSelectionEnd --> move all three (i.e. just use arrow keys) _selection->end = targetPos; - if (!*moveSelectionEnd) + if (!movingEnd) { _selection->start = targetPos; _selection->pivot = targetPos; From 95640907418f47e0f05020a66b14eec89b01c78e Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Thu, 19 May 2022 07:44:30 -0700 Subject: [PATCH 8/8] fix ctrl+a --> select all in mm --- src/cascadia/TerminalControl/ControlCore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 79c9a18d3ef..d24dca93cef 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -392,7 +392,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation vkey != VK_SNAPSHOT && keyDown) { - if (modifiers.IsCtrlPressed() && vkey == 'A') + if (_terminal->IsInMarkMode() && modifiers.IsCtrlPressed() && vkey == 'A') { auto lock = _terminal->LockForWriting(); _terminal->SelectAll();