Merge from vscode 8df646d3c5477b02737fc10343fa7cf0cc3f606b

This commit is contained in:
ADS Merger
2020-03-25 06:20:54 +00:00
parent 6e5fbc9012
commit d810da9d87
114 changed files with 2036 additions and 797 deletions

View File

@@ -5,7 +5,7 @@
@font-face {
font-family: "codicon";
src: url("./codicon.ttf?fb4c14f317e1decb0289895ecc9356f0") format("truetype");
src: url("./codicon.ttf?3d9ee7d873425ff0bc441f48a1de0c54") format("truetype");
}
.codicon[class*='codicon-'] {
@@ -420,4 +420,7 @@
.codicon-bell-dot:before { content: "\f102" }
.codicon-debug-alt-2:before { content: "\f103" }
.codicon-debug-alt:before { content: "\f104" }
.codicon-run-all:before { content: "\f105" }
.codicon-debug-console:before { content: "\f105" }
.codicon-library:before { content: "\f106" }
.codicon-output:before { content: "\f107" }
.codicon-run-all:before { content: "\f108" }

View File

@@ -275,6 +275,12 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
this.layout();
}
updateOptions(options: IListViewOptions<T>) {
if (options.additionalScrollHeight !== undefined) {
this.additionalScrollHeight = options.additionalScrollHeight;
}
}
triggerScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) {
this.scrollableElement.triggerScrollFromMouseWheelEvent(browserEvent);
}

View File

