Change:
<ins> /*--------------------------------------------------------------------------------------------- *  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import 'vs/css!./anchorSelect'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { Selection } from 'vs/editor/common/core/selection'; import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { TrackedRangeStickiness } from 'vs/editor/common/model'; import { MarkdownString } from 'vs/base/common/htmlContent'; import { IDisposable } from 'vs/base/common/lifecycle'; export const SelectionAnchorSet = new RawContextKey('selectionAnchorSet', false); class SelectionAnchorController implements IEditorContribution { public static readonly ID = 'editor.contrib.selectionAnchorController'; static get(editor: ICodeEditor): SelectionAnchorController { return editor.getContribution<SelectionAnchorController>(SelectionAnchorController.ID); } private decorationId: string | undefined; private selectionAnchorSetContextKey: IContextKey<boolean>; private modelChangeListener: IDisposable; constructor( private editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService ) { this.selectionAnchorSetContextKey = SelectionAnchorSet.bindTo(contextKeyService); this.modelChangeListener = editor.onDidChangeModel(() => this.selectionAnchorSetContextKey.reset()); } setSelectionAnchor(): void { if (this.editor.hasModel()) { const position = this.editor.getPosition(); const previousDecorations = this.decorationId ? [this.decorationId] : []; const newDecorationId = this.editor.deltaDecorations(previousDecorations, [{ range: Selection.fromPositions(position, position), options: { stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, hoverMessage: new MarkdownString().appendText(localize('selectionAnchor', "Selection Anchor")), className: 'selection-anchor' } }]); this.decorationId = newDecorationId[0]; this.selectionAnchorSetContextKey.set(!!this.decorationId); } } goToSelectionAnchor(): void { if (this.editor.hasModel() && this.decorationId) { const anchorPosition = this.editor.getModel().getDecorationRange(this.decorationId); if (anchorPosition) { this.editor.setPosition(anchorPosition.getStartPosition()); } } } selectFromAnchorToCursor(): void { if (this.editor.hasModel() && this.decorationId) { const start = this.editor.getModel().getDecorationRange(this.decorationId); if (start) { const end = this.editor.getPosition(); this.editor.setSelection(Selection.fromPositions(start.getStartPosition(), end)); this.cancelSelectionAnchor(); } } } cancelSelectionAnchor(): void { if (this.decorationId) { this.editor.deltaDecorations([this.decorationId], []); this.decorationId = undefined; this.selectionAnchorSetContextKey.set(false); } } dispose(): void { this.cancelSelectionAnchor(); this.modelChangeListener.dispose(); } } class SetSelectionAnchor extends EditorAction { constructor() { super({ id: 'editor.action.setSelectionAnchor', label: localize('setSelectionAnchor', "Set Selection Anchor"), alias: 'Set Selection Anchor', precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_B), weight: KeybindingWeight.EditorContrib } }); } async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> { const controller = SelectionAnchorController.get(editor); controller.setSelectionAnchor(); } } class GoToSelectionAnchor extends EditorAction { constructor() { super({ id: 'editor.action.goToSelectionAnchor', label: localize('goToSelectionAnchor', "Go to Selection Anchor"), alias: 'Go to Selection Anchor', precondition: SelectionAnchorSet, }); } async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> { const controller = SelectionAnchorController.get(editor); controller.goToSelectionAnchor(); } } class SelectFromAnchorToCursor extends EditorAction { constructor() { super({ id: 'editor.action.selectFromAnchorToCursor', label: localize('selectFromAnchorToCursor', "Select from Anchor to Cursor"), alias: 'Select from Anchor to Cursor', precondition: SelectionAnchorSet, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_K), weight: KeybindingWeight.EditorContrib } }); } async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> { const controller = SelectionAnchorController.get(editor); controller.selectFromAnchorToCursor(); } } class CancelSelectionAnchor extends EditorAction { constructor() { super({ id: 'editor.action.cancelSelectionAnchor', label: localize('cancelSelectionAnchor', "Cancel Selection Anchor"), alias: 'Cancel Selection Anchor', precondition: SelectionAnchorSet, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyCode.Escape, weight: KeybindingWeight.EditorContrib } }); } async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> { const controller = SelectionAnchorController.get(editor); controller.cancelSelectionAnchor(); } } registerEditorContribution(SelectionAnchorController.ID, SelectionAnchorController); registerEditorAction(SetSelectionAnchor); registerEditorAction(GoToSelectionAnchor); registerEditorAction(SelectFromAnchorToCursor); registerEditorAction(CancelSelectionAnchor); </ins>

Discussion:
<!-- Do Not Delete This! featurerequesttemplate --<!-- Please read our Rules of Conduct: --<!-- Please search existing issues to avoid creating duplicates. --<!-- Describe the feature you'd like. --The way selection currently works in VS Code requires you to hold down the shift key while holding down the arrow keys or using "Home", "End" and other such keys to contiguously select blocks of text/code. While this works for most cases, this can become rather cumbersome for screen reader users when large amounts of code need to be acted on at once, e.g. copied, deleted etc. The main cause of this is that screen readers pretty much require keyboard shortcuts to be used to get anything done. Quickly checking down a few lines (screen readers only see one line at a time), checking context, various other things are pretty much impossible while you are trying to select a large piece of code. This is especially painful, for example, when you have a large amount of dummy HTML that needs to be replaced by a dynamic loop. Checking if you managed to get 6 levels worth of nested divs rather than that one outer div you didn't mean to highlight becomes an exercise in frustration. A way around this problem is to, rather than depend on a held down key for contiguous selection, use a single keypress to mark the beginning and another to mark the end of the wanted selection. Once both points are set, the text in between those points is highlighted and can then be acted on. This frees the keyboard up to , for example, move around the file, etc. without ever losing your selection requested to be notified of this feature request being created.
I think this makes sense in general, to add a "Start selection" command and "End selection". Assigning to me and I might have time in May to look into this, thus assinging to that milestone for now. if you have code pointers or any preferences do let me know
well makes sense to me, although there are features like expand selection etc. I also have problems with selecting nested blocks etc, and expand selection seems to work for this case, although I'd say you have to be a bit careful to verify what it's selecting.
For an example of an implementation of this look at notepad++. Begin/end selection is an option in the context menu when in a file.

I find this very useful when needing to copy large blocks of text.
This feature is my consumer dream in any and every editor I use. Selecting a very large block of text using a screen reader is not very comfortable. If it is possible to implement a command that allows you to jump to the beginning and end of the selected block, it will also be very useful.
well currently I am learning to do it this way: point at the beginning of, say, an if. select the whole line and next one because of the brace (in c# brace is usually below the if) and then use the expand selection feature, your selection should expand to the closing brace of this exact block.
If it gets implemented then it will be very beneficial for productivity.
The one old standard - used to use it in things like visual interdev and VS.Net 2005, etc., if remember correctly was purely F8 to mark start of selection, and then navigate around code however you like, and then hit shift + F8, and it would mark the whole block from start marker to end marker
yeah. unfortunately f8 is taken. :) Also I prefer shortcuts without function keys as they are quite far in the kbd.
Thanks for feedback and yes it will behave just like that: One command to start selection, another command to end selection. I am not sure if there will be a good feault keyboard shortcut, I will try to find something with F8 in the mix. Like Ctrl + F8 to start, Cltr + Shift + F8 to stop. This can be customisable so any user can put whatever he likes.
Hahah, when I was very young, in the late 1980s, there was this program under both MS-DOS and CP/M called . It had layered keyboard commands, and two of them were CTRL+K, b to mark the start, and CTRL+K, k to mark an end of a block. This was the old equivalent of text selection. Borland's Turbo Pascal 3.0, the first true IDE I used, had a similar command set, which made the learning curve very flat. :-) I noticed immediately that CTRL+K is used for several layered commands in VS Code as well, so we could maybe leverage that.

Yeah it might make sense to use the same command actually and the same shortcut so it is just a toggle, would make the whole thing more simple. Since why would you start a selection if you are already in a selection? So ctrl+k then something is the way to go.
The one small, not too important reason why some people might like to have separate commands would be if they'd initialised selection, and, marked the starting point, but, now wanted to shift it to somewhere else. Wouldn't really cause issues, but, they'd then need to do something like ctrl +K, move to next point, ctrl +K, and then ctrl +K to re-mark it as start? Jacob Kruger
I was thinking the same thing. The separate commands for start and end selection do make sense for the case where one needs to be adjusted multiple times.
Ok makes sense, two seperate commands it is. Thanks for feedback.
Implementation wise, I also think this could be implemented with two commands. The first one would be "set selection anchor" and would add an editor decoration at the current position. Using a decoration would make sure that the anchor stays with the surrounding text even if there are edits in the file. The second one, "select from anchor to position" would read up that decoration and create a selection in between. A third command could be as well, "jump to anchor", which might be helpful to kind of "save a position" and then go reading around, and then jump back to it. Not sure if that would be useful, just a thought.
Oh I could totally see myself use this a lot of times! A big for that!
good idea to use the decoration as an implementation detail. And the "Go to anchor" command makes a lot of sense. My idea for command naming: "Mark Start of Selection" "Mark End of Selection" "Go to Selection Mark" Ideas on naming welcome. I can look into this next week.
Me too! It seems to me that it would be very interesting if we could easily jump to the beginning or end of the selected text.
Ok, I plan to create a And will introduce following 3 editor commands as you suggested (with a slight modification): "Set Selection Anchor", "Select From Anchor to Cursor", "Go to Selection Anchor" The only alternative name I have is to use "Mark" instead of "Anchor".

Though Anchor works fine for me, I like it for its uniqueness. Feedback on naming very welcome
We have introduced three commands: "Set Selection Anchor" Ctrl+k, Ctrl+b "Select From Anchor to Cursor" Ctrl+k, Ctrl+k "Cancel Selection Anchor" escape "Go to Selection Anchor" no default keybinding Please try it out in VS Code insiders from Tuesday and let us know how it behaves for you.
Also please provide feedback if you would like confirmation once the anchor is set. Should we announce "Selection Anchor Set"?
Probably " Anchor placed" or similar would be good to announce, just something short. It would also be good to be notified when you encounter the anchor while arrowing through the document, but at that point we get back to announcing errors, lightbulbs and other ornaments on a per-line basis :)
Yup, agree with what said.
Thanks for feedback. We now announce "Anchor set". As for reading it once you encounter it, yes this goes in the same bag of announcing errors, lighbulbs and other. For that we first need this
It seems that the announcement "anchor set" only happens the first time that the command "Set Selection Anchor" is used. From the second time on, nothing is announced by the orca.
thanks for feedback. The issue here is that we update the aria-live region, from "anchor set" to again "anchor set". Orca does not see detect difference in the content and does not read anything. do you have some recommendation what should we do here if we want some message to be re-read multiple times? In theory we could create a new live container, but that feels clunky.
And if the command also announced the position? Something like that: anchor set at line 1 column 10. or anchor set at 1:10
that would fix it. Good suggestion. Let me push that change.
I have pushed a fix for this as you suggested, try it out from Thursdays vscode insiders and let me know what you think.
It was great, thanks.
This works amazingly well, thank you! I was trying to use the "Go to Selection Anchor" command without setting a keystroke by using it from the quick picker. But it doesn't show up when I search for anchor.

My bad, I just realized that the command list is smart enough to not offer that as an option if no anchor is present.
yeah, we only show the command when it is applicable - when an anchor was set.
Can't we start selection automatically after command "Set Selection Anchor"? This way we won't need to use "Select From Anchor to Cursor" at all.
can you sketch outthe exact scenario? I fail to see what you mean exactly. Right now you set the anchor, then scroll down to where you want your selection to end and select from anchor to cursor. So placing an anchor in a sense already starts selection. Starting to highlight from starting the anchor sort of defeats thepurpose a bit for the initial feature request, I think
Current implementation: Set Anchor -Move cursor somewhere -Select From Anchor To Cursor -Copy/Cut/Delete Proposal: Set Anchor -Move cursor somewhere -Copy/Cut/Delete But now I get your point that this won't work for screen reader so it should be separate feature.
Agree with . The purpose was to reduce the verbiage screen readers issue when text is being selected. Also, not having the selection indicator on the braille display certainly helps with quickly finding the end point of the selection, before actually making it.
thanks for the suggestion, but as and point out the current approach has more upside.