Skip to content

Commit

Permalink
remove mark mode for separate PR (easier discussion)
Browse files Browse the repository at this point in the history
  • Loading branch information
carlos-zamora committed May 8, 2020
1 parent 33e37b1 commit 9fb946d
Showing 1 changed file with 24 additions and 59 deletions.
83 changes: 24 additions & 59 deletions doc/specs/Keyboard-Selection.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
author: Carlos Zamora @cazamor
author: Carlos Zamora @carlos-zamora
created on: 2019-08-30
last updated: 2019-09-21
last updated: 2020-05-7
issue id: #715
---

Expand All @@ -13,15 +13,16 @@ This spec describes a new set of keybindings that allows the user to create and

## Inspiration

ConHost allows the user to edit an existing selection using the keyboard. Holding `Shift` allows the user to move the second selection anchor in accordance with the arrow keys. The selection anchor updates by one cell per key event, allowing the user to refine the selected region.
ConHost allows the user to modify a selection using the keyboard. Holding `Shift` allows the user to move the second selection endpoint in accordance with the arrow keys. The selection anchor updates by one cell per key event, allowing the user to refine the selected region.

Mark mode allows the users to update the selection anchors sequentially, and create a block selection.
Mark mode allows the user to create a selection using only the keyboard. Then edit it as mentioned above.


## Solution Design

The fundamental solution design for keyboard selection is that the responsibilities between the Terminal Control and Terminal Core must be very distinct. The Terminal Control is responsible for handling user interaction and directing the Terminal Core to update the selection. The Terminal Core will need to update the selection according to the preferences of the Terminal Control.


### Fundamental Terminal Control Changes

`TermControl::_KeyDownHandler()` is responsible for interpretting the key events. At the time of writing this spec, there are 3 cases handled in this order:
Expand All @@ -36,11 +37,12 @@ It may seem that some effort can be saved by making the keyboard selection act a

However, the mouse handler operates by translating a pixel coordinate on the screen to a text buffer coordinate. This would have to be rewritten and the approach was deemed unworthy.


### Fundamental Terminal Core Changes

The Terminal Core will need to expose a `KeyboardSelection()` function that is called by the keybinding handler. The following parameters will need to be passed in:
The Terminal Core will need to expose a `MoveSelectionEndpoint()` function that is called by the keybinding handler. The following parameters will need to be passed in:
- `enum Direction`: the direction that the selection anchor will attempt to move to. Possible values include `Up`, `Down`, `Left`, and `Right`.
- `enum SelectionExpansionMode`: the selection expansion mode that the selection anchor will adhere to. Possible values include `Cell`, `Word`, and `Viewport`.
- `enum SelectionExpansionMode`: the selection expansion mode that the selection anchor will adhere to. Possible values include `Cell`, `Word`, `Viewport`, `Buffer`.

For `SelectionExpansionMode = Cell`, the selection anchor will be updated according to the buffer's output pattern. For **horizontal movements**, the selection anchor will attempt to move left or right. If a viewport boundary is hit, the anchor will wrap appropriately (i.e.: hitting the left boundary moves it to the last cell of the line above it).

Expand All @@ -60,35 +62,6 @@ Every combination of the `Direction` and `SelectionExpansionMode` will map to a

**NOTE**: If `copyOnSelect` is enabled, we need to make sure we update the clipboard on every change in selection.

### Mark Mode
Mark Mode is a mode where the user can create more complete and complex selections using only the keyboard. It can be cycled int an enabled/disabled state through a user keybinding (`toggleMarkMode`).

Upon being enabled, the current cursor position becomes the selection anchor. The user can move the selection anchor using the same keybindings defined for keyboard selection (`moveSelectionAnchor` action).

#### `toggleMarkMode`
`toggleMarkMode` has two keybinding arguments:
| Parameter | Accepted Values | Default Value | Description |
|--|--|--|--|
| `anchorKeybinding` | regular keybindings and plain modifier keys | `Shift` | The keybinding used to anchor the selection anchor to it's current text buffer position. While holding down that keybinding, any `moveSelectionAnchor` actions will move the other selection anchor (`endSelectionPosition`). |
| `anchorMode` | `Hold`, `Toggle` | `Hold` | If `Hold`, the user needs to hold the `anchorKeybinding` keybinding to move the second selection anchor. If `Toggle`, the user switches between selection anchors when they press it. |