@@ -854,6 +854,7 @@ export interface IListOptions<T> {
readonly mouseSupport?: boolean;
readonly horizontalScrolling?: boolean;
readonly ariaProvider?: IAriaProvider<T>;
readonly additionalScrollHeight?: number;
}
export interface IListStyles {
@@ -1110,6 +1111,7 @@ class ListViewDragAndDrop<T> implements IListViewDragAndDrop<T> {
export interface IListOptionsUpdate {
readonly enableKeyboardNavigation?: boolean;
readonly automaticKeyboardNavigation?: boolean;
readonly additionalScrollHeight?: number;
}
export class List<T> implements ISpliceable<T>, IDisposable {
@@ -1289,6 +1291,10 @@ export class List<T> implements ISpliceable<T>, IDisposable {
if (this.typeLabelController) {
this.typeLabelController.updateOptions(this._options);
}
if (optionsUpdate.additionalScrollHeight !== undefined) {
this.view.updateOptions(optionsUpdate);
}
}
get options(): IListOptions<T> {

View File

@@ -110,7 +110,7 @@ abstract class ViewItem<TLayoutContext> {
get snap(): boolean { return !!this.view.snap; }
set enabled(enabled: boolean) {
this.container.style.pointerEvents = enabled ? null : 'none';
this.container.style.pointerEvents = enabled ? '' : 'none';
}
constructor(

View File

@@ -791,7 +791,7 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
this.refreshPromises.set(node, result);
return result.finally(() => this.refreshPromises.delete(node));
return result.finally(() => { this.refreshPromises.delete(node); });
}
private _onDidChangeCollapseState({ node, deep }: ICollapseStateChangeEvent<IAsyncDataTreeNode<TInput, T> | null, any>): void {

View File

@@ -28,11 +28,17 @@ export class HistoryNavigator<T> implements INavigator<T> {
}
public next(): T | null {
return this._navigator.next();
if (this._currentPosition() !== this._elements.length - 1) {
return this._navigator.next();
}
return null;
}
public previous(): T | null {
return this._navigator.previous();
if (this._currentPosition() !== 0) {
return this._navigator.previous();
}
return null;
}
public current(): T | null {
@@ -73,6 +79,15 @@ export class HistoryNavigator<T> implements INavigator<T> {
}
}
private _currentPosition(): number {
const currentElement = this._navigator.current();
if (!currentElement) {
return -1;
}
return this._elements.indexOf(currentElement);
}
private _initialize(history: readonly T[]): void {
this._history = new Set();
for (const entry of history) {

View File

@@ -5,7 +5,7 @@
import * as extpath from 'vs/base/common/extpath';
import * as paths from 'vs/base/common/path';
import { URI, originalFSPath as uriOriginalFSPath } from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { equalsIgnoreCase } from 'vs/base/common/strings';
import { Schemas } from 'vs/base/common/network';
import { isLinux, isWindows } from 'vs/base/common/platform';
@@ -13,7 +13,28 @@ import { CharCode } from 'vs/base/common/charCode';
import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob';
import { TernarySearchTree } from 'vs/base/common/map';
export const originalFSPath = uriOriginalFSPath;
export function originalFSPath(uri: URI): string {
let value: string;
const uriPath = uri.path;
if (uri.authority && uriPath.length > 1 && uri.scheme === 'file') {
// unc path: file://shares/c$/far/boo
value = `//${uri.authority}${uriPath}`;
} else if (
isWindows
&& uriPath.charCodeAt(0) === CharCode.Slash
&& extpath.isWindowsDriveLetter(uriPath.charCodeAt(1))
&& uriPath.charCodeAt(2) === CharCode.Colon
) {
value = uriPath.substr(1);
} else {
// other path
value = uriPath;
}
if (isWindows) {
value = value.replace(/\//g, '\\');
}
return value;
}
/**
* Creates a key from a resource URI to be used to resource comparison and for resource maps.
@@ -24,7 +45,7 @@ export function getComparisonKey(resource: URI, caseInsensitivePath = hasToIgnor
if (caseInsensitivePath) {
path = path.toLowerCase();
}
return `${resource.scheme}://${resource.authority.toLowerCase()}/${path}?${resource.query}`;
return resource.with({ authority: resource.authority.toLowerCase(), path: path, fragment: null }).toString();
}
export function hasToIgnoreCase(resource: URI | undefined): boolean {
@@ -123,7 +144,15 @@ export function dirname(resource: URI): URI {
* @returns The resulting URI.
*/
export function joinPath(resource: URI, ...pathFragment: string[]): URI {
return URI.joinPaths(resource, ...pathFragment);
let joinedPath: string;
if (resource.scheme === 'file') {
joinedPath = URI.file(paths.join(originalFSPath(resource), ...pathFragment)).path;
} else {
joinedPath = paths.posix.join(resource.path || '/', ...pathFragment);
}
return resource.with({
path: joinedPath
});
}
/**

View File

@@ -6,7 +6,6 @@
import { isWindows } from 'vs/base/common/platform';
import { CharCode } from 'vs/base/common/charCode';
import * as paths from 'vs/base/common/path';
import * as extpath from 'vs/base/common/extpath';
const _schemePattern = /^\w[\w\d+.-]*$/;
const _singleSlashStart = /^\//;
@@ -206,7 +205,7 @@ export class URI implements UriComponents {
// if (this.scheme !== 'file') {
// console.warn(`[UriError] calling fsPath with scheme ${this.scheme}`);
// }
return _makeFsPath(this);
return _makeFsPath(this, false);
}
// ---- modify to new -------------------------
@@ -340,20 +339,21 @@ export class URI implements UriComponents {
/**
* Join a URI path with path fragments and normalizes the resulting path.
*
* @param resource The input URI.
* @param uri The input URI.
* @param pathFragment The path fragment to add to the URI path.
* @returns The resulting URI.
*/
static joinPaths(resource: URI, ...pathFragment: string[]): URI {
let joinedPath: string;
if (resource.scheme === 'file') {
joinedPath = URI.file(paths.join(originalFSPath(resource), ...pathFragment)).path;
} else {
joinedPath = paths.posix.join(resource.path || '/', ...pathFragment);
static joinPath(uri: URI, ...pathFragment: string[]): URI {
if (!uri.path) {
throw new Error(`[UriError]: cannot call joinPaths on URI without path`);
}
return resource.with({
path: joinedPath
});
let newPath: string;
if (isWindows && uri.scheme === 'file') {
newPath = URI.file(paths.win32.join(_makeFsPath(uri, true), ...pathFragment)).path;
} else {
newPath = paths.posix.join(uri.path, ...pathFragment);
}
return uri.with({ path: newPath });
}
// ---- printing/externalize ---------------------------
@@ -421,7 +421,7 @@ class _URI extends URI {
get fsPath(): string {
if (!this._fsPath) {
this._fsPath = _makeFsPath(this);
this._fsPath = _makeFsPath(this, false);
}
return this._fsPath;
}
@@ -577,7 +577,7 @@ function encodeURIComponentMinimal(path: string): string {
/**
* Compute `fsPath` for the given uri
*/
function _makeFsPath(uri: URI): string {
function _makeFsPath(uri: URI, keepDriveLetterCasing: boolean): string {
let value: string;
if (uri.authority && uri.path.length > 1 && uri.scheme === 'file') {
@@ -589,7 +589,11 @@ function _makeFsPath(uri: URI): string {
&& uri.path.charCodeAt(2) === CharCode.Colon
) {
// windows drive letter: file:///c:/far/boo
value = uri.path[1].toLowerCase() + uri.path.substr(2);
if (!keepDriveLetterCasing) {
value = uri.path[1].toLowerCase() + uri.path.substr(2);
} else {
value = uri.path.substr(1, 2);
}
} else {
// other path
value = uri.path;
@@ -695,29 +699,3 @@ function percentDecode(str: string): string {
}
return str.replace(_rEncodedAsHex, (match) => decodeURIComponentGraceful(match));
}
// --- utils
export function originalFSPath(uri: URI): string {
let value: string;
const uriPath = uri.path;
if (uri.authority && uriPath.length > 1 && uri.scheme === 'file') {
// unc path: file://shares/c$/far/boo
value = `//${uri.authority}${uriPath}`;
} else if (
isWindows
&& uriPath.charCodeAt(0) === CharCode.Slash
&& extpath.isWindowsDriveLetter(uriPath.charCodeAt(1))
&& uriPath.charCodeAt(2) === CharCode.Colon
) {
value = uriPath.substr(1);
} else {
// other path
value = uriPath;
}
if (isWindows) {
value = value.replace(/\//g, '\\');
}
return value;
}

View File

@@ -526,7 +526,7 @@ export class ChannelClient implements IChannelClient, IDisposable {
this.activeRequests.add(disposable);
});
return result.finally(() => this.activeRequests.delete(disposable));
return result.finally(() => { this.activeRequests.delete(disposable); });
}
private requestEvent(channelName: string, name: string, arg?: any): Event<any> {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/quickInput';
import { IQuickPickItem, IPickOptions, IInputOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInput, IQuickInputButton, IInputBox, IQuickPickItemButtonEvent, QuickPickInput, IQuickPickSeparator, IKeyMods, IQuickPickAcceptEvent, NO_KEY_MODS } from 'vs/base/parts/quickinput/common/quickInput';
import { IQuickPickItem, IPickOptions, IInputOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInput, IQuickInputButton, IInputBox, IQuickPickItemButtonEvent, QuickPickInput, IQuickPickSeparator, IKeyMods, IQuickPickAcceptEvent, NO_KEY_MODS, ItemActivation } from 'vs/base/parts/quickinput/common/quickInput';
import * as dom from 'vs/base/browser/dom';
import { CancellationToken } from 'vs/base/common/cancellation';
import { QuickInputList, QuickInputListFocus } from './quickInputList';
@@ -20,11 +20,9 @@ import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import Severity from 'vs/base/common/severity';
import { ActionBar, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action } from 'vs/base/common/actions';
import { URI } from 'vs/base/common/uri';
import { equals } from 'vs/base/common/arrays';
import { TimeoutTimer } from 'vs/base/common/async';
import { getIconClass } from 'vs/base/parts/quickinput/browser/quickInputUtils';
import { registerAndGetAmdImageURL } from 'vs/base/common/amd';
import { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list';
import { List, IListOptions, IListStyles } from 'vs/base/browser/ui/list/listWidget';
import { IInputBoxStyles } from 'vs/base/browser/ui/inputbox/inputBox';
@@ -70,10 +68,7 @@ const $ = dom.$;
type Writeable<T> = { -readonly [P in keyof T]: T[P] };
const backButton = {
iconPath: {
dark: URI.parse(registerAndGetAmdImageURL('vs/base/parts/quickinput/browser/media/arrow-left-dark.svg')),
light: URI.parse(registerAndGetAmdImageURL('vs/base/parts/quickinput/browser/media/arrow-left-light.svg'))
},
iconClass: 'codicon-arrow-left',
tooltip: localize('quickInput.back', "Back"),
handle: -1 // TODO
};
@@ -391,7 +386,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
private _matchOnLabel = true;
private _sortByLabel = true;
private _autoFocusOnList = true;
private _autoFocusSecondEntry = false;
private _itemActivation = ItemActivation.FIRST;
private _activeItems: T[] = [];
private activeItemsUpdated = false;
private activeItemsToConfirm: T[] | null = [];
@@ -527,12 +522,12 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
this.update();
}
get autoFocusSecondEntry() {
return this._autoFocusSecondEntry;
get itemActivation() {
return this._itemActivation;
}
set autoFocusSecondEntry(autoFocusSecondEntry: boolean) {
this._autoFocusSecondEntry = autoFocusSecondEntry;
set itemActivation(itemActivation: ItemActivation) {
this._itemActivation = itemActivation;
}
get activeItems() {
@@ -879,11 +874,18 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
this.ui.checkAll.checked = this.ui.list.getAllVisibleChecked();
this.ui.visibleCount.setCount(this.ui.list.getVisibleCount());
this.ui.count.setCount(this.ui.list.getCheckedCount());
if (this._autoFocusSecondEntry) {
this.ui.list.focus(QuickInputListFocus.Second);
this._autoFocusSecondEntry = false; // only valid once, then unset
} else {
this.trySelectFirst();
switch (this._itemActivation) {
case ItemActivation.SECOND:
this.ui.list.focus(QuickInputListFocus.Second);
this._itemActivation = ItemActivation.FIRST; // only valid once, then unset
break;
case ItemActivation.LAST:
this.ui.list.focus(QuickInputListFocus.Last);
this._itemActivation = ItemActivation.FIRST; // only valid once, then unset
break;
default:
this.trySelectFirst();
break;
}
}
if (this.ui.container.classList.contains('show-checkboxes') !== !!this.canSelectMany) {

View File

@@ -496,7 +496,7 @@ export class QuickInputList {
}
set enabled(value: boolean) {
this.list.getHTMLElement().style.pointerEvents = value ? null : 'none';
this.list.getHTMLElement().style.pointerEvents = value ? '' : 'none';
}
focus(what: QuickInputListFocus): void {

View File

@@ -182,6 +182,12 @@ export interface IQuickPickAcceptEvent {
inBackground: boolean;
}
export enum ItemActivation {
FIRST = 1,
SECOND,
LAST
}
export interface IQuickPick<T extends IQuickPickItem> extends IQuickInput {
value: string;
@@ -237,20 +243,17 @@ export interface IQuickPick<T extends IQuickPickItem> extends IQuickInput {
autoFocusOnList: boolean;
/**
* If enabled, will try to select the second entry of the picks
* once they appear instead of the first one. This is useful
* e.g. when `quickNavigate` is enabled to be able to select
* a previous entry by just releasing the quick nav keys.
*/
autoFocusSecondEntry: boolean;
quickNavigate: IQuickNavigateConfiguration | undefined;
activeItems: ReadonlyArray<T>;
readonly onDidChangeActive: Event<T[]>;
/**
* Allows to control which entry should be activated by default.
*/
itemActivation: ItemActivation;
selectedItems: ReadonlyArray<T>;
readonly onDidChangeSelection: Event<T[]>;

View File

@@ -106,6 +106,40 @@ suite('History Navigator', () => {
assert.deepEqual(['2', '3', '1'], toArray(testObject));
});
test('previous returns null if the current position is the first one', () => {
const testObject = new HistoryNavigator(['1', '2', '3']);
testObject.first();
assert.deepEqual(testObject.previous(), null);
});
test('previous returns object if the current position is not the first one', () => {
const testObject = new HistoryNavigator(['1', '2', '3']);
testObject.first();
testObject.next();
assert.deepEqual(testObject.previous(), '1');
});
test('next returns null if the current position is the last one', () => {
const testObject = new HistoryNavigator(['1', '2', '3']);
testObject.last();
assert.deepEqual(testObject.next(), null);
});
test('next returns object if the current position is not the last one', () => {
const testObject = new HistoryNavigator(['1', '2', '3']);
testObject.last();
testObject.previous();
assert.deepEqual(testObject.next(), '3');
});
test('clear', () => {
const testObject = new HistoryNavigator(['a', 'b', 'c']);
assert.equal(testObject.previous(), 'c');

View File

@@ -503,4 +503,65 @@ suite('URI', () => {
// }
// console.profileEnd();
});
function assertJoined(base: string, fragment: string, expected: string, checkWithUrl: boolean = true) {
const baseUri = URI.parse(base);
const newUri = URI.joinPath(baseUri, fragment);
const actual = newUri.toString(true);
assert.equal(actual, expected);
if (checkWithUrl) {
const actualUrl = new URL(fragment, base).href;
assert.equal(actualUrl, expected, 'DIFFERENT from URL');
}
}
test('URI#joinPath', function () {
assertJoined(('file:///foo/'), '../../bazz', 'file:///bazz');
assertJoined(('file:///foo'), '../../bazz', 'file:///bazz');
assertJoined(('file:///foo'), '../../bazz', 'file:///bazz');
assertJoined(('file:///foo/bar/'), './bazz', 'file:///foo/bar/bazz');
assertJoined(('file:///foo/bar'), './bazz', 'file:///foo/bar/bazz', false);
assertJoined(('file:///foo/bar'), 'bazz', 'file:///foo/bar/bazz', false);
// "auto-path" scheme
assertJoined(('file:'), 'bazz', 'file:///bazz');
assertJoined(('http://domain'), 'bazz', 'http://domain/bazz');
assertJoined(('https://domain'), 'bazz', 'https://domain/bazz');
assertJoined(('http:'), 'bazz', 'http:/bazz', false);
assertJoined(('https:'), 'bazz', 'https:/bazz', false);
// no "auto-path" scheme with and w/o paths
assertJoined(('foo:/'), 'bazz', 'foo:/bazz');
assertJoined(('foo://bar/'), 'bazz', 'foo://bar/bazz');
// no "auto-path" + no path -> error
assert.throws(() => assertJoined(('foo:'), 'bazz', ''));
assert.throws(() => new URL('bazz', 'foo:'));
assert.throws(() => assertJoined(('foo://bar'), 'bazz', ''));
assert.throws(() => new URL('bazz', 'foo://bar'));
});
test('URI#joinPath (posix)', function () {
if (isWindows) {
this.skip();
}
assertJoined(('file:///c:/foo/'), '../../bazz', 'file:///bazz', false);
assertJoined(('file://server/share/c:/'), '../../bazz', 'file://server/bazz', false);
assertJoined(('file://server/share/c:'), '../../bazz', 'file://server/bazz', false);
assertJoined(('file://ser/foo/'), '../../bazz', 'file://ser/bazz');
assertJoined(('file://ser/foo'), '../../bazz', 'file://ser/bazz');
});
test('URI#joinPath (windows)', function () {
if (!isWindows) {
this.skip();
}
assertJoined(('file:///c:/foo/'), '../../bazz', 'file:///c:/bazz', false);
assertJoined(('file://server/share/c:/'), '../../bazz', 'file://server/share/bazz', false);
assertJoined(('file://server/share/c:'), '../../bazz', 'file://server/share/bazz', false);
assertJoined(('file://ser/foo/'), '../../bazz', 'file://ser/foo/bazz', false);
assertJoined(('file://ser/foo'), '../../bazz', 'file://ser/foo/bazz', false);
});
});