Skip to content

Commit

Permalink
Introduce switchSelectionEndpoint action (#13370)
Browse files Browse the repository at this point in the history
## Summary of the Pull Request
Introduces the `switchSelectionEndpoint` action which switches whichever selection endpoint is targeted when a selection is present. For example, if you are targeting "start", `switchSelectionEndpoint` makes it so that now you are targeting "end". This also updates the selection markers appropriately.

## References
Spec - #5804 
#13358
Closes #3663

## Detailed Description of the Pull Request / Additional comments
Most of the code is just standard code of adding a new action. Other than that, we have...
- if there is no selection, the action fails and the keybinding is passed through (similar to `copy()`)
- when we update the selection endpoint, we need to also update the "pivot". This ensures that future calls of `UpdateSelection()` respect this swap.
- [Corner Case] if the cursor is being moved, we make it so that you basically "anchored" an endpoint and you don't have to hold shift anymore.
  • Loading branch information
carlos-zamora authored Jul 1, 2022
1 parent d6a9e9f commit 7b8a53c
Show file tree
Hide file tree
Showing 15 changed files with 77 additions and 3 deletions.
1 change: 1 addition & 0 deletions doc/cascadia/profiles.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@
"toggleFocusMode",
"selectAll",
"setFocusMode",
"switchSelectionEndpoint",
"toggleFullscreen",
"setFullScreen",
"setMaximized",
Expand Down
10 changes: 10 additions & 0 deletions src/cascadia/TerminalApp/AppActionHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1112,4 +1112,14 @@ namespace winrt::TerminalApp::implementation
args.Handled(handled);
}
}

void TerminalPage::_HandleSwitchSelectionEndpoint(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& control{ _GetActiveControl() })
{
const auto handled = control.SwitchSelectionEndpoint();
args.Handled(handled);
}
}
}
10 changes: 10 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return static_cast<Control::SelectionInteractionMode>(_terminal->SelectionMode());
}

bool ControlCore::SwitchSelectionEndpoint()
{
if (_terminal->IsSelectionActive())
{
_terminal->SwitchSelectionEndpoint();
return true;
}
return false;
}

// Method Description:
// - Pre-process text pasted (presumably from the clipboard)
// before sending it over the terminal's connection.
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool ToggleBlockSelection();
void ToggleMarkMode();
Control::SelectionInteractionMode SelectionMode() const;
bool SwitchSelectionEndpoint();

void GotFocus();
void LostFocus();
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalControl/ControlCore.idl
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ namespace Microsoft.Terminal.Control
void ClearSelection();
Boolean ToggleBlockSelection();
void ToggleMarkMode();
Boolean SwitchSelectionEndpoint();
void ClearBuffer(ClearBufferType clearType);

void SetHoveredCell(Microsoft.Terminal.Core.Point terminalPosition);
Expand Down
5 changes: 5 additions & 0 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1929,6 +1929,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_core.ToggleMarkMode();
}

bool TermControl::SwitchSelectionEndpoint()
{
return _core.SwitchSelectionEndpoint();
}

void TermControl::Close()
{
if (!_IsClosing())
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalControl/TermControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SelectAll();
bool ToggleBlockSelection();
void ToggleMarkMode();
bool SwitchSelectionEndpoint();
void Close();
Windows::Foundation::Size CharacterDimensions() const;
Windows::Foundation::Size MinimumSize();
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalControl/TermControl.idl
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ namespace Microsoft.Terminal.Control
void SelectAll();
Boolean ToggleBlockSelection();
void ToggleMarkMode();
Boolean SwitchSelectionEndpoint();
void ClearBuffer(ClearBufferType clearType);
void Close();
Windows.Foundation.Size CharacterDimensions { get; };
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalCore/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Terminal::Terminal() :
_selectionMode{ SelectionInteractionMode::None },
_selection{ std::nullopt },
_selectionEndpoint{ static_cast<SelectionEndpoint>(0) },
_anchorInactiveSelectionEndpoint{ false },
_taskbarState{ 0 },
_taskbarProgress{ 0 },
_trimBlockSelection{ false },
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ class Microsoft::Terminal::Core::Terminal final :
void UpdateSelection(SelectionDirection direction, SelectionExpansion mode, ControlKeyStates mods);
void SelectAll();
SelectionInteractionMode SelectionMode() const noexcept;
void SwitchSelectionEndpoint();
void ToggleMarkMode();

using UpdateSelectionParams = std::optional<std::pair<SelectionDirection, SelectionExpansion>>;
Expand Down Expand Up @@ -349,6 +350,7 @@ class Microsoft::Terminal::Core::Terminal final :
SelectionExpansion _multiClickSelectionMode;
SelectionInteractionMode _selectionMode;
SelectionEndpoint _selectionEndpoint;
bool _anchorInactiveSelectionEndpoint;
#pragma endregion

std::unique_ptr<TextBuffer> _mainBuffer;
Expand Down
38 changes: 36 additions & 2 deletions src/cascadia/TerminalCore/TerminalSelection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,33 @@ void Terminal::ToggleMarkMode()
}
}