#### Rendering during Mark Mode
Since we are just moving the selection anchors, rendering the selection rects should operate normally. We need to ensure that we still scroll when we move a selection anchor past the top of bottom of the viewport.

In ConHost, output would be paused when a selection was present. This is a completely separate issue that is being tracked in (#2529)[https://github.com/microsoft/terminal/pull/2529].

#### Exiting Mark Mode
There are multiple ways to exit mark mode. The user can press...
- the `toggleMarkMode` keybinding
- the `ESC` key
- the `copy` keybinding (which also copies the contents of the selection to the user's clipboard)



<!--Holding down the `holdSelectionAnchor` keybinding action (set to `Shift` by default) anchors the selection anchor to it's current text buffer position. While holding down that keybinding, any `moveSelectionAnchor` actions will move the other selection anchor (`endSelectionPosition`).
**NOTE**: `holdSelectionAnchor` will have an `Enum anchorSwitching` parameter. Where `Hold` (default) is the functionality mentioned above, and `Toggle` switches between the selection anchors when pressed.-->


## UI/UX Design

Expand All @@ -97,47 +70,43 @@ There are multiple ways to exit mark mode. The user can press...
Thanks to Keybinding Args, there will only be 4 new commands that need to be added:
| Action | Keybinding Args | Description |
|--|--|--|
| `moveSelectionAnchor` | | If a selection exists, moves the last selection anchor.
| `moveSelectionPoint` | | If a selection exists, moves the last selection anchor.
| | `Enum direction { up, down, left, right}` | The direction the selection will be moved in. |
| | `Enum expansionMode { cell, word, line, viewport, buffer }` | The context for which to move the selection anchor to. (defaults to `cell`)
| `selectEntireBuffer` | | Select the entire text buffer.
| `toggleMarkMode` | | Enter or exit mark mode. This allows you to create an entire selection using only the keyboard. |
| `holdSelectionAnchor` | | Enter or exit mark mode. This allows you to create an entire selection using only the keyboard. |


By default, the following keybindings will be set:
```JS
// Cell Selection
{ "command": { "action": "moveSelectionAnchor", "direction": "down" }, "keys": ["shift+down"] },
{ "command": { "action": "moveSelectionAnchor", "direction": "up" }, "keys": ["shift+up"] },
{ "command": { "action": "moveSelectionAnchor", "direction": "left" }, "keys": ["shift+left"] },
{ "command": { "action": "moveSelectionAnchor", "direction": "right" }, "keys": ["shift+right"] },
{ "command": { "action": "moveSelectionPoint", "direction": "down" }, "keys": ["shift+down"] },
{ "command": { "action": "moveSelectionPoint", "direction": "up" }, "keys": ["shift+up"] },
{ "command": { "action": "moveSelectionPoint", "direction": "left" }, "keys": ["shift+left"] },
{ "command": { "action": "moveSelectionPoint", "direction": "right" }, "keys": ["shift+right"] },

// Word Selection
{ "command": { "action": "moveSelectionAnchor", "direction": "left", "expansionMode": "word" }, "keys": ["ctrl+shift+left"] },
{ "command": { "action": "moveSelectionAnchor", "direction": "right", "expansionMode": "word" }, "keys": ["ctrl+shift+right"] },
{ "command": { "action": "moveSelectionPoint", "direction": "left", "expansionMode": "word" }, "keys": ["ctrl+shift+left"] },
{ "command": { "action": "moveSelectionPoint", "direction": "right", "expansionMode": "word" }, "keys": ["ctrl+shift+right"] },

// Viewport Selection
{ "command": { "action": "moveSelectionAnchor", "direction": "left", "expansionMode": "viewport" }, "keys": ["shift+home"] },
{ "command": { "action": "moveSelectionAnchor", "direction": "right", "expansionMode": "viewport" }, "keys": ["shift+end"] },
{ "command": { "action": "moveSelectionAnchor", "direction": "up", "expansionMode": "viewport" }, "keys": ["ctrl+shift+up"] },
{ "command": { "action": "moveSelectionAnchor", "direction": "down", "expansionMode": "viewport" }, "keys": ["ctrl+shift+down"] },
{ "command": { "action": "moveSelectionPoint", "direction": "left", "expansionMode": "viewport" }, "keys": ["shift+home"] },
{ "command": { "action": "moveSelectionPoint", "direction": "right", "expansionMode": "viewport" }, "keys": ["shift+end"] },
{ "command": { "action": "moveSelectionPoint", "direction": "up", "expansionMode": "viewport" }, "keys": ["ctrl+shift+up"] },
{ "command": { "action": "moveSelectionPoint", "direction": "down", "expansionMode": "viewport" }, "keys": ["ctrl+shift+down"] },

// Buffer Corner Selection
{ "command": { "action": "moveSelectionAnchor", "direction": "up", "expansionMode": "buffer" }, "keys": ["ctrl+shift+home"] },
{ "command": { "action": "moveSelectionAnchor", "direction": "down", "expansionMode": "buffer" }, "keys": ["ctrl+shift+end"] },
{ "command": { "action": "moveSelectionPoint", "direction": "up", "expansionMode": "buffer" }, "keys": ["ctrl+shift+home"] },
{ "command": { "action": "moveSelectionPoint", "direction": "down", "expansionMode": "buffer" }, "keys": ["ctrl+shift+end"] },

// Select All
{ "command": "selectEntireBuffer", "keys": ["ctrl+shift+a"] },

// Mark Mode
{ "command": "toggleMarkMode", "keys": ["ctrl+shift+m"] },
```

## Capabilities

### Accessibility

Being able to create and update a selection without the use of a mouse is a very important feature to users with disabilities. The UI Automation system (particularly with the use of the signaling model), should be aware that a new selection exists. Thus, the bounding rects should be updated and the associated text regions should be reread appropriately.
Using the keyboard is generally a more accessible experience than using the mouse. Being able to modify a selection by using the keyboard is a good first step towards making selecting text more accessible.

### Security

Expand All @@ -161,11 +130,7 @@ The settings model makes all of these features easy to disable, if the user wish

## Future considerations

### Expanding Mark Mode functionality
This spec currently limits mark mode functionality to the following:
- only move by cell (no other expansion modes)
- no rebinding arrow keys allowed
In addition to the `enum direction` and `enum expansionMode` args introduced above, a `bool markMode` arg can be added. If set to `true`, the selection anchor will adjust to these commands when in mark mode. This will allow the selection anchor to be able to be adjusted by different expansion modes.
This functionality will be expanded to create a feature similar to Mark Mode. This will allow a user to create a selection using only the keyboard.


## Resources
Expand Down

1 comment on commit 9fb946d

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New misspellings found, please review:

  • carlos
  • interpretting
  • scenarious
  • windowsdeveloper
  • zamora
To accept these changes, run the following commands
remove_obsolete_words=$(mktemp)
echo '#!/usr/bin/perl -ni
my $re=join "|", qw('"
Emojis
HREF
textblock
usr
vpack
"');
next if /^($re)(?:$| .*)/;
print;' > $remove_obsolete_words
chmod +x $remove_obsolete_words
for file in .github/actions/spell-check/whitelist/alphabet.txt .github/actions/spell-check/whitelist/web.txt .github/actions/spell-check/whitelist/whitelist.txt; do $remove_obsolete_words $file; done
rm $remove_obsolete_words
(
echo "
carlos
href
interpretting
scenarious
windowsdeveloper
zamora
"
) | sort -u -f | perl -ne 'next unless /./; print' > new_whitelist.txt && mv new_whitelist.txt '.github/actions/spell-check/whitelist/9fb946d305315ee6a86e4fda7237c3cbae579bd3.txt'
✏️ Contributor please read this
  • If the items listed above are names, please add them to .github/actions/spell-check/dictionary/names.txt.
  • If they're APIs, you can add them to a file in .github/actions/spell-check/dictionary/.
  • If they're just things you're using, please add them to an appropriate file in .github/actions/spell-check/whitelist/.
  • If you need to use a specific token in one place and it shouldn't generally be used, you can
    add an item in an appropriate file in .github/actions/spell-check/patterns/.

See the README.md in each directory for more information.

⚠️ Reviewers

At present, the action that triggered this message will not show its ❌ in this PR unless the branch is within this repository.
Thus, you should make sure that this comment has been addressed before encouraging the merge bot to merge this PR.

Please sign in to comment.