mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-01 22:12:26 +01:00
✨ proper shift selection in list
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
import 'vs/css!./list';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { isNumber } from 'vs/base/common/types';
|
||||
import { range } from 'vs/base/common/arrays';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
@@ -282,6 +283,28 @@ class MouseController<T> implements IDisposable {
|
||||
this.view.domNode.focus();
|
||||
|
||||
const focus = e.index;
|
||||
|
||||
if (e.shiftKey) {
|
||||
const oldFocus = this.list.getFocus()[0];
|
||||
|
||||
if (oldFocus !== undefined) {
|
||||
const min = Math.min(oldFocus, focus);
|
||||
const max = Math.max(oldFocus, focus);
|
||||
const rangeSelection = range(max + 1, min);
|
||||
const selection = this.list.getSelection();
|
||||
const contiguousRange = getContiguousRangeContaining(disjunction(selection, [oldFocus]), oldFocus);
|
||||
|
||||
if (contiguousRange.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newSelection = disjunction(rangeSelection, relativeComplement(selection, contiguousRange));
|
||||
this.list.setSelection(newSelection);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.list.setFocus([focus]);
|
||||
|
||||
if (platform.isMacintosh ? e.altKey : e.ctrlKey) {
|
||||
@@ -316,6 +339,56 @@ const DefaultOptions: IListOptions<any> = {
|
||||
mouseSupport: true
|
||||
};
|
||||
|
||||
function getContiguousRangeContaining(range: number[], value: number): number[] {
|
||||
const index = range.indexOf(value);
|
||||
|
||||
if (index === -1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const result = [];
|
||||
let i = index - 1;
|
||||
while (i >= 0 && range[i] === value - (index - i)) {
|
||||
result.push(range[i--]);
|
||||
}
|
||||
|
||||
result.reverse();
|
||||
i = index;
|
||||
while (i < range.length && range[i] === value + (i - index)) {
|
||||
result.push(range[i++]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given two sorted collections of numbers, returns the intersection
|
||||
* betweem them (OR).
|
||||
*/
|
||||
function disjunction(one: number[], other: number[]): number[] {
|
||||
const result = [];
|
||||
let i = 0, j = 0;
|
||||
|
||||
while (i < one.length || j < other.length) {
|
||||
if (i >= one.length) {
|
||||
result.push(other[j++]);
|
||||
} else if (j >= other.length) {
|
||||
result.push(one[i++]);
|
||||
} else if (one[i] === other[j]) {
|
||||
result.push(one[i]);
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
} else if (one[i] < other[j]) {
|
||||
result.push(one[i++]);
|
||||
} else {
|
||||
result.push(other[j++]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given two sorted collections of numbers, returns the exclusive
|
||||
* disjunction between them (XOR).
|
||||
@@ -343,6 +416,33 @@ function exclusiveDisjunction(one: number[], other: number[]): number[] {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given two sorted collections of numbers, returns the relative
|
||||
* complement between them (XOR).
|
||||
*/
|
||||
function relativeComplement(one: number[], other: number[]): number[] {
|
||||
const result = [];
|
||||
let i = 0, j = 0;
|
||||
|
||||
while (i < one.length || j < other.length) {
|
||||
if (i >= one.length) {
|
||||
result.push(other[j++]);
|
||||
} else if (j >= other.length) {
|
||||
result.push(one[i++]);
|
||||
} else if (one[i] === other[j]) {
|
||||
i++;
|
||||
j++;
|
||||
continue;
|
||||
} else if (one[i] < other[j]) {
|
||||
result.push(one[i++]);
|
||||
} else {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const numericSort = (a: number, b: number) => a - b;
|
||||
|
||||
export class List<T> implements ISpliceable<T>, IDisposable {
|
||||
|
||||
Reference in New Issue
Block a user