// Method Description:
// - switch the targeted selection endpoint with the other one (i.e. start <--> end)
void Terminal::SwitchSelectionEndpoint()
{
if (IsSelectionActive())
{
if (WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::Start) && WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::End))
{
// moving cursor --> anchor start, move end
_selectionEndpoint = SelectionEndpoint::End;
_anchorInactiveSelectionEndpoint = true;
}
else if (WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::End))
{
// moving end --> now we're moving start
_selectionEndpoint = SelectionEndpoint::Start;
_selection->pivot = _selection->end;
}
else if (WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::Start))
{
// moving start --> now we're moving end
_selectionEndpoint = SelectionEndpoint::End;
_selection->pivot = _selection->start;
}
}
}

Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) const
{
if ((_selectionMode == SelectionInteractionMode::Mark || mods.IsShiftPressed()) && !mods.IsAltPressed())
Expand Down Expand Up @@ -365,14 +392,20 @@ Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams
// - mods: the key modifiers pressed when performing this update
void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode, ControlKeyStates mods)
{
// This is a special variable used to track if we should move the cursor when in mark mode.
// We have special functionality where if you use the "switchSelectionEndpoint" action
// when in mark mode (moving the cursor), we anchor an endpoint and you can use the
// plain arrow keys to move the endpoint. This way, you don't have to hold shift anymore!
const bool shouldMoveBothEndpoints = _selectionMode == SelectionInteractionMode::Mark && !_anchorInactiveSelectionEndpoint && !mods.IsShiftPressed();

// 1. Figure out which endpoint to update
// [Mark Mode]
// - shift pressed --> only move "end" (or "start" if "pivot" == "end")
// - otherwise --> move both "start" and "end" (moving cursor)
// [Quick Edit]
// - just move "end" (or "start" if "pivot" == "end")
_selectionEndpoint = static_cast<SelectionEndpoint>(0);
if (_selectionMode == SelectionInteractionMode::Mark && !mods.IsShiftPressed())
if (shouldMoveBothEndpoints)
{
WI_SetAllFlags(_selectionEndpoint, SelectionEndpoint::Start | SelectionEndpoint::End);
}
Expand Down Expand Up @@ -405,7 +438,7 @@ void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion

// 3. Actually modify the selection state
_selectionMode = std::max(_selectionMode, SelectionInteractionMode::Keyboard);
if (_selectionMode == SelectionInteractionMode::Mark && !mods.IsShiftPressed())
if (shouldMoveBothEndpoints)
{
// [Mark Mode] + shift unpressed --> move all three (i.e. just use arrow keys)
_selection->start = targetPos;
Expand Down Expand Up @@ -598,6 +631,7 @@ void Terminal::ClearSelection()
_selection = std::nullopt;
_selectionMode = SelectionInteractionMode::None;
_selectionEndpoint = static_cast<SelectionEndpoint>(0);
_anchorInactiveSelectionEndpoint = false;
}

// Method Description:
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ 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 ToggleBlockSelectionKey{ "toggleBlockSelection" };
static constexpr std::string_view SwitchSelectionEndpointKey{ "switchSelectionEndpoint" };

static constexpr std::string_view ActionKey{ "action" };

Expand Down Expand Up @@ -400,6 +401,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{ ShortcutAction::SelectAll, RS_(L"SelectAllCommandKey") },
{ ShortcutAction::MarkMode, RS_(L"MarkModeCommandKey") },
{ ShortcutAction::ToggleBlockSelection, RS_(L"ToggleBlockSelectionCommandKey") },
{ ShortcutAction::SwitchSelectionEndpoint, RS_(L"SwitchSelectionEndpointCommandKey") },
};
}();

Expand Down
3 changes: 2 additions & 1 deletion src/cascadia/TerminalSettingsModel/AllShortcutActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@
ON_ALL_ACTIONS(RestoreLastClosed) \
ON_ALL_ACTIONS(SelectAll) \
ON_ALL_ACTIONS(MarkMode) \
ON_ALL_ACTIONS(ToggleBlockSelection)
ON_ALL_ACTIONS(ToggleBlockSelection) \
ON_ALL_ACTIONS(SwitchSelectionEndpoint)

#define ALL_SHORTCUT_ACTIONS_WITH_ARGS \
ON_ALL_ACTIONS_WITH_ARGS(AdjustFontSize) \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -564,4 +564,7 @@
<data name="ToggleBlockSelectionCommandKey" xml:space="preserve">
<value>Toggle block selection</value>
</data>
<data name="SwitchSelectionEndpointCommandKey" xml:space="preserve">
<value>Switch selection endpoint</value>
</data>
</root>
1 change: 1 addition & 0 deletions src/cascadia/TerminalSettingsModel/defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@
{ "command": "selectAll", "keys": "ctrl+shift+a" },
{ "command": "markMode", "keys": "ctrl+shift+m" },
{ "command": "toggleBlockSelection" },
{ "command": "switchSelectionEndpoint" },

// Scrollback
{ "command": "scrollDown", "keys": "ctrl+shift+down" },
Expand Down

0 comments on commit 7b8a53c

Please sign in to comment.