Vscode merge (#4582)

* Merge from vscode 37cb23d3dd4f9433d56d4ba5ea3203580719a0bd

* fix issues with merges

* bump node version in azpipe

* replace license headers

* remove duplicate launch task

* fix build errors

* fix build errors

* fix tslint issues

* working through package and linux build issues

* more work

* wip

* fix packaged builds

* working through linux build errors

* wip

* wip

* wip

* fix mac and linux file limits

* iterate linux pipeline

* disable editor typing

* revert series to parallel

* remove optimize vscode from linux

* fix linting issues

* revert testing change

* add work round for new node

* readd packaging for extensions

* fix issue with angular not resolving decorator dependencies
This commit is contained in:
Anthony Dresser
2019-03-19 17:44:35 -07:00
committed by GitHub
parent 833d197412
commit 87765e8673
1879 changed files with 54505 additions and 38058 deletions

View File

@@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CancellationToken } from 'vs/base/common/cancellation';
import { Event } from 'vs/base/common/event';
/**
* An `IChannel` is an abstraction over a collection of commands.
* You can `call` several commands on a channel, each taking at
* most one single argument. A `call` always returns a promise
* with at most one single return value.
*/
export interface IChannel {
call<T>(command: string, arg?: any, cancellationToken?: CancellationToken): Promise<T>;
listen<T>(event: string, arg?: any): Event<T>;
}
/**
* An `IServerChannel` is the couter part to `IChannel`,
* on the server-side. You should implement this interface
* if you'd like to handle remote promises or events.
*/
export interface IServerChannel<TContext = string> {
call<T>(ctx: TContext, command: string, arg?: any, cancellationToken?: CancellationToken): Promise<T>;
listen<T>(ctx: TContext, event: string, arg?: any): Event<T>;
}

View File

@@ -14,7 +14,7 @@ export class Client extends IPCClient implements IDisposable {
private protocol: Protocol;
private static createProtocol(): Protocol {
const onMessage = Event.fromNodeEventEmitter<string>(ipcRenderer, 'ipc:message', (_, message: string) => message);
const onMessage = Event.fromNodeEventEmitter<Buffer>(ipcRenderer, 'ipc:message', (_, message: Buffer) => message);
ipcRenderer.send('ipc:hello');
return new Protocol(ipcRenderer, onMessage);
}

View File

@@ -11,11 +11,11 @@ import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
interface IIPCEvent {
event: { sender: Electron.WebContents; };
message: string;
message: Buffer | null;
}
function createScopedOnMessageEvent(senderId: number, eventName: string): Event<string> {
const onMessage = Event.fromNodeEventEmitter<IIPCEvent>(ipcMain, eventName, (event, message: string) => ({ event, message }));
function createScopedOnMessageEvent(senderId: number, eventName: string): Event<Buffer | null> {
const onMessage = Event.fromNodeEventEmitter<IIPCEvent>(ipcMain, eventName, (event, message) => ({ event, message }));
const onMessageFromSender = Event.filter(onMessage, ({ event }) => event.sender.id === senderId);
return Event.map(onMessageFromSender, ({ message }) => message);
}
@@ -38,7 +38,7 @@ export class Server extends IPCServer {
const onDidClientReconnect = new Emitter<void>();
Server.Clients.set(id, toDisposable(() => onDidClientReconnect.fire()));
const onMessage = createScopedOnMessageEvent(id, 'ipc:message');
const onMessage = createScopedOnMessageEvent(id, 'ipc:message') as Event<Buffer>;
const onDidClientDisconnect = Event.any(Event.signal(createScopedOnMessageEvent(id, 'ipc:disconnect')), onDidClientReconnect.event);
const protocol = new Protocol(webContents, onMessage);

View File

@@ -5,14 +5,15 @@
import { ChildProcess, fork, ForkOptions } from 'child_process';
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
import { Delayer, always, createCancelablePromise } from 'vs/base/common/async';
import { Delayer, createCancelablePromise } from 'vs/base/common/async';
import { deepClone, assign } from 'vs/base/common/objects';
import { Emitter, Event } from 'vs/base/common/event';
import { createQueuedSender } from 'vs/base/node/processes';
import { ChannelServer as IPCServer, ChannelClient as IPCClient, IChannelClient, IChannel } from 'vs/base/parts/ipc/node/ipc';
import { ChannelServer as IPCServer, ChannelClient as IPCClient, IChannelClient } from 'vs/base/parts/ipc/node/ipc';
import { isRemoteConsoleLog, log } from 'vs/base/node/console';
import { CancellationToken } from 'vs/base/common/cancellation';
import * as errors from 'vs/base/common/errors';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
/**
* This implementation doesn't perform well since it uses base64 encoding for buffers.
@@ -132,7 +133,7 @@ export class Client implements IChannelClient, IDisposable {
const disposable = toDisposable(() => result.cancel());
this.activeRequests.add(disposable);
always(result, () => {
result.finally(() => {
cancellationTokenListener.dispose();
this.activeRequests.delete(disposable);

View File

@@ -3,33 +3,20 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc';
import { Event, Emitter } from 'vs/base/common/event';
/**
* This implementation doesn't perform well since it uses base64 encoding for buffers.
* Electron 3.0 should have suport for buffers in IPC: https://github.com/electron/electron/pull/13055
*/
import { Event } from 'vs/base/common/event';
export interface Sender {
send(channel: string, msg: string | null): void;
send(channel: string, msg: Buffer | null): void;
}
export class Protocol implements IMessagePassingProtocol {
private listener: IDisposable;
private _onMessage = new Emitter<Buffer>();
get onMessage(): Event<Buffer> { return this._onMessage.event; }
constructor(private sender: Sender, onMessageEvent: Event<string>) {
onMessageEvent(msg => this._onMessage.fire(Buffer.from(msg, 'base64')));
}
constructor(private sender: Sender, readonly onMessage: Event<Buffer>) { }
send(message: Buffer): void {
try {
this.sender.send('ipc:message', message.toString('base64'));
this.sender.send('ipc:message', message);
} catch (e) {
// systems are going down
}
@@ -37,6 +24,5 @@ export class Protocol implements IMessagePassingProtocol {
dispose(): void {
this.sender.send('ipc:disconnect', null);
this.listener = dispose(this.listener);
}
}

View File

@@ -6,11 +6,10 @@
import { Socket, Server as NetServer, createConnection, createServer } from 'net';
import { Event, Emitter } from 'vs/base/common/event';
import { IMessagePassingProtocol, ClientConnectionEvent, IPCServer, IPCClient } from 'vs/base/parts/ipc/node/ipc';
import { join } from 'path';
import { join } from 'vs/base/common/path';
import { tmpdir } from 'os';
import { generateUuid } from 'vs/base/common/uuid';
import { IDisposable } from 'vs/base/common/lifecycle';
import { TimeoutTimer } from 'vs/base/common/async';
export function generateRandomPipeName(): string {
const randomSuffix = generateUuid();
@@ -22,6 +21,80 @@ export function generateRandomPipeName(): string {
}
}
class ChunkStream {
private _chunks: Buffer[];
private _totalLength: number;
public get byteLength() {
return this._totalLength;
}
constructor() {
this._chunks = [];
this._totalLength = 0;
}
public acceptChunk(buff: Buffer) {
this._chunks.push(buff);
this._totalLength += buff.byteLength;
}
public readUInt32BE(): number {
let tmp = this.read(4);
return tmp.readUInt32BE(0);
}
public read(byteCount: number): Buffer {
if (byteCount === 0) {
return Buffer.allocUnsafe(0);
}
if (byteCount > this._totalLength) {
throw new Error(`Cannot read so many bytes!`);
}
if (this._chunks[0].byteLength === byteCount) {
// super fast path, precisely first chunk must be returned
const result = this._chunks.shift()!;
this._totalLength -= byteCount;
return result;
}
if (this._chunks[0].byteLength > byteCount) {
// fast path, the reading is entirely within the first chunk
const result = this._chunks[0].slice(0, byteCount);
this._chunks[0] = this._chunks[0].slice(byteCount);
this._totalLength -= byteCount;
return result;
}
let result = Buffer.allocUnsafe(byteCount);
let resultOffset = 0;
while (byteCount > 0) {
const chunk = this._chunks[0];
if (chunk.byteLength > byteCount) {
// this chunk will survive
this._chunks[0] = chunk.slice(byteCount);
chunk.copy(result, resultOffset, 0, byteCount);
resultOffset += byteCount;
this._totalLength -= byteCount;
byteCount -= byteCount;
} else {
// this chunk will be entirely read
this._chunks.shift();
chunk.copy(result, resultOffset, 0, chunk.byteLength);
resultOffset += chunk.byteLength;
this._totalLength -= chunk.byteLength;
byteCount -= chunk.byteLength;
}
}
return result;
}
}
/**
* A message has the following format:
*
@@ -35,9 +108,8 @@ export class Protocol implements IDisposable, IMessagePassingProtocol {
private static readonly _headerLen = 4;
private _isDisposed: boolean;
private _chunks: Buffer[];
private _incomingData: ChunkStream;
private _firstChunkTimer: TimeoutTimer;
private _socketDataListener: (data: Buffer) => void;
private _socketEndListener: () => void;
private _socketCloseListener: () => void;
@@ -48,11 +120,9 @@ export class Protocol implements IDisposable, IMessagePassingProtocol {
private _onClose = new Emitter<void>();
readonly onClose: Event<void> = this._onClose.event;
constructor(private _socket: Socket, firstDataChunk?: Buffer) {
constructor(private _socket: Socket) {
this._isDisposed = false;
this._chunks = [];
let totalLength = 0;
this._incomingData = new ChunkStream();
const state = {
readHead: true,
@@ -61,24 +131,15 @@ export class Protocol implements IDisposable, IMessagePassingProtocol {
const acceptChunk = (data: Buffer) => {
this._chunks.push(data);
totalLength += data.length;
this._incomingData.acceptChunk(data);
while (totalLength > 0) {
while (this._incomingData.byteLength > 0) {
if (state.readHead) {
// expecting header -> read 5bytes for header
// information: `bodyIsJson` and `bodyLen`
if (totalLength >= Protocol._headerLen) {
const all = Buffer.concat(this._chunks);
state.bodyLen = all.readUInt32BE(0);
// expecting header -> read header
if (this._incomingData.byteLength >= Protocol._headerLen) {
state.bodyLen = this._incomingData.readUInt32BE();
state.readHead = false;
const rest = all.slice(Protocol._headerLen);
totalLength = rest.length;
this._chunks = [rest];
} else {
break;
}
@@ -87,15 +148,8 @@ export class Protocol implements IDisposable, IMessagePassingProtocol {
if (!state.readHead) {
// expecting body -> read bodyLen-bytes for
// the actual message or wait for more data
if (totalLength >= state.bodyLen) {
const all = Buffer.concat(this._chunks);
const buffer = all.slice(0, state.bodyLen);
// ensure the getBuffer returns a valid value if invoked from the event listeners
const rest = all.slice(state.bodyLen);
totalLength = rest.length;
this._chunks = [rest];
if (this._incomingData.byteLength >= state.bodyLen) {
const buffer = this._incomingData.read(state.bodyLen);
state.bodyLen = -1;
state.readHead = true;
@@ -113,28 +167,12 @@ export class Protocol implements IDisposable, IMessagePassingProtocol {
}
};
const acceptFirstDataChunk = () => {
if (firstDataChunk && firstDataChunk.length > 0) {
let tmp = firstDataChunk;
firstDataChunk = undefined;
acceptChunk(tmp);
}
};
// Make sure to always handle the firstDataChunk if no more `data` event comes in
this._firstChunkTimer = new TimeoutTimer();
this._firstChunkTimer.setIfNotSet(() => {
acceptFirstDataChunk();
}, 0);
this._socketDataListener = (data: Buffer) => {
acceptFirstDataChunk();
acceptChunk(data);
};
_socket.on('data', this._socketDataListener);
this._socketEndListener = () => {
acceptFirstDataChunk();
};
_socket.on('end', this._socketEndListener);
@@ -146,7 +184,6 @@ export class Protocol implements IDisposable, IMessagePassingProtocol {
dispose(): void {
this._isDisposed = true;
this._firstChunkTimer.dispose();
this._socket.removeListener('data', this._socketDataListener);
this._socket.removeListener('end', this._socketEndListener);
this._socket.removeListener('close', this._socketCloseListener);
@@ -156,8 +193,8 @@ export class Protocol implements IDisposable, IMessagePassingProtocol {
this._socket.end();
}
getBuffer(): Buffer {
return Buffer.concat(this._chunks);
readEntireBuffer(): Buffer {
return this._incomingData.read(this._incomingData.byteLength);
}
send(buffer: Buffer): void {

View File

@@ -5,9 +5,10 @@
import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { Event, Emitter, Relay } from 'vs/base/common/event';
import { always, CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async';
import { CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import * as errors from 'vs/base/common/errors';
import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc';
export const enum RequestType {
Promise = 100,
@@ -51,27 +52,6 @@ enum State {
Idle
}
/**
* An `IChannel` is an abstraction over a collection of commands.
* You can `call` several commands on a channel, each taking at
* most one single argument. A `call` always returns a promise
* with at most one single return value.
*/
export interface IChannel {
call<T>(command: string, arg?: any, cancellationToken?: CancellationToken): Promise<T>;
listen<T>(event: string, arg?: any): Event<T>;
}
/**
* An `IServerChannel` is the couter part to `IChannel`,
* on the server-side. You should implement this interface
* if you'd like to handle remote promises or events.
*/
export interface IServerChannel<TContext = string> {
call<T>(ctx: TContext, command: string, arg?: any, cancellationToken?: CancellationToken): Promise<T>;
listen<T>(ctx: TContext, event: string, arg?: any): Event<T>;
}
/**
* An `IChannelServer` hosts a collection of channels. You are
* able to register channels onto it, provided a channel name.
@@ -448,9 +428,7 @@ export class ChannelClient implements IChannelClient, IDisposable {
this.activeRequests.add(disposable);
});
always(result, () => this.activeRequests.delete(disposable));
return result;
return result.finally(() => this.activeRequests.delete(disposable));
}
private requestEvent(channelName: string, name: string, arg?: any): Event<any> {
@@ -690,7 +668,7 @@ export class IPCClient<TContext = string> implements IChannelClient, IChannelSer
export function getDelayedChannel<T extends IChannel>(promise: Promise<T>): T {
return {
call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise<T> {
return promise.then(c => c.call(command, arg, cancellationToken));
return promise.then(c => c.call<T>(command, arg, cancellationToken));
},
listen<T>(event: string, arg?: any): Event<T> {
@@ -752,4 +730,4 @@ export class StaticRouter<TContext = string> implements IClientRouter<TContext>
await Event.toPromise(hub.onDidChangeConnections);
return await this.route(hub);
}
}
}

View File

@@ -5,7 +5,6 @@
import * as assert from 'assert';
import { Client } from 'vs/base/parts/ipc/node/ipc.cp';
import { always } from 'vs/base/common/async';
import { TestServiceClient } from './testService';
import { getPathFromAmdModule } from 'vs/base/common/amd';
@@ -27,7 +26,7 @@ suite('IPC, Child Process', () => {
assert.equal(r.outgoing, 'pong');
});
return always(result, () => client.dispose());
return result.finally(() => client.dispose());
});
test('events', () => {
@@ -49,7 +48,7 @@ suite('IPC, Child Process', () => {
const request = service.marco();
const result = Promise.all([request, event]);
return always(result, () => client.dispose());
return result.finally(() => client.dispose());
});
test('event dispose', () => {
@@ -74,6 +73,6 @@ suite('IPC, Child Process', () => {
assert.equal(count, 2);
});
return always(result, () => client.dispose());
return result.finally(() => client.dispose());
});
});

View File

@@ -85,39 +85,4 @@ suite('IPC, Socket Protocol', () => {
});
});
});
test('can devolve to a socket and evolve again without losing data', () => {
let resolve: (v: void) => void;
let result = new Promise<void>((_resolve, _reject) => {
resolve = _resolve;
});
const sender = new Protocol(stream);
const receiver1 = new Protocol(stream);
assert.equal(stream.listenerCount('data'), 2);
assert.equal(stream.listenerCount('end'), 2);
receiver1.onMessage((msg) => {
assert.equal(JSON.parse(msg.toString()).value, 1);
let buffer = receiver1.getBuffer();
receiver1.dispose();
assert.equal(stream.listenerCount('data'), 1);
assert.equal(stream.listenerCount('end'), 1);
const receiver2 = new Protocol(stream, buffer);
receiver2.onMessage((msg) => {
assert.equal(JSON.parse(msg.toString()).value, 2);
resolve(undefined);
});
});
const msg1 = { value: 1 };
const msg2 = { value: 2 };
sender.send(Buffer.from(JSON.stringify(msg1)));
sender.send(Buffer.from(JSON.stringify(msg2)));
return result;
});
});

View File

@@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { IMessagePassingProtocol, IPCServer, ClientConnectionEvent, IPCClient, IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc';
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { IMessagePassingProtocol, IPCServer, ClientConnectionEvent, IPCClient } from 'vs/base/parts/ipc/node/ipc';
import { Emitter, Event } from 'vs/base/common/event';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { canceled } from 'vs/base/common/errors';
@@ -71,7 +72,7 @@ class TestIPCClient extends IPCClient<string> {
class TestIPCServer extends IPCServer<string> {
private onDidClientConnect: Emitter<ClientConnectionEvent>;
private readonly onDidClientConnect: Emitter<ClientConnectionEvent>;
constructor() {
const onDidClientConnect = new Emitter<ClientConnectionEvent>();

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc';
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { Event, Emitter } from 'vs/base/common/event';
import { timeout } from 'vs/base/common/async';

View File

@@ -8,8 +8,8 @@ import * as types from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree';
import { IconLabel, IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { IQuickNavigateConfiguration, IModel, IDataSource, IFilter, IAccessiblityProvider, IRenderer, IRunner, Mode } from 'vs/base/parts/quickopen/common/quickOpen';
import { Action, IAction, IActionRunner } from 'vs/base/common/actions';
import { IQuickNavigateConfiguration, IModel, IDataSource, IFilter, IAccessiblityProvider, IRenderer, IRunner, Mode, IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen';
import { Action, IAction, IActionRunner, IActionItem } from 'vs/base/common/actions';
import { compareAnything } from 'vs/base/common/comparers';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
@@ -35,15 +35,15 @@ let IDS = 0;
export class QuickOpenItemAccessorClass implements IItemAccessor<QuickOpenEntry> {
getItemLabel(entry: QuickOpenEntry): string {
getItemLabel(entry: QuickOpenEntry): string | null {
return entry.getLabel();
}
getItemDescription(entry: QuickOpenEntry): string {
getItemDescription(entry: QuickOpenEntry): string | null {
return entry.getDescription();
}
getItemPath(entry: QuickOpenEntry): string {
getItemPath(entry: QuickOpenEntry): string | undefined {
const resource = entry.getResource();
return resource ? resource.fsPath : undefined;
@@ -55,8 +55,8 @@ export const QuickOpenItemAccessor = new QuickOpenItemAccessorClass();
export class QuickOpenEntry {
private id: string;
private labelHighlights: IHighlight[];
private descriptionHighlights: IHighlight[];
private detailHighlights: IHighlight[];
private descriptionHighlights?: IHighlight[];
private detailHighlights?: IHighlight[];
private hidden: boolean;
constructor(highlights: IHighlight[] = []) {
@@ -75,14 +75,14 @@ export class QuickOpenEntry {
/**
* The label of the entry to identify it from others in the list
*/
getLabel(): string {
getLabel(): string | null {
return null;
}
/**
* The options for the label to use for this entry
*/
getLabelOptions(): IIconLabelValueOptions {
getLabelOptions(): IIconLabelValueOptions | null {
return null;
}
@@ -97,42 +97,42 @@ export class QuickOpenEntry {
/**
* Detail information about the entry that is optional and can be shown below the label
*/
getDetail(): string {
getDetail(): string | null {
return null;
}
/**
* The icon of the entry to identify it from others in the list
*/
getIcon(): string {
getIcon(): string | null {
return null;
}
/**
* A secondary description that is optional and can be shown right to the label
*/
getDescription(): string {
getDescription(): string | null {
return null;
}
/**
* A tooltip to show when hovering over the entry.
*/
getTooltip(): string {
getTooltip(): string | null {
return null;
}
/**
* A tooltip to show when hovering over the description portion of the entry.
*/
getDescriptionTooltip(): string {
getDescriptionTooltip(): string | null {
return null;
}
/**
* An optional keybinding to show for an entry.
*/
getKeybinding(): ResolvedKeybinding {
getKeybinding(): ResolvedKeybinding | null {
return null;
}
@@ -140,7 +140,7 @@ export class QuickOpenEntry {
* A resource for this entry. Resource URIs can be used to compare different kinds of entries and group
* them together.
*/
getResource(): URI {
getResource(): URI | null {
return null;
}
@@ -170,7 +170,7 @@ export class QuickOpenEntry {
/**
* Allows to return highlight ranges that should show up for the entry label and description.
*/
getHighlights(): [IHighlight[] /* Label */, IHighlight[] /* Description */, IHighlight[] /* Detail */] {
getHighlights(): [IHighlight[] /* Label */, IHighlight[] | undefined /* Description */, IHighlight[] | undefined /* Detail */] {
return [this.labelHighlights, this.descriptionHighlights, this.detailHighlights];
}
@@ -180,7 +180,7 @@ export class QuickOpenEntry {
*
* The context parameter provides additional context information how the run was triggered.
*/
run(mode: Mode, context: IContext): boolean {
run(mode: Mode, context: IEntryRunContext): boolean {
return false;
}
@@ -195,9 +195,9 @@ export class QuickOpenEntry {
}
export class QuickOpenEntryGroup extends QuickOpenEntry {
private entry: QuickOpenEntry;
private groupLabel: string;
private withBorder: boolean;
private entry?: QuickOpenEntry;
private groupLabel?: string;
private withBorder?: boolean;
constructor(entry?: QuickOpenEntry, groupLabel?: string, withBorder?: boolean) {
super();
@@ -210,11 +210,11 @@ export class QuickOpenEntryGroup extends QuickOpenEntry {
/**
* The label of the group or null if none.
*/
getGroupLabel(): string {
getGroupLabel(): string | undefined {
return this.groupLabel;
}
setGroupLabel(groupLabel: string): void {
setGroupLabel(groupLabel: string | undefined): void {
this.groupLabel = groupLabel;
}
@@ -222,18 +222,18 @@ export class QuickOpenEntryGroup extends QuickOpenEntry {
* Whether to show a border on top of the group entry or not.
*/
showBorder(): boolean {
return this.withBorder;
return !!this.withBorder;
}
setShowBorder(showBorder: boolean): void {
this.withBorder = showBorder;
}
getLabel(): string {
getLabel(): string | null {
return this.entry ? this.entry.getLabel() : super.getLabel();
}
getLabelOptions(): IIconLabelValueOptions {
getLabelOptions(): IIconLabelValueOptions | null {
return this.entry ? this.entry.getLabelOptions() : super.getLabelOptions();
}
@@ -241,27 +241,27 @@ export class QuickOpenEntryGroup extends QuickOpenEntry {
return this.entry ? this.entry.getAriaLabel() : super.getAriaLabel();
}
getDetail(): string {
getDetail(): string | null {
return this.entry ? this.entry.getDetail() : super.getDetail();
}
getResource(): URI {
getResource(): URI | null {
return this.entry ? this.entry.getResource() : super.getResource();
}
getIcon(): string {
getIcon(): string | null {
return this.entry ? this.entry.getIcon() : super.getIcon();
}
getDescription(): string {
getDescription(): string | null {
return this.entry ? this.entry.getDescription() : super.getDescription();
}
getEntry(): QuickOpenEntry {
getEntry(): QuickOpenEntry | undefined {
return this.entry;
}
getHighlights(): [IHighlight[], IHighlight[], IHighlight[]] {
getHighlights(): [IHighlight[], IHighlight[] | undefined, IHighlight[] | undefined] {
return this.entry ? this.entry.getHighlights() : super.getHighlights();
}
@@ -277,7 +277,7 @@ export class QuickOpenEntryGroup extends QuickOpenEntry {
this.entry ? this.entry.setHidden(hidden) : super.setHidden(hidden);
}
run(mode: Mode, context: IContext): boolean {
run(mode: Mode, context: IEntryRunContext): boolean {
return this.entry ? this.entry.run(mode, context) : super.run(mode, context);
}
}
@@ -288,7 +288,7 @@ class NoActionProvider implements IActionProvider {
return false;
}
getActions(tree: ITree, element: any): IAction[] {
getActions(tree: ITree, element: any): IAction[] | null {
return null;
}
@@ -296,11 +296,11 @@ class NoActionProvider implements IActionProvider {
return false;
}
getSecondaryActions(tree: ITree, element: any): IAction[] {
getSecondaryActions(tree: ITree, element: any): IAction[] | null {
return null;
}
getActionItem(tree: ITree, element: any, action: Action) {
getActionItem(tree: ITree, element: any, action: Action): IActionItem | null {
return null;
}
}
@@ -316,7 +316,7 @@ export interface IQuickOpenEntryTemplateData {
}
export interface IQuickOpenEntryGroupTemplateData extends IQuickOpenEntryTemplateData {
group: HTMLDivElement;
group?: HTMLDivElement;
}
const templateEntry = 'quickOpenEntry';
@@ -325,9 +325,9 @@ const templateEntryGroup = 'quickOpenEntryGroup';
class Renderer implements IRenderer<QuickOpenEntry> {
private actionProvider: IActionProvider;
private actionRunner: IActionRunner;
private actionRunner?: IActionRunner;
constructor(actionProvider: IActionProvider = new NoActionProvider(), actionRunner: IActionRunner | null = null) {
constructor(actionProvider: IActionProvider = new NoActionProvider(), actionRunner?: IActionRunner) {
this.actionProvider = actionProvider;
this.actionRunner = actionRunner;
}
@@ -356,7 +356,7 @@ class Renderer implements IRenderer<QuickOpenEntry> {
// Entry
const row1 = DOM.$('.quick-open-row');
const row2 = DOM.$('.quick-open-row');
const entry = DOM.$('.quick-open-entry', null, row1, row2);
const entry = DOM.$('.quick-open-entry', undefined, row1, row2);
entryContainer.appendChild(entry);
// Icon
@@ -379,7 +379,7 @@ class Renderer implements IRenderer<QuickOpenEntry> {
const detail = new HighlightedLabel(detailContainer, true);
// Entry Group
let group: HTMLDivElement;
let group: HTMLDivElement | undefined;
if (templateId === templateEntryGroup) {
group = document.createElement('div');
DOM.addClass(group, 'results-group');
@@ -442,7 +442,9 @@ class Renderer implements IRenderer<QuickOpenEntry> {
// Border
if (group.showBorder()) {
DOM.addClass(groupData.container, 'results-group-separator');
groupData.container.style.borderTopColor = styles.pickerGroupBorder.toString();
if (styles.pickerGroupBorder) {
groupData.container.style.borderTopColor = styles.pickerGroupBorder.toString();
}
} else {
DOM.removeClass(groupData.container, 'results-group-separator');
groupData.container.style.borderTopColor = null;
@@ -450,8 +452,12 @@ class Renderer implements IRenderer<QuickOpenEntry> {
// Group Label
const groupLabel = group.getGroupLabel() || '';
groupData.group.textContent = groupLabel;
groupData.group.style.color = styles.pickerGroupForeground.toString();
if (groupData.group) {
groupData.group.textContent = groupLabel;
if (styles.pickerGroupForeground) {
groupData.group.style.color = styles.pickerGroupForeground.toString();
}
}
}
// Normal Entry
@@ -465,31 +471,31 @@ class Renderer implements IRenderer<QuickOpenEntry> {
// Label
const options: IIconLabelValueOptions = entry.getLabelOptions() || Object.create(null);
options.matches = labelHighlights || [];
options.title = entry.getTooltip();
options.descriptionTitle = entry.getDescriptionTooltip() || entry.getDescription(); // tooltip over description because it could overflow
options.title = types.withNullAsUndefined(entry.getTooltip());
options.descriptionTitle = entry.getDescriptionTooltip() || types.withNullAsUndefined(entry.getDescription()); // tooltip over description because it could overflow
options.descriptionMatches = descriptionHighlights || [];
data.label.setLabel(entry.getLabel(), entry.getDescription(), options);
data.label.setLabel(types.withNullAsUndefined(entry.getLabel()), types.withNullAsUndefined(entry.getDescription()), options);
// Meta
data.detail.set(entry.getDetail(), detailHighlights);
data.detail.set(types.withNullAsUndefined(entry.getDetail()), detailHighlights);
// Keybinding
data.keybinding.set(entry.getKeybinding());
data.keybinding.set(entry.getKeybinding()!);
}
}
disposeTemplate(templateId: string, templateData: IQuickOpenEntryGroupTemplateData): void {
const data = templateData as IQuickOpenEntryGroupTemplateData;
data.actionBar.dispose();
data.actionBar = null;
data.container = null;
data.entry = null;
data.keybinding = null;
data.detail = null;
data.group = null;
data.icon = null;
data.actionBar = null!;
data.container = null!;
data.entry = null!;
data.keybinding = null!;
data.detail = null!;
data.group = null!;
data.icon = null!;
data.label.dispose();
data.label = null;
data.label = null!;
}
}
@@ -562,7 +568,7 @@ export class QuickOpenModel implements
return entry.getId();
}
getLabel(entry: QuickOpenEntry): string {
getLabel(entry: QuickOpenEntry): string | null {
return entry.getLabel();
}
@@ -579,7 +585,7 @@ export class QuickOpenModel implements
return !entry.isHidden();
}
run(entry: QuickOpenEntry, mode: Mode, context: IContext): boolean {
run(entry: QuickOpenEntry, mode: Mode, context: IEntryRunContext): boolean {
return entry.run(mode, context);
}
}
@@ -603,8 +609,8 @@ export function compareEntries(elementA: QuickOpenEntry, elementB: QuickOpenEntr
}
// Fallback to the full path if labels are identical and we have associated resources
let nameA = elementA.getLabel();
let nameB = elementB.getLabel();
let nameA = elementA.getLabel()!;
let nameB = elementB.getLabel()!;
if (nameA === nameB) {
const resourceA = elementA.getResource();
const resourceB = elementB.getResource();

View File

@@ -24,7 +24,7 @@ export class DataSource implements IDataSource {
getId(tree: ITree, element: any): string {
if (!element) {
return null;
return null!;
}
const model = this.modelProvider.getModel();
@@ -33,7 +33,7 @@ export class DataSource implements IDataSource {
hasChildren(tree: ITree, element: any): boolean {
const model = this.modelProvider.getModel();
return model && model === element && model.entries.length > 0;
return !!(model && model === element && model.entries.length > 0);
}
getChildren(tree: ITree, element: any): Promise<any[]> {
@@ -49,10 +49,10 @@ export class DataSource implements IDataSource {
export class AccessibilityProvider implements IAccessibilityProvider {
constructor(private modelProvider: IModelProvider) { }
getAriaLabel(tree: ITree, element: any): string {
getAriaLabel(tree: ITree, element: any): string | null {
const model = this.modelProvider.getModel();
return model.accessibilityProvider && model.accessibilityProvider.getAriaLabel(element);
return model.accessibilityProvider ? model.accessibilityProvider.getAriaLabel(element) : null;
}
getPosInSet(tree: ITree, element: any): string {

View File

@@ -36,7 +36,7 @@ export interface IQuickOpenCallbacks {
export interface IQuickOpenOptions extends IQuickOpenStyles {
minItemsToShow?: number;
maxItemsToShow?: number;
inputPlaceHolder: string;
inputPlaceHolder?: string;
inputAriaLabel?: string;
actionProvider?: IActionProvider;
keyboardSupport?: boolean;
@@ -110,12 +110,12 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
private visible: boolean;
private isLoosingFocus: boolean;
private callbacks: IQuickOpenCallbacks;
private quickNavigateConfiguration: IQuickNavigateConfiguration;
private quickNavigateConfiguration: IQuickNavigateConfiguration | undefined;
private container: HTMLElement;
private treeElement: HTMLElement;
private inputElement: HTMLElement;
private layoutDimensions: DOM.Dimension;
private model: IModel<any>;
private model: IModel<any> | null;
private inputChangingTimeoutHandle: any;
private styles: IQuickOpenStyles;
private renderer: Renderer;
@@ -137,7 +137,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
}
getModel(): IModel<any> {
return this.model;
return this.model!;
}
setCallbacks(callbacks: IQuickOpenCallbacks): void {
@@ -181,7 +181,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
DOM.addClass(this.inputContainer, 'quick-open-input');
this.element.appendChild(this.inputContainer);
this.inputBox = this._register(new InputBox(this.inputContainer, null, {
this.inputBox = this._register(new InputBox(this.inputContainer, undefined, {
placeholder: this.options.inputPlaceHolder || '',
ariaLabel: DEFAULT_INPUT_ARIA_LABEL,
inputBackground: this.styles.inputBackground,
@@ -538,10 +538,15 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
}
// ARIA
this.inputElement.setAttribute('aria-activedescendant', this.treeElement.getAttribute('aria-activedescendant'));
const arivaActiveDescendant = this.treeElement.getAttribute('aria-activedescendant');
if (arivaActiveDescendant) {
this.inputElement.setAttribute('aria-activedescendant', arivaActiveDescendant);
} else {
this.inputElement.removeAttribute('aria-activedescendant');
}
const context: IEntryRunContext = { event: event, keymods: this.extractKeyMods(event), quickNavigateConfiguration: this.quickNavigateConfiguration };
this.model.runner.run(value, Mode.PREVIEW, context);
this.model!.runner.run(value, Mode.PREVIEW, context);
}
private elementSelected(value: any, event?: any, preferredMode?: Mode): void {
@@ -553,7 +558,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
const context: IEntryRunContext = { event, keymods: this.extractKeyMods(event), quickNavigateConfiguration: this.quickNavigateConfiguration };
hide = this.model.runner.run(value, mode, context);
hide = this.model!.runner.run(value, mode, context);
}
// Hide if command was run successfully
@@ -603,7 +608,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
if (types.isString(param)) {
this.doShowWithPrefix(param);
} else {
if (options.value) {
if (options && options.value) {
this.restoreLastInput(options.value);
}
this.doShowWithInput(param, options && options.autoFocus ? options.autoFocus : {});
@@ -634,7 +639,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
this.setInput(input, autoFocus);
}
private setInputAndLayout(input: IModel<any>, autoFocus: IAutoFocus): void {
private setInputAndLayout(input: IModel<any>, autoFocus?: IAutoFocus): void {
this.treeContainer.style.height = `${this.getHeight(input)}px`;
this.tree.setInput(null).then(() => {
@@ -676,7 +681,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
const prefix = autoFocus.autoFocusPrefixMatch;
const lowerCasePrefix = prefix.toLowerCase();
for (const entry of entries) {
const label = input.dataSource.getLabel(entry);
const label = input.dataSource.getLabel(entry) || '';
if (!caseSensitiveMatch && label.indexOf(prefix) === 0) {
caseSensitiveMatch = entry;
@@ -747,13 +752,13 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
// Indicate entries to tree
this.tree.layout();
const entries = input ? input.entries.filter(e => this.isElementVisible(input, e)) : [];
const entries = input ? input.entries!.filter(e => this.isElementVisible(input!, e)) : [];
this.updateResultCount(entries.length);
// Handle auto focus
if (autoFocus) {
if (entries.length) {
this.autoFocus(input, entries, autoFocus);
this.autoFocus(input!, entries, autoFocus);
}
}
});
@@ -770,7 +775,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
let height = 0;
let preferredItemsHeight: number;
let preferredItemsHeight: number | undefined;
if (this.layoutDimensions && this.layoutDimensions.height) {
preferredItemsHeight = (this.layoutDimensions.height - 50 /* subtract height of input field (30px) and some spacing (drop shadow) to fit */) * 0.4 /* max 40% of screen */;
}
@@ -834,12 +839,12 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
}
if (this.callbacks.onHide) {
this.callbacks.onHide(reason);
this.callbacks.onHide(reason!);
}
}
getQuickNavigateConfiguration(): IQuickNavigateConfiguration {
return this.quickNavigateConfiguration;
return this.quickNavigateConfiguration!;
}
setPlaceHolder(placeHolder: string): void {
@@ -868,7 +873,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
}
}
setInput(input: IModel<any>, autoFocus: IAutoFocus, ariaLabel?: string): void {
setInput(input: IModel<any>, autoFocus?: IAutoFocus, ariaLabel?: string): void {
if (!this.isVisible()) {
return;
}
@@ -940,7 +945,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
return this.inputBox;
}
setExtraClass(clazz: string): void {
setExtraClass(clazz: string | null): void {
const previousClass = this.element.getAttribute('quick-open-extra-class');
if (previousClass) {
DOM.removeClasses(this.element, previousClass);

View File

@@ -49,7 +49,7 @@ export const enum Mode {
export interface IEntryRunContext {
event: any;
keymods: IKeyMods;
quickNavigateConfiguration: IQuickNavigateConfiguration;
quickNavigateConfiguration: IQuickNavigateConfiguration | undefined;
}
export interface IKeyMods {
@@ -59,7 +59,7 @@ export interface IKeyMods {
export interface IDataSource<T> {
getId(entry: T): string;
getLabel(entry: T): string;
getLabel(entry: T): string | null;
}
/**

View File

@@ -5,7 +5,7 @@
import { compareAnything } from 'vs/base/common/comparers';
import { matchesPrefix, IMatch, matchesCamelCase, isUpper } from 'vs/base/common/filters';
import { nativeSep } from 'vs/base/common/paths';
import { sep } from 'vs/base/common/path';
import { isWindows, isLinux } from 'vs/base/common/platform';
import { stripWildcards, equalsIgnoreCase } from 'vs/base/common/strings';
import { CharCode } from 'vs/base/common/charCode';
@@ -156,7 +156,7 @@ function doScore(query: string, queryLower: string, queryLength: number, target:
return [scores[queryLength * targetLength - 1], positions.reverse()];
}
function computeCharScore(queryCharAtIndex, queryLowerCharAtIndex, target: string, targetLower: string, targetIndex: number, matchesSequenceLength: number): number {
function computeCharScore(queryCharAtIndex: string, queryLowerCharAtIndex: string, target: string, targetLower: string, targetIndex: number, matchesSequenceLength: number): number {
let score = 0;
if (queryLowerCharAtIndex !== targetLower[targetIndex]) {
@@ -285,17 +285,17 @@ export interface IItemAccessor<T> {
/**
* Just the label of the item to score on.
*/
getItemLabel(item: T): string;
getItemLabel(item: T): string | null;
/**
* The optional description of the item to score on. Can be null.
*/
getItemDescription(item: T): string;
getItemDescription(item: T): string | null;
/**
* If the item is a file, the path of the file to score on. Can be null.
*/
getItemPath(file: T): string;
getItemPath(file: T): string | undefined;
}
const PATH_IDENTITY_SCORE = 1 << 18;
@@ -320,11 +320,11 @@ export function prepareQuery(original: string): IPreparedQuery {
let value = stripWildcards(original).replace(/\s/g, ''); // get rid of all wildcards and whitespace
if (isWindows) {
value = value.replace(/\//g, nativeSep); // Help Windows users to search for paths when using slash
value = value.replace(/\//g, sep); // Help Windows users to search for paths when using slash
}
const lowercase = value.toLowerCase();
const containsPathSeparator = value.indexOf(nativeSep) >= 0;
const containsPathSeparator = value.indexOf(sep) >= 0;
return { original, value, lowercase, containsPathSeparator };
}
@@ -376,10 +376,10 @@ function createMatches(offsets: undefined | number[]): IMatch[] {
return ret;
}
function doScoreItem(label: string, description: string, path: string, query: IPreparedQuery, fuzzy: boolean): IItemScore {
function doScoreItem(label: string, description: string | null, path: string | undefined, query: IPreparedQuery, fuzzy: boolean): IItemScore {
// 1.) treat identity matches on full path highest
if (path && isLinux ? query.original === path : equalsIgnoreCase(query.original, path)) {
if (path && (isLinux ? query.original === path : equalsIgnoreCase(query.original, path))) {
return { score: PATH_IDENTITY_SCORE, labelMatch: [{ start: 0, end: label.length }], descriptionMatch: description ? [{ start: 0, end: description.length }] : undefined };
}
@@ -410,7 +410,7 @@ function doScoreItem(label: string, description: string, path: string, query: IP
if (description) {
let descriptionPrefix = description;
if (!!path) {
descriptionPrefix = `${description}${nativeSep}`; // assume this is a file path
descriptionPrefix = `${description}${sep}`; // assume this is a file path
}
const descriptionPrefixLength = descriptionPrefix.length;
@@ -469,8 +469,8 @@ export function compareItemsByScore<T>(itemA: T, itemB: T, query: IPreparedQuery
return scoreA === LABEL_PREFIX_SCORE ? -1 : 1;
}
const labelA = accessor.getItemLabel(itemA);
const labelB = accessor.getItemLabel(itemB);
const labelA = accessor.getItemLabel(itemA) || '';
const labelB = accessor.getItemLabel(itemB) || '';
// prefer shorter names when both match on label prefix
if (labelA.length !== labelB.length) {
@@ -484,8 +484,8 @@ export function compareItemsByScore<T>(itemA: T, itemB: T, query: IPreparedQuery
return scoreA === LABEL_CAMELCASE_SCORE ? -1 : 1;
}
const labelA = accessor.getItemLabel(itemA);
const labelB = accessor.getItemLabel(itemB);
const labelA = accessor.getItemLabel(itemA) || '';
const labelB = accessor.getItemLabel(itemB) || '';
// prefer more compact camel case matches over longer
const comparedByMatchLength = compareByMatchLength(itemScoreA.labelMatch, itemScoreB.labelMatch);
@@ -592,8 +592,8 @@ function compareByMatchLength(matchesA?: IMatch[], matchesB?: IMatch[]): number
export function fallbackCompare<T>(itemA: T, itemB: T, query: IPreparedQuery, accessor: IItemAccessor<T>): number {
// check for label + description length and prefer shorter
const labelA = accessor.getItemLabel(itemA);
const labelB = accessor.getItemLabel(itemB);
const labelA = accessor.getItemLabel(itemA) || '';
const labelB = accessor.getItemLabel(itemB) || '';
const descriptionA = accessor.getItemDescription(itemA);
const descriptionB = accessor.getItemDescription(itemB);

View File

@@ -6,7 +6,7 @@
import * as assert from 'assert';
import * as scorer from 'vs/base/parts/quickopen/common/quickOpenScorer';
import { URI } from 'vs/base/common/uri';
import { basename, dirname, nativeSep } from 'vs/base/common/paths';
import { basename, dirname, sep } from 'vs/base/common/path';
import { isWindows } from 'vs/base/common/platform';
class ResourceAccessorClass implements scorer.IItemAccessor<URI> {
@@ -797,9 +797,9 @@ suite('Quick Open Scorer', () => {
});
test('compareFilesByScore - avoid match scattering (bug #12095)', function () {
const resourceA = URI.file('src/vs/workbench/parts/files/common/explorerViewModel.ts');
const resourceB = URI.file('src/vs/workbench/parts/files/browser/views/explorerView.ts');
const resourceC = URI.file('src/vs/workbench/parts/files/browser/views/explorerViewer.ts');
const resourceA = URI.file('src/vs/workbench/contrib/files/common/explorerViewModel.ts');
const resourceB = URI.file('src/vs/workbench/contrib/files/browser/views/explorerView.ts');
const resourceC = URI.file('src/vs/workbench/contrib/files/browser/views/explorerViewer.ts');
let query = 'filesexplorerview.ts';
@@ -815,6 +815,6 @@ suite('Quick Open Scorer', () => {
assert.equal(scorer.prepareQuery('model Tester.ts').value, 'modelTester.ts');
assert.equal(scorer.prepareQuery('Model Tester.ts').lowercase, 'modeltester.ts');
assert.equal(scorer.prepareQuery('ModelTester.ts').containsPathSeparator, false);
assert.equal(scorer.prepareQuery('Model' + nativeSep + 'Tester.ts').containsPathSeparator, true);
assert.equal(scorer.prepareQuery('Model' + sep + 'Tester.ts').containsPathSeparator, true);
});
});

View File

@@ -724,12 +724,12 @@ export interface IActionProvider {
/**
* Returns whether or not the element has actions. These show up in place right to the element in the tree.
*/
hasActions(tree: ITree, element: any): boolean;
hasActions(tree: ITree | null, element: any): boolean;
/**
* Returns a promise of an array with the actions of the element that should show up in place right to the element in the tree.
*/
getActions(tree: ITree, element: any): IAction[];
getActions(tree: ITree | null, element: any): IAction[] | null;
/**
* Returns whether or not the element has secondary actions. These show up once the user has expanded the element's action bar.
@@ -739,7 +739,7 @@ export interface IActionProvider {
/**
* Returns a promise of an array with the secondary actions of the element that should show up once the user has expanded the element's action bar.
*/
getSecondaryActions(tree: ITree, element: any): IAction[];
getSecondaryActions(tree: ITree, element: any): IAction[] | null;
/**
* Returns an action item to render an action.

View File

@@ -13,7 +13,7 @@ import * as mouse from 'vs/base/browser/mouseEvent';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import * as _ from 'vs/base/parts/tree/browser/tree';
import { IDragAndDropData } from 'vs/base/browser/dnd';
import { KeyCode, KeyMod, Keybinding, SimpleKeybinding, createSimpleKeybinding } from 'vs/base/common/keyCodes';
import { KeyCode, KeyMod, Keybinding, SimpleKeybinding, createKeybinding } from 'vs/base/common/keyCodes';
export interface IKeyBindingCallback {
(tree: _.ITree, event: IKeyboardEvent): void;
@@ -49,7 +49,7 @@ export interface IControllerOptions {
}
interface IKeybindingDispatcherItem {
keybinding: Keybinding;
keybinding: Keybinding | null;
callback: IKeyBindingCallback;
}
@@ -62,10 +62,12 @@ export class KeybindingDispatcher {
}
public has(keybinding: KeyCode): boolean {
let target = createSimpleKeybinding(keybinding, platform.OS);
for (const a of this._arr) {
if (target.equals(a.keybinding)) {
return true;
let target = createKeybinding(keybinding, platform.OS);
if (target !== null) {
for (const a of this._arr) {
if (target.equals(a.keybinding)) {
return true;
}
}
}
return false;
@@ -73,7 +75,7 @@ export class KeybindingDispatcher {
public set(keybinding: number, callback: IKeyBindingCallback) {
this._arr.push({
keybinding: createSimpleKeybinding(keybinding, platform.OS),
keybinding: createKeybinding(keybinding, platform.OS),
callback: callback
});
}
@@ -82,7 +84,7 @@ export class KeybindingDispatcher {
// Loop from the last to the first to handle overwrites
for (let i = this._arr.length - 1; i >= 0; i--) {
let item = this._arr[i];
if (keybinding.equals(item.keybinding)) {
if (keybinding.toChord().equals(item.keybinding)) {
return item.callback;
}
}
@@ -556,7 +558,7 @@ export class DefaultTreestyler implements _.ITreeStyler {
export class CollapseAllAction extends Action {
constructor(private viewer: _.ITree, enabled: boolean) {
super('vs.tree.collapse', nls.localize('collapse', "Collapse"), 'monaco-tree-action collapse-all', enabled);
super('vs.tree.collapse', nls.localize('collapse all', "Collapse All"), 'monaco-tree-action collapse-all', enabled);
}
public run(context?: any): Promise<any> {

View File

@@ -1286,8 +1286,8 @@ export class TreeView extends HeightMap {
element = this.model!.getInput();
position = DOM.getDomNodePagePosition(this.inputItem.element);
} else {
let id = this.context.dataSource.getId(this.context.tree, element);
let viewItem = this.items[id];
const id = this.context.dataSource.getId(this.context.tree, element);
const viewItem = this.items[id!];
position = DOM.getDomNodePagePosition(viewItem.element);
}
@@ -1422,6 +1422,8 @@ export class TreeView extends HeightMap {
}
private onDragOver(e: DragEvent): boolean {
e.preventDefault(); // needed so that the drop event fires (https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome)
let event = new Mouse.DragMouseEvent(e);
let viewItem = this.getItemAround(event.target);