Repository: microsoft/vscode (TypeScript)
Date: 2022-09-07 18:35:50+00:00
Task type: Bug Fix

Issue:
Unselecting selection among multi-selection and pressing DEL delete latest unselected item
<!-- ⚠️⚠️ Do Not Delete This! bug_report_template ⚠️⚠️ -->
<!-- Please read our Rules of Conduct: https://opensource.microsoft.com/codeofconduct/ -->
<!-- Please search existing issues to avoid creating duplicates. -->
<!-- Also please test using the latest insiders build to make sure your issue has not already been fixed: https://code.visualstudio.com/insiders/ -->

<!-- Use Help > Report Issue to prefill these. -->
Version: 1.50.1 (user setup)
Commit: d2e414d9e4239a252d1ab117bd7067f125afd80a
Date: 2020-10-13T15:06:15.712Z
Electron: 9.2.1
Chrome: 83.0.4103.122
Node.js: 12.14.1
V8: 8.3.110.13-electron.0
OS: Windows_NT x64 10.0.19041


Steps to Reproduce:

1. Open a project/workspace with multiple files
2. Select a range of files using SHIFT modifier
3. Use CTRL modifier to unselect one file from current selection
4. Press DEL to delete selection
5. A confirmation to delete will prompt about deleting the latest unselected file
6. Finally the unselected file is deleted

<!-- Launch with `code --disable-extensions` to check. -->
Does this issue occur when all extensions are disabled?: Yes


Issue discussion:
(Experimental duplicate detection)
Thanks for submitting this issue. Please also check if it is already covered by an existing one, like:
- [Allow un-selecting an item in a contributed tree (#48754)](https://www.github.com/microsoft/vscode/issues/48754) <!-- score: 0.507 -->
<!-- potential_duplicates_comment -->
Yeah this is as designed. We always execute explorer commands on focused items, not on selected. Selection is respected only if focus belongs to it.
I see how in some cases this is not intuitive. However for now we would not change this.
This imo is really bad and I was bitten by it by deleting the exact thing I wished to NOT delete. The `del` shortcut should go with the selection (if there is any) over the focused item.
@eamodio but then do you argue that all commands in the explorer should just go with the selection, or only the delete one?
Does this hold when triggering via keyboard, context menu, command palette or always?
Why would someone select files without intention to act on them?
I have been having this issue, and I am hoping this gets fixed soon.

https://i.gyazo.com/51178dd63daef7bb9fa451c521ce8795.mp4

1. shift + DOWN to select files
2. control (or command) + CLICK to deselect a file
3. control (or command) + DELETE to delete the files

*don't click anywhere else between 2 and 3

I was just bitten by this and had to dig up the victim from the trash, so I took the time to understand what had happened and figured out this behaviour. Now I realize it already had happened when copy/pasting files, whithout me investigating since it was less problematic. 

> @eamodio but then do you argue that all commands in the explorer should just go with the selection, or only the delete one? Does this hold when triggering via keyboard, context menu, command palette or always?

So I don't know if there's any other command than these, but I think selection should be used over focus when present, since as @mystiquewolf perfectly worded it:

> Why would someone select files without intention to act on them?



Solution patch:
diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts
--- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts
+++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts
@@ -108,6 +108,11 @@ export function getContext(focus: ExplorerItem[], selection: ExplorerItem[], res
 	let focusedStat: ExplorerItem | undefined;
 	focusedStat = focus.length ? focus[0] : undefined;
 
+	// If we are respecting multi-select and we have a multi-selection we ignore focus as we want to act on the selection
+	if (respectMultiSelection && selection.length > 1) {
+		focusedStat = undefined;
+	}
+
 	const compressedNavigationController = focusedStat && compressedNavigationControllerProvider.getCompressedNavigationController(focusedStat);
 	focusedStat = compressedNavigationController ? compressedNavigationController.current : focusedStat;
 


Test patch:
diff --git a/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts b/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts
--- a/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts
+++ b/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts
@@ -34,7 +34,7 @@ suite('Files - ExplorerView', () => {
 		const s4 = createStat.call(this, '/path/to/stat', 'stat', false, false, 8096, d);
 		const noNavigationController = { getCompressedNavigationController: (stat: ExplorerItem) => undefined };
 
-		assert.deepStrictEqual(getContext([s1], [s2, s3, s4], true, noNavigationController), [s1]);
+		assert.deepStrictEqual(getContext([s1], [s2, s3, s4], true, noNavigationController), [s2, s3, s4]);
 		assert.deepStrictEqual(getContext([s1], [s1, s3, s4], true, noNavigationController), [s1, s3, s4]);
 		assert.deepStrictEqual(getContext([s1], [s3, s1, s4], false, noNavigationController), [s1]);
 		assert.deepStrictEqual(getContext([], [s3, s1, s4], false, noNavigationController), []);