Merge from vscode fc10e26ea50f82cdd84e9141491357922e6f5fba (#4639)

This commit is contained in:
Anthony Dresser
2019-03-21 10:58:16 -07:00
committed by GitHub
parent 8298db7d13
commit b65ee5b42e
149 changed files with 1408 additions and 814 deletions

View File

@@ -6,7 +6,6 @@
'use strict';
import * as fs from 'fs';
import { execSync } from 'child_process';
import { Readable } from 'stream';
import * as crypto from 'crypto';
import * as azure from 'azure-storage';
@@ -293,15 +292,18 @@ function main(): void {
return;
}
const commit = process.env['BUILD_SOURCEVERSION'];
if (!commit) {
console.warn('Skipping publish due to missing BUILD_SOURCEVERSION');
return;
}
const opts = minimist<PublishOptions>(process.argv.slice(2), {
boolean: ['upload-only']
});
// {{SQL CARBON EDIT}}
let [quality, platform, type, name, version, _isUpdate, file, commit] = opts._;
if (!commit) {
commit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();
}
const [quality, platform, type, name, version, _isUpdate, file] = opts._;
publish(commit, quality, platform, type, name, version, _isUpdate, file, opts).catch(err => {
console.error(err);

View File

@@ -112,12 +112,12 @@
"@types/node" "*"
"@types/gulp-uglify@^3.0.5":
version "3.0.6"
resolved "https://registry.yarnpkg.com/@types/gulp-uglify/-/gulp-uglify-3.0.6.tgz#7c7c38017680bbb8a3d815e23a7026799432ce54"
integrity sha512-NvnNG0lg0+fJHNDK/b4OvLZkn5uHSIgm1XslRqgHal8CHG85sxmcktnNR1XdIUkwYpNbYZkXfvpzNtAxb6cgyQ==
version "3.0.5"
resolved "https://registry.yarnpkg.com/@types/gulp-uglify/-/gulp-uglify-3.0.5.tgz#ddcbbb6bd15a84b8a6c5e2218c2efba98102d135"
integrity sha512-LD2b6gCPugrKI1W188nIp0gm+cAnGGwaTFpPdeZYVXwPHdoCQloy3du0JR62MeMjAwUwlcOb+SKYT6Qgw7yBiA==
dependencies:
"@types/node" "*"
"@types/uglify-js" "*"
"@types/uglify-js" "^2"
"@types/gulp@^4.0.5":
version "4.0.6"
@@ -221,6 +221,13 @@
dependencies:
source-map "^0.6.1"
"@types/uglify-js@^2":
version "2.6.32"
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-2.6.32.tgz#1b60906946fcf6ee4ceafa812d2b86f1358da904"
integrity sha512-pVD2cG2wsKPvtpcxVZiSvK8eV9CpxXdlvhbAN//1eD3rOodqQLaEZ1qMNPl/+J93HrECsNLItRx5DkZuSW3j3A==
dependencies:
source-map "^0.6.1"
"@types/underscore@^1.8.9":
version "1.8.9"
resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.8.9.tgz#fef41f800cd23db1b4f262ddefe49cd952d82323"

View File

@@ -240,6 +240,11 @@
"title": "%command.branch%",
"category": "Git"
},
{
"command": "git.branchFrom",
"title": "%command.branchFrom%",
"category": "Git"
},
{
"command": "git.deleteBranch",
"title": "%command.deleteBranch%",
@@ -512,6 +517,10 @@
"command": "git.branch",
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.branchFrom",
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.deleteBranch",
"when": "config.git.enabled && gitOpenRepositoryCount != 0"

View File

@@ -32,6 +32,7 @@
"command.undoCommit": "Undo Last Commit",
"command.checkout": "Checkout to...",
"command.branch": "Create Branch...",
"command.branchFrom": "Create Branch From...",
"command.deleteBranch": "Delete Branch...",
"command.renameBranch": "Rename Branch...",
"command.merge": "Merge Branch...",

View File

@@ -103,6 +103,20 @@ class CreateBranchItem implements QuickPickItem {
}
}
class CreateBranchFromItem implements QuickPickItem {
constructor(private cc: CommandCenter) { }
get label(): string { return localize('create branch from', '$(plus) Create new branch from...'); }
get description(): string { return ''; }
get alwaysShow(): boolean { return true; }
async run(repository: Repository): Promise<void> {
await this.cc.branch(repository);
}
}
class HEADItem implements QuickPickItem {
constructor(private repository: Repository) { }
@@ -1422,9 +1436,10 @@ export class CommandCenter {
await repository.checkout(treeish);
return true;
}
const createBranch = new CreateBranchItem(this);
const picks = [createBranch, ...createCheckoutItems(repository)];
const createBranch = new CreateBranchItem(this);
const createBranchFrom = new CreateBranchFromItem(this);
const picks = [createBranch, createBranchFrom, ...createCheckoutItems(repository)];
const placeHolder = localize('select a ref to checkout', 'Select a ref to checkout');
const quickpick = window.createQuickPick();
@@ -1441,6 +1456,8 @@ export class CommandCenter {
if (choice === createBranch) {
await this._branch(repository, quickpick.value);
} else if (choice === createBranchFrom) {
await this._branch(repository, quickpick.value, true);
} else {
await (choice as CheckoutItem).run(repository);
}
@@ -1453,7 +1470,12 @@ export class CommandCenter {
await this._branch(repository);
}
private async _branch(repository: Repository, defaultName?: string): Promise<void> {
@command('git.branchFrom', { repository: true })
async branchFrom(repository: Repository): Promise<void> {
await this._branch(repository, undefined, true);
}
private async _branch(repository: Repository, defaultName?: string, from = false): Promise<void> {
const config = workspace.getConfiguration('git');
const branchWhitespaceChar = config.get<string>('branchWhitespaceChar')!;
const branchValidationRegex = config.get<string>('branchValidationRegex')!;
@@ -1481,15 +1503,21 @@ export class CommandCenter {
return;
}
const picks = [new HEADItem(repository), ...createCheckoutItems(repository)];
const placeHolder = localize('select a ref to create a new branch from', 'Select a ref to create the \'{0}\' branch from', branchName);
const target = await window.showQuickPick(picks, { placeHolder });
let target = 'HEAD';
if (!target) {
return;
if (from) {
const picks = [new HEADItem(repository), ...createCheckoutItems(repository)];
const placeHolder = localize('select a ref to create a new branch from', 'Select a ref to create the \'{0}\' branch from', branchName);
const choice = await window.showQuickPick(picks, { placeHolder });
if (!choice) {
return;
}
target = choice.label;
}
await repository.branch(branchName, true, target.label);
await repository.branch(branchName, true, target);
}
@command('git.deleteBranch', { repository: true })

View File

@@ -397,7 +397,7 @@ export class InputBox extends Widget {
return errorMsg ? errorMsg.type !== MessageType.ERROR : true;
}
private stylesForType(type: MessageType | undefined): { border: Color | undefined | null; background: Color | undefined | null; foreground: Color | undefined | null } {
private stylesForType(type: MessageType | undefined): { border: Color | undefined; background: Color | undefined; foreground: Color | undefined } {
switch (type) {
case MessageType.INFO: return { border: this.inputValidationInfoBorder, background: this.inputValidationInfoBackground, foreground: this.inputValidationInfoForeground };
case MessageType.WARNING: return { border: this.inputValidationWarningBorder, background: this.inputValidationWarningBackground, foreground: this.inputValidationWarningForeground };

View File

@@ -379,6 +379,18 @@ export function uniqueFilter<T>(keyFn: (t: T) => string): (t: T) => boolean {
};
}
export function lastIndex<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean): number {
for (let i = array.length - 1; i >= 0; i--) {
const element = array[i];
if (fn(element)) {
return i;
}
}
return -1;
}
export function firstIndex<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean): number {
for (let i = 0; i < array.length; i++) {
const element = array[i];

View File

@@ -93,7 +93,6 @@ export function isUndefinedOrNull(obj: any): obj is undefined | null {
return isUndefined(obj) || obj === null;
}
const hasOwnProperty = Object.prototype.hasOwnProperty;
/**

View File

@@ -10,7 +10,7 @@ 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 } from 'vs/base/parts/ipc/node/ipc';
import { isRemoteConsoleLog, log } from 'vs/base/node/console';
import { isRemoteConsoleLog, log } from 'vs/base/common/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';

View File

@@ -248,6 +248,7 @@ class ProtocolReader {
class ProtocolWriter {
private _isDisposed: boolean;
private readonly _socket: Socket;
private readonly _logFile: number;
private _data: Buffer[];
@@ -255,6 +256,7 @@ class ProtocolWriter {
public lastWriteTime: number;
constructor(socket: Socket, logFile: number) {
this._isDisposed = false;
this._socket = socket;
this._logFile = logFile;
this._data = [];
@@ -264,6 +266,7 @@ class ProtocolWriter {
public dispose(): void {
this.flush();
this._isDisposed = true;
}
public flush(): void {
@@ -272,6 +275,11 @@ class ProtocolWriter {
}
public write(msg: ProtocolMessage) {
if (this._isDisposed) {
console.warn(`Cannot write message in a disposed ProtocolWriter`);
console.warn(msg);
return;
}
if (this._logFile) {
log(this._logFile, `send-${ProtocolMessageTypeToString(msg.type)}-${msg.id}-${msg.ack}-`, msg.data);
}
@@ -373,12 +381,13 @@ export class Protocol implements IDisposable, IMessagePassingProtocol {
}
dispose(): void {
this._socketWriter.dispose();
this._socketReader.dispose();
this._socket.removeListener('close', this._socketCloseListener);
}
end(): void {
this._socket.end();
getSocket(): Socket {
return this._socket;
}
send(buffer: Buffer): void {
@@ -427,8 +436,9 @@ export class Client<TContext = string> extends IPCClient<TContext> {
dispose(): void {
super.dispose();
this.protocol.end();
const socket = this.protocol.getSocket();
this.protocol.dispose();
socket.end();
}
}
@@ -800,10 +810,6 @@ export class PersistentProtocol {
}
}
end(): void {
this._socket.end();
}
readEntireBuffer(): Buffer {
return this._socketReader.readEntireBuffer();
}

View File

@@ -143,7 +143,7 @@ class TestChannel implements IServerChannel {
constructor(private service: ITestService) { }
call(_, command: string, arg: any, cancellationToken: CancellationToken): Promise<any> {
call(_: unknown, command: string, arg: any, cancellationToken: CancellationToken): Promise<any> {
switch (command) {
case 'marco': return this.service.marco();
case 'error': return this.service.error(arg);
@@ -154,7 +154,7 @@ class TestChannel implements IServerChannel {
}
}
listen(_, event: string, arg?: any): Event<any> {
listen(_: unknown, event: string, arg?: any): Event<any> {
switch (event) {
case 'pong': return this.service.pong;
default: throw new Error('not implemented');

View File

@@ -41,7 +41,7 @@ export class TestChannel implements IServerChannel {
constructor(private testService: ITestService) { }
listen(_, event: string): Event<any> {
listen(_: unknown, event: string): Event<any> {
switch (event) {
case 'marco': return this.testService.onMarco;
}
@@ -49,7 +49,7 @@ export class TestChannel implements IServerChannel {
throw new Error('Event not found');
}
call(_, command: string, ...args: any[]): Promise<any> {
call(_: unknown, command: string, ...args: any[]): Promise<any> {
switch (command) {
case 'pong': return this.testService.pong(args[0]);
case 'cancelMe': return this.testService.cancelMe();

View File

@@ -270,7 +270,7 @@ suite('Arrays', () => {
}
test('coalesce', () => {
let a: Array<number | undefined | null> = arrays.coalesce([null, 1, null, 2, 3]);
let a: Array<number | null> = arrays.coalesce([null, 1, null, 2, 3]);
assert.equal(a.length, 3);
assert.equal(a[0], 1);
assert.equal(a[1], 2);
@@ -306,7 +306,7 @@ suite('Arrays', () => {
});
test('coalesce - inplace', function () {
let a: Array<number | undefined | null> = [null, 1, null, 2, 3];
let a: Array<number | null> = [null, 1, null, 2, 3];
arrays.coalesceInPlace(a);
assert.equal(a.length, 3);
assert.equal(a[0], 1);

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { getFirstFrame } from 'vs/base/node/console';
import { getFirstFrame } from 'vs/base/common/console';
import { normalize } from 'vs/base/common/path';
suite('Console', () => {

View File

@@ -30,7 +30,7 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProper
import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService';
import { MainProcessService, IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { IssueReporterModel } from 'vs/code/electron-browser/issue/issueReporterModel';
import { IssueReporterModel, IssueReporterData as IssueReporterModelData } from 'vs/code/electron-browser/issue/issueReporterModel';
import { IssueReporterData, IssueReporterStyles, IssueType, ISettingsSearchIssueReporterData, IssueReporterFeatures, IssueReporterExtensionData } from 'vs/platform/issue/common/issue';
import BaseHtml from 'vs/code/electron-browser/issue/issueReporterPage';
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
@@ -92,7 +92,7 @@ export class IssueReporter extends Disposable {
this.previewButton = new Button(issueReporterElement);
}
ipcRenderer.on('vscode:issuePerformanceInfoResponse', (_, info) => {
ipcRenderer.on('vscode:issuePerformanceInfoResponse', (_: unknown, info: Partial<IssueReporterData>) => {
this.logService.trace('issueReporter: Received performance data');
this.issueReporterModel.update(info);
this.receivedPerformanceInfo = true;
@@ -103,7 +103,7 @@ export class IssueReporter extends Disposable {
this.updatePreviewButtonState();
});
ipcRenderer.on('vscode:issueSystemInfoResponse', (_, info) => {
ipcRenderer.on('vscode:issueSystemInfoResponse', (_: unknown, info: any) => {
this.logService.trace('issueReporter: Received system data');
this.issueReporterModel.update({ systemInfo: info });
this.receivedSystemInfo = true;
@@ -899,7 +899,7 @@ export class IssueReporter extends Disposable {
return `${repositoryUrl}${queryStringPrefix}title=${encodeURIComponent(issueTitle)}`;
}
private updateSystemInfo = (state) => {
private updateSystemInfo(state: IssueReporterModelData) {
const target = document.querySelector('.block-system .block-info');
if (target) {
let tableHtml = '';
@@ -968,14 +968,14 @@ export class IssueReporter extends Disposable {
}
}
private updateProcessInfo = (state) => {
private updateProcessInfo(state: IssueReporterModelData) {
const target = document.querySelector('.block-process .block-info');
if (target) {
target.innerHTML = `<code>${state.processInfo}</code>`;
}
}
private updateWorkspaceInfo = (state) => {
private updateWorkspaceInfo(state: IssueReporterModelData) {
document.querySelector('.block-workspace .block-info code')!.textContent = '\n' + state.workspaceInfo;
}
@@ -1075,9 +1075,13 @@ export class IssueReporter extends Disposable {
// helper functions
function hide(el) {
el.classList.add('hidden');
function hide(el: Element | undefined | null) {
if (el) {
el.classList.add('hidden');
}
}
function show(el) {
el.classList.remove('hidden');
function show(el: Element | undefined | null) {
if (el) {
el.classList.remove('hidden');
}
}

View File

@@ -38,7 +38,7 @@ import { ILocalizationsService } from 'vs/platform/localizations/common/localiza
import { LocalizationsChannel } from 'vs/platform/localizations/node/localizationsIpc';
import { DialogChannelClient } from 'vs/platform/dialogs/node/dialogIpc';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IDisposable, dispose, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle';
import { DownloadService } from 'vs/platform/download/node/downloadService';
import { IDownloadService } from 'vs/platform/download/common/download';
import { StaticRouter } from 'vs/base/parts/ipc/node/ipc';
@@ -161,12 +161,12 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
const localizationsChannel = new LocalizationsChannel(localizationsService);
server.registerChannel('localizations', localizationsChannel);
// clean up deprecated extensions
(extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions();
// update localizations cache
(localizationsService as LocalizationsService).update();
// cache clean ups
disposables.push(combinedDisposable([
// clean up deprecated extensions
toDisposable(() => (extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions()),
// update localizations cache
toDisposable(() => (localizationsService as LocalizationsService).update()),
// other cache clean ups
instantiationService2.createInstance(NodeCachedDataCleaner),
instantiationService2.createInstance(LanguagePackCachedDataCleaner),
instantiationService2.createInstance(StorageDataCleaner),

View File

@@ -10,13 +10,17 @@ import * as resources from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IOpenerService, IOpener } from 'vs/platform/opener/common/opener';
import { equalsIgnoreCase } from 'vs/base/common/strings';
import { IDisposable } from 'vs/base/common/lifecycle';
import { LinkedList } from 'vs/base/common/linkedList';
export class OpenerService implements IOpenerService {
_serviceBrand: any;
private readonly _opener = new LinkedList<IOpener>();
constructor(
@ICodeEditorService private readonly _editorService: ICodeEditorService,
@ICommandService private readonly _commandService: ICommandService,
@@ -24,14 +28,30 @@ export class OpenerService implements IOpenerService {
//
}
open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean> {
registerOpener(opener: IOpener): IDisposable {
const remove = this._opener.push(opener);
return { dispose: remove };
}
const { scheme, path, query, fragment } = resource;
if (!scheme) {
// no scheme ?!?
async open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean> {
// no scheme ?!?
if (!resource.scheme) {
return Promise.resolve(false);
}
// check with contributed openers
for (const opener of this._opener.toArray()) {
const handled = await opener.open(resource, options);
if (handled) {
return true;
}
}
// use default openers
return this._doOpen(resource, options);
}
private _doOpen(resource: URI, options?: { openToSide?: boolean }): Promise<boolean> {
const { scheme, path, query, fragment } = resource;
if (equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https) || equalsIgnoreCase(scheme, Schemas.mailto)) {
// open http or default mail application

View File

@@ -65,8 +65,8 @@ export interface CharacterMap {
[char: string]: string;
}
const autoCloseAlways = _ => true;
const autoCloseNever = _ => false;
const autoCloseAlways = () => true;
const autoCloseNever = () => false;
const autoCloseBeforeWhitespace = (chr: string) => (chr === ' ' || chr === '\t');
export class CursorConfiguration {

View File

@@ -36,7 +36,7 @@ export interface ITextModelContentProvider {
/**
* Given a resource, return the content of the resource as `ITextModel`.
*/
provideTextContent(resource: URI): Promise<ITextModel | undefined | null> | null | undefined;
provideTextContent(resource: URI): Promise<ITextModel | null> | null;
}
export interface ITextEditorModel extends IEditorModel {

View File

@@ -94,6 +94,7 @@ export const enum MenuId {
SCMSourceControl,
SCMTitle,
SearchContext,
StatusBarWindowIndicatorMenu,
TouchBarContext,
ViewItemContext,
ViewTitle,

View File

@@ -12,11 +12,11 @@ export class DialogChannel implements IServerChannel {
constructor(@IDialogService private readonly dialogService: IDialogService) { }
listen<T>(_, event: string): Event<T> {
listen<T>(_: unknown, event: string): Event<T> {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, args?: any[]): Promise<any> {
call(_: unknown, command: string, args?: any[]): Promise<any> {
switch (command) {
case 'show': return this.dialogService.show(args![0], args![1], args![2]);
case 'confirm': return this.dialogService.confirm(args![0]);

View File

@@ -29,7 +29,7 @@ export class DownloadServiceChannel implements IServerChannel {
constructor() { }
listen(_, event: string, arg?: any): Event<any> {
listen(_: unknown, event: string, arg?: any): Event<any> {
switch (event) {
case 'upload': return Event.buffer(upload(URI.revive(arg)));
}
@@ -37,7 +37,7 @@ export class DownloadServiceChannel implements IServerChannel {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string): Promise<any> {
call(_: unknown, command: string): Promise<any> {
throw new Error(`Call not found: ${command}`);
}
}

View File

@@ -48,11 +48,11 @@ export class DriverChannel implements IServerChannel {
constructor(private driver: IDriver) { }
listen<T>(_, event: string): Event<T> {
listen<T>(_: unknown, event: string): Event<T> {
throw new Error('No event found');
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'getWindowIds': return this.driver.getWindowIds();
case 'capturePage': return this.driver.capturePage(arg);
@@ -150,11 +150,11 @@ export class WindowDriverRegistryChannel implements IServerChannel {
constructor(private registry: IWindowDriverRegistry) { }
listen<T>(_, event: string): Event<T> {
listen<T>(_: unknown, event: string): Event<T> {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'registerWindowDriver': return this.registry.registerWindowDriver(arg);
case 'reloadWindowDriver': return this.registry.reloadWindowDriver(arg);
@@ -195,11 +195,11 @@ export class WindowDriverChannel implements IServerChannel {
constructor(private driver: IWindowDriver) { }
listen<T>(_, event: string): Event<T> {
listen<T>(_: unknown, event: string): Event<T> {
throw new Error(`No event found: ${event}`);
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'click': return this.driver.click(arg[0], arg[1], arg[2]);
case 'doubleClick': return this.driver.doubleClick(arg);

View File

@@ -153,7 +153,8 @@ export interface ITranslation {
export interface IExtensionGalleryService {
_serviceBrand: any;
isEnabled(): boolean;
query(options?: IQueryOptions): Promise<IPager<IGalleryExtension>>;
query(token: CancellationToken): Promise<IPager<IGalleryExtension>>;
query(options: IQueryOptions, token: CancellationToken): Promise<IPager<IGalleryExtension>>;
download(extension: IGalleryExtension, operation: InstallOperation): Promise<string>;
reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise<void>;
getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string>;

View File

@@ -451,7 +451,12 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
});
}
query(options: IQueryOptions = {}): Promise<IPager<IGalleryExtension>> {
query(token: CancellationToken): Promise<IPager<IGalleryExtension>>;
query(options: IQueryOptions, token: CancellationToken): Promise<IPager<IGalleryExtension>>;
query(arg1: any, arg2?: any): Promise<IPager<IGalleryExtension>> {
const options: IQueryOptions = CancellationToken.isCancellationToken(arg1) ? {} : arg1;
const token: CancellationToken = CancellationToken.isCancellationToken(arg1) ? arg1 : arg2;
if (!this.isEnabled()) {
return Promise.reject(new Error('No extension gallery service configured.'));
}
@@ -511,7 +516,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
query = query.withSortOrder(options.sortOrder);
}
return this.queryGallery(query, CancellationToken.None).then(({ galleryExtensions, total }) => {
return this.queryGallery(query, token).then(({ galleryExtensions, total }) => {
const extensions = galleryExtensions.map((e, index) => toExtension(e, e.versions[0], index, query, options.source));
// {{SQL CARBON EDIT}}
const pageSize = extensions.length;

View File

@@ -318,9 +318,6 @@ export class ExtensionManagementService extends Disposable implements IExtension
const existingExtension = installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0];
if (existingExtension) {
operation = InstallOperation.Update;
if (semver.gt(existingExtension.manifest.version, extension.version)) {
await this.uninstall(existingExtension, true);
}
}
this.downloadInstallableExtension(extension, operation)
@@ -329,7 +326,10 @@ export class ExtensionManagementService extends Disposable implements IExtension
.then(local => this.installDependenciesAndPackExtensions(local, existingExtension)
.then(() => local, error => this.uninstall(local, true).then(() => Promise.reject(error), () => Promise.reject(error))))
.then(
local => {
async local => {
if (existingExtension && semver.neq(existingExtension.manifest.version, extension.version)) {
await this.setUninstalled(existingExtension);
}
this.installingExtensions.delete(key);
onDidInstallExtensionSuccess(extension, operation, local);
successCallback(null);
@@ -529,7 +529,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
// filter out installed extensions
const names = dependenciesAndPackExtensions.filter(id => installed.every(({ identifier: galleryIdentifier }) => !areSameExtensions(galleryIdentifier, { id })));
if (names.length) {
return this.galleryService.query({ names, pageSize: dependenciesAndPackExtensions.length })
return this.galleryService.query({ names, pageSize: dependenciesAndPackExtensions.length }, CancellationToken.None)
.then(galleryResult => {
const extensionsToInstall = galleryResult.firstPage;
return Promise.all(extensionsToInstall.map(async e => {
@@ -609,11 +609,11 @@ export class ExtensionManagementService extends Disposable implements IExtension
}
private findGalleryExtensionById(uuid: string): Promise<IGalleryExtension> {
return this.galleryService.query({ ids: [uuid], pageSize: 1 }).then(galleryResult => galleryResult.firstPage[0]);
return this.galleryService.query({ ids: [uuid], pageSize: 1 }, CancellationToken.None).then(galleryResult => galleryResult.firstPage[0]);
}
private findGalleryExtensionByName(name: string): Promise<IGalleryExtension> {
return this.galleryService.query({ names: [name], pageSize: 1 }).then(galleryResult => galleryResult.firstPage[0]);
return this.galleryService.query({ names: [name], pageSize: 1 }, CancellationToken.None).then(galleryResult => galleryResult.firstPage[0]);
}
private joinErrors(errorOrErrors: (Error | string) | (Array<Error | string>)): Error {

View File

@@ -701,7 +701,16 @@ export interface IUpdateContentOptions {
}
export interface IResolveFileOptions {
/**
* Automatically continue resolving children of a directory until the provided resources
* are found.
*/
resolveTo?: URI[];
/**
* Automatically continue resolving children of a directory if the number of children is 1.
*/
resolveSingleChildDescendants?: boolean;
}
@@ -1034,12 +1043,6 @@ export interface ILegacyFileService {
onFileChanges: Event<FileChangesEvent>;
onAfterOperation: Event<FileOperationEvent>;
resolveFile(resource: URI, options?: IResolveFileOptions): Promise<IFileStat>;
resolveFiles(toResolve: { resource: URI, options?: IResolveFileOptions }[]): Promise<IResolveFileResult[]>;
existsFile(resource: URI): Promise<boolean>;
resolveContent(resource: URI, options?: IResolveContentOptions): Promise<IContent>;
resolveStreamContent(resource: URI, options?: IResolveContentOptions): Promise<IStreamContent>;
@@ -1057,4 +1060,4 @@ export interface ILegacyFileService {
watchFileChanges(resource: URI): void;
unwatchFileChanges(resource: URI): void;
}
}

View File

@@ -42,7 +42,7 @@ suite('Files', () => {
assert.strictEqual(true, r1.gotDeleted());
});
function testIsEqual(testMethod: (pA: string | null | undefined, pB: string, ignoreCase: boolean) => boolean): void {
function testIsEqual(testMethod: (pA: string | undefined, pB: string, ignoreCase: boolean) => boolean): void {
// corner cases
assert(testMethod('', '', true));

View File

@@ -35,12 +35,12 @@ export class TestInstantiationService extends InstantiationService {
return <T>this._create(service, { mock: true });
}
public stub<T>(service: ServiceIdentifier<T>, ctor?: any): T;
public stub<T>(service: ServiceIdentifier<T>, obj?: any): T;
public stub<T>(service: ServiceIdentifier<T>, ctor?: any, property?: string, value?: any): sinon.SinonStub;
public stub<T>(service: ServiceIdentifier<T>, obj?: any, property?: string, value?: any): sinon.SinonStub;
public stub<T>(service: ServiceIdentifier<T>, property?: string, value?: any): sinon.SinonStub;
public stub<T>(serviceIdentifier: ServiceIdentifier<T>, arg2?: any, arg3?: string, arg4?: any): sinon.SinonStub {
public stub<T>(service: ServiceIdentifier<T>, ctor: Function): T;
public stub<T>(service: ServiceIdentifier<T>, obj: Partial<T>): T;
public stub<T>(service: ServiceIdentifier<T>, ctor: Function, property: string, value: any): sinon.SinonStub;
public stub<T>(service: ServiceIdentifier<T>, obj: Partial<T>, property: string, value: any): sinon.SinonStub;
public stub<T>(service: ServiceIdentifier<T>, property: string, value: any): sinon.SinonStub;
public stub<T>(serviceIdentifier: ServiceIdentifier<T>, arg2: any, arg3?: string, arg4?: any): sinon.SinonStub {
let service = typeof arg2 !== 'string' ? arg2 : undefined;
let serviceMock: IServiceMock<any> = { id: serviceIdentifier, service: service };
let property = typeof arg2 === 'string' ? arg2 : arg3;

View File

@@ -50,7 +50,7 @@ export class IssueService implements IIssueService {
});
});
ipcMain.on('vscode:issueReporterConfirmClose', (_) => {
ipcMain.on('vscode:issueReporterConfirmClose', () => {
const messageOptions = {
message: localize('confirmCloseIssueReporter', "Your input will not be saved. Are you sure you want to close this window?"),
type: 'warning',
@@ -72,7 +72,7 @@ export class IssueService implements IIssueService {
}
});
ipcMain.on('vscode:workbenchCommand', (_, commandInfo) => {
ipcMain.on('vscode:workbenchCommand', (_: unknown, commandInfo) => {
const { id, from, args } = commandInfo;
let parentWindow: BrowserWindow | null;
@@ -92,7 +92,7 @@ export class IssueService implements IIssueService {
}
});
ipcMain.on('vscode:openExternal', (_, arg) => {
ipcMain.on('vscode:openExternal', (_: unknown, arg) => {
this.windowsService.openExternal(arg);
});

View File

@@ -11,11 +11,11 @@ export class IssueChannel implements IServerChannel {
constructor(private service: IIssueService) { }
listen<T>(_, event: string): Event<T> {
listen<T>(_: unknown, event: string): Event<T> {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'openIssueReporter':
return this.service.openReporter(arg);

View File

@@ -70,11 +70,11 @@ export class LaunchChannel implements IServerChannel {
constructor(private service: ILaunchService) { }
listen<T>(_, event: string): Event<T> {
listen<T>(_: unknown, event: string): Event<T> {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg: any): Promise<any> {
call(_: unknown, command: string, arg: any): Promise<any> {
switch (command) {
case 'start':
const { args, userEnv } = arg as IStartArguments;

View File

@@ -15,7 +15,7 @@ export class LocalizationsChannel implements IServerChannel {
this.onDidLanguagesChange = Event.buffer(service.onDidLanguagesChange, true);
}
listen(_, event: string): Event<any> {
listen(_: unknown, event: string): Event<any> {
switch (event) {
case 'onDidLanguagesChange': return this.onDidLanguagesChange;
}
@@ -23,7 +23,7 @@ export class LocalizationsChannel implements IServerChannel {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'getLanguageIds': return this.service.getLanguageIds(arg);
}

View File

@@ -15,7 +15,7 @@ export class LogLevelSetterChannel implements IServerChannel {
this.onDidChangeLogLevel = Event.buffer(service.onDidChangeLogLevel, true);
}
listen(_, event: string): Event<any> {
listen(_: unknown, event: string): Event<any> {
switch (event) {
case 'onDidChangeLogLevel': return this.onDidChangeLogLevel;
}
@@ -23,7 +23,7 @@ export class LogLevelSetterChannel implements IServerChannel {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'setLevel': this.service.setLevel(arg); return Promise.resolve();
}

View File

@@ -11,11 +11,11 @@ export class MenubarChannel implements IServerChannel {
constructor(private service: IMenubarService) { }
listen<T>(_, event: string): Event<T> {
listen<T>(_: unknown, event: string): Event<T> {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'updateMenubar': return this.service.updateMenubar(arg[0], arg[1]);
}

View File

@@ -5,13 +5,21 @@
import { URI } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IDisposable } from 'vs/base/common/lifecycle';
export const IOpenerService = createDecorator<IOpenerService>('openerService');
export interface IOpener {
open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean>;
}
export interface IOpenerService {
_serviceBrand: any;
registerOpener(opener: IOpener): IDisposable;
/**
* Opens a resource, like a webadress, a document uri, or executes command.
*
@@ -23,5 +31,6 @@ export interface IOpenerService {
export const NullOpenerService: IOpenerService = Object.freeze({
_serviceBrand: undefined,
registerOpener() { return { dispose() { } }; },
open() { return Promise.resolve(false); }
});

View File

@@ -104,7 +104,7 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
return { items: mapToSerializable(items) } as ISerializableItemsChangeEvent;
}
listen(_, event: string): Event<any> {
listen(_: unknown, event: string): Event<any> {
switch (event) {
case 'onDidChangeItems': return this.onDidChangeItems;
}
@@ -112,7 +112,7 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'getItems': {
return this.whenReady.then(() => mapToSerializable(this.storageMainService.items));

View File

@@ -16,11 +16,11 @@ export class TelemetryAppenderChannel implements IServerChannel {
constructor(private appender: ITelemetryAppender) { }
listen<T>(_, event: string): Event<T> {
listen<T>(_: unknown, event: string): Event<T> {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, { eventName, data }: ITelemetryLog): Promise<any> {
call(_: unknown, command: string, { eventName, data }: ITelemetryLog): Promise<any> {
this.appender.log(eventName, data);
return Promise.resolve(null);
}

View File

@@ -11,7 +11,7 @@ export class UpdateChannel implements IServerChannel {
constructor(private service: IUpdateService) { }
listen(_, event: string): Event<any> {
listen(_: unknown, event: string): Event<any> {
switch (event) {
case 'onStateChange': return this.service.onStateChange;
}
@@ -19,7 +19,7 @@ export class UpdateChannel implements IServerChannel {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'checkForUpdates': return this.service.checkForUpdates(arg);
case 'downloadUpdate': return this.service.downloadUpdate();

View File

@@ -8,16 +8,21 @@ import { URI } from 'vs/base/common/uri';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { URLServiceChannelClient, URLHandlerChannel } from 'vs/platform/url/node/urlIpc';
import { URLService } from 'vs/platform/url/common/urlService';
import { IOpenerService } from 'vs/platform/opener/common/opener';
export class RelayURLService extends URLService implements IURLHandler {
private urlService: IURLService;
constructor(@IMainProcessService mainProcessService: IMainProcessService) {
constructor(
@IMainProcessService mainProcessService: IMainProcessService,
@IOpenerService openerService: IOpenerService
) {
super();
this.urlService = new URLServiceChannelClient(mainProcessService.getChannel('url'));
mainProcessService.registerChannel('urlHandler', new URLHandlerChannel(this));
openerService.registerOpener(this);
}
open(uri: URI): Promise<boolean> {

View File

@@ -13,11 +13,11 @@ export class URLServiceChannel implements IServerChannel {
constructor(private service: IURLService) { }
listen<T>(_, event: string): Event<T> {
listen<T>(_: unknown, event: string): Event<T> {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'open': return this.service.open(URI.revive(arg));
}
@@ -45,11 +45,11 @@ export class URLHandlerChannel implements IServerChannel {
constructor(private handler: IURLHandler) { }
listen<T>(_, event: string): Event<T> {
listen<T>(_: unknown, event: string): Event<T> {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'handleURL': return this.handler.handleURL(URI.revive(arg));
}

View File

@@ -28,7 +28,7 @@ export class WindowsChannel implements IServerChannel {
this.onRecentlyOpenedChange = Event.buffer(service.onRecentlyOpenedChange, true);
}
listen(_, event: string): Event<any> {
listen(_: unknown, event: string): Event<any> {
switch (event) {
case 'onWindowOpen': return this.onWindowOpen;
case 'onWindowFocus': return this.onWindowFocus;
@@ -41,7 +41,7 @@ export class WindowsChannel implements IServerChannel {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'pickFileFolderAndOpen': return this.service.pickFileFolderAndOpen(arg);
case 'pickFileAndOpen': return this.service.pickFileAndOpen(arg);

View File

@@ -12,11 +12,11 @@ export class WorkspacesChannel implements IServerChannel {
constructor(private service: IWorkspacesMainService) { }
listen<T>(_, event: string): Event<T> {
listen<T>(_: unknown, event: string): Event<T> {
throw new Error(`Event not found: ${event}`);
}
call(_, command: string, arg?: any): Promise<any> {
call(_: unknown, command: string, arg?: any): Promise<any> {
switch (command) {
case 'createUntitledWorkspace': {
const rawFolders: IWorkspaceFolderCreationData[] = arg[0];

View File

@@ -6,10 +6,10 @@
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { MainContext, MainThreadConsoleShape, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IRemoteConsoleLog, log, parse } from 'vs/base/node/console';
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/electron-browser/extensionHost';
import { IRemoteConsoleLog, log, parse } from 'vs/base/common/console';
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService';
import { IBroadcastService } from 'vs/workbench/services/broadcast/common/broadcast';
import { EXTENSION_LOG_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost';
@extHostNamedCustomer(MainContext.MainThreadConsole)

View File

@@ -41,14 +41,14 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
$registerTextContentProvider(handle: number, scheme: string): void {
const registration = this._textModelResolverService.registerTextModelContentProvider(scheme, {
provideTextContent: (uri: URI): Promise<ITextModel | undefined> => {
provideTextContent: (uri: URI): Promise<ITextModel | null> => {
return this._proxy.$provideTextDocumentContent(handle, uri).then(value => {
if (typeof value === 'string') {
const firstLineText = value.substr(0, 1 + value.search(/\r?\n/));
const languageSelection = this._modeService.createByFilepathOrFirstLine(uri.fsPath, firstLineText);
return this._modelService.createModel(value, languageSelection, uri);
}
return undefined;
return null;
});
}
});

View File

@@ -12,7 +12,7 @@ import { IModeService } from 'vs/editor/common/services/modeService';
import { IModelService, shouldSynchronizeModel } from 'vs/editor/common/services/modelService';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IFileService } from 'vs/platform/files/common/files';
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors';
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
import { ExtHostContext, ExtHostDocumentsShape, IExtHostContext, MainThreadDocumentsShape } from 'vs/workbench/api/common/extHost.protocol';
import { ITextEditorModel } from 'vs/workbench/common/editor';
import { ITextFileService, TextFileModelChangeEvent } from 'vs/workbench/services/textfile/common/textfiles';

View File

@@ -17,9 +17,9 @@ import { IModelService, shouldSynchronizeModel } from 'vs/editor/common/services
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IFileService } from 'vs/platform/files/common/files';
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { MainThreadDocuments } from 'vs/workbench/api/electron-browser/mainThreadDocuments';
import { MainThreadTextEditor } from 'vs/workbench/api/electron-browser/mainThreadEditor';
import { MainThreadTextEditors } from 'vs/workbench/api/electron-browser/mainThreadEditors';
import { MainThreadDocuments } from 'vs/workbench/api/browser/mainThreadDocuments';
import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor';
import { MainThreadTextEditors } from 'vs/workbench/api/browser/mainThreadEditors';
import { ExtHostContext, ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IExtHostContext, IModelAddedData, ITextEditorAddData, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import { EditorViewColumn, editorGroupToViewColumn } from 'vs/workbench/api/common/shared/editor';
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';

View File

@@ -18,14 +18,12 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors';
import { MainThreadTextEditor } from 'vs/workbench/api/electron-browser/mainThreadEditor';
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor';
import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, IExtHostContext, ITextDocumentShowOptions, ITextEditorConfigurationUpdate, ITextEditorPositionData, IUndoStopOptions, MainThreadTextEditorsShape, TextEditorRevealType, WorkspaceEditDto, reviveWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol';
import { EditorViewColumn, editorGroupToViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IURLService } from 'vs/platform/url/common/url';
import product from 'vs/platform/product/node/product';
export class MainThreadTextEditors implements MainThreadTextEditorsShape {
@@ -270,7 +268,6 @@ CommandsRegistry.registerCommand('_workbench.open', function (accessor: Services
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);
const openerService = accessor.get(IOpenerService);
const urlService = accessor.get(IURLService);
const [resource, options, position, label] = args;
@@ -282,12 +279,8 @@ CommandsRegistry.registerCommand('_workbench.open', function (accessor: Services
if (resource && resource.scheme === 'command') {
// do not allow to execute commands from here
return Promise.resolve(undefined);
}
if (resource && (resource.scheme === product.urlProtocol || /^vscode/.test(resource.scheme))) {
return urlService.open(resource).then(_ => undefined);
}
// finally, delegate to opener service
return openerService.open(resource).then(_ => undefined);
});

View File

@@ -8,7 +8,6 @@ import Severity from 'vs/base/common/severity';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IExtHostContext, MainContext, MainThreadExtensionServiceShape } from 'vs/workbench/api/common/extHost.protocol';
import { IExtensionService, ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { localize } from 'vs/nls';
@@ -17,11 +16,12 @@ import { EnablementState } from 'vs/platform/extensionManagement/common/extensio
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IExtensionsWorkbenchService, IExtension } from 'vs/workbench/contrib/extensions/common/extensions';
import { CancellationToken } from 'vs/base/common/cancellation';
@extHostNamedCustomer(MainContext.MainThreadExtensionService)
export class MainThreadExtensionService implements MainThreadExtensionServiceShape {
private readonly _extensionService: ExtensionService;
private readonly _extensionService: IExtensionService;
private readonly _notificationService: INotificationService;
private readonly _extensionsWorkbenchService: IExtensionsWorkbenchService;
private readonly _windowService: IWindowService;
@@ -33,9 +33,7 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
@IWindowService windowService: IWindowService
) {
if (extensionService instanceof ExtensionService) {
this._extensionService = extensionService;
}
this._extensionService = extensionService;
this._notificationService = notificationService;
this._extensionsWorkbenchService = extensionsWorkbenchService;
this._windowService = windowService;
@@ -108,7 +106,7 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
private async _handleMissingNotInstalledDependency(extension: IExtensionDescription, missingDependency: string): Promise<void> {
const extName = extension.displayName || extension.name;
const dependencyExtension = (await this._extensionsWorkbenchService.queryGallery({ names: [missingDependency] })).firstPage[0];
const dependencyExtension = (await this._extensionsWorkbenchService.queryGallery({ names: [missingDependency] }, CancellationToken.None)).firstPage[0];
if (dependencyExtension) {
this._notificationService.notify({
severity: Severity.Error,
@@ -124,4 +122,7 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
}
}
$onExtensionHostExit(code: number): void {
this._extensionService._onExtensionHostExit(code);
}
}

View File

@@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ExtHostContext, IExtHostContext } from '../common/extHost.protocol';
import { Disposable } from 'vs/base/common/lifecycle';
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IHeapService } from 'vs/workbench/services/heap/common/heap';
@extHostCustomer
export class MainThreadHeapService extends Disposable {
constructor(
extHostContext: IExtHostContext,
@IHeapService heapService: IHeapService,
) {
super();
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostHeapService);
this._register(heapService.onGarbageCollection((ids) => {
// send to ext host
proxy.$onGarbageCollection(ids);
}));
}
}

View File

@@ -14,15 +14,14 @@ import { Range as EditorRange } from 'vs/editor/common/core/range';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto, ISerializedSignatureHelpProviderMetadata, CodeInsetDto, LinkDto, CallHierarchyDto } from '../common/extHost.protocol';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
import { IHeapService } from './mainThreadHeapService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import { URI } from 'vs/base/common/uri';
import { Selection } from 'vs/editor/common/core/selection';
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { IHeapService } from 'vs/workbench/services/heap/common/heap';
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
@@ -127,7 +126,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- outline
$registerDocumentSymbolProvider(handle: number, selector: ISerializedDocumentFilter[], displayName: string): void {
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentSymbolProvider>{
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(selector, <modes.DocumentSymbolProvider>{
displayName,
provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined> => {
return this._proxy.$provideDocumentSymbols(handle, model.uri, token);
@@ -168,7 +167,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
provider.onDidChange = emitter.event;
}
this._registrations[handle] = modes.CodeLensProviderRegistry.register(typeConverters.LanguageSelector.from(selector), provider);
this._registrations[handle] = modes.CodeLensProviderRegistry.register(selector, provider);
}
$emitCodeLensEvent(eventHandle: number, event?: any): void {
@@ -203,14 +202,14 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
provider.onDidChange = emitter.event;
}
const langSelector = typeConverters.LanguageSelector.from(selector);
const langSelector = selector;
this._registrations[handle] = codeInset.CodeInsetProviderRegistry.register(langSelector, provider);
}
// --- declaration
$registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DefinitionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DefinitionProvider>{
this._registrations[handle] = modes.DefinitionProviderRegistry.register(selector, <modes.DefinitionProvider>{
provideDefinition: (model, position, token): Promise<modes.LocationLink[]> => {
return this._proxy.$provideDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);
}
@@ -218,7 +217,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
$registerDeclarationSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DeclarationProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DeclarationProvider>{
this._registrations[handle] = modes.DeclarationProviderRegistry.register(selector, <modes.DeclarationProvider>{
provideDeclaration: (model, position, token) => {
return this._proxy.$provideDeclaration(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);
}
@@ -226,7 +225,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
$registerImplementationSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.ImplementationProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.ImplementationProvider>{
this._registrations[handle] = modes.ImplementationProviderRegistry.register(selector, <modes.ImplementationProvider>{
provideImplementation: (model, position, token): Promise<modes.LocationLink[]> => {
return this._proxy.$provideImplementation(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);
}
@@ -234,7 +233,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
$registerTypeDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.TypeDefinitionProvider>{
this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(selector, <modes.TypeDefinitionProvider>{
provideTypeDefinition: (model, position, token): Promise<modes.LocationLink[]> => {
return this._proxy.$provideTypeDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);
}
@@ -244,7 +243,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- extra info
$registerHoverProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.HoverProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.HoverProvider>{
this._registrations[handle] = modes.HoverProviderRegistry.register(selector, <modes.HoverProvider>{
provideHover: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.Hover | undefined> => {
return this._proxy.$provideHover(handle, model.uri, position, token);
}
@@ -254,7 +253,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- occurrences
$registerDocumentHighlightProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentHighlightProvider>{
this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(selector, <modes.DocumentHighlightProvider>{
provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.DocumentHighlight[] | undefined> => {
return this._proxy.$provideDocumentHighlights(handle, model.uri, position, token);
}
@@ -264,7 +263,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- references
$registerReferenceSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.ReferenceProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.ReferenceProvider>{
this._registrations[handle] = modes.ReferenceProviderRegistry.register(selector, <modes.ReferenceProvider>{
provideReferences: (model: ITextModel, position: EditorPosition, context: modes.ReferenceContext, token: CancellationToken): Promise<modes.Location[]> => {
return this._proxy.$provideReferences(handle, model.uri, position, context, token).then(MainThreadLanguageFeatures._reviveLocationDto);
}
@@ -274,7 +273,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- quick fix
$registerQuickFixSupport(handle: number, selector: ISerializedDocumentFilter[], providedCodeActionKinds?: string[]): void {
this._registrations[handle] = modes.CodeActionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.CodeActionProvider>{
this._registrations[handle] = modes.CodeActionProviderRegistry.register(selector, <modes.CodeActionProvider>{
provideCodeActions: (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: modes.CodeActionContext, token: CancellationToken): Promise<modes.CodeAction[]> => {
return this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token).then(dto => {
if (dto) {
@@ -290,7 +289,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- formatting
$registerDocumentFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], extensionId: ExtensionIdentifier): void {
this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentFormattingEditProvider>{
this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(selector, <modes.DocumentFormattingEditProvider>{
extensionId,
provideDocumentFormattingEdits: (model: ITextModel, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
return this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options, token);
@@ -299,7 +298,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
$registerRangeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], extensionId: ExtensionIdentifier): void {
this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentRangeFormattingEditProvider>{
this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(selector, <modes.DocumentRangeFormattingEditProvider>{
extensionId,
provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
return this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options, token);
@@ -308,7 +307,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
$registerOnTypeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void {
this._registrations[handle] = modes.OnTypeFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.OnTypeFormattingEditProvider>{
this._registrations[handle] = modes.OnTypeFormattingEditProviderRegistry.register(selector, <modes.OnTypeFormattingEditProvider>{
extensionId,
autoFormatTriggerCharacters,
provideOnTypeFormattingEdits: (model: ITextModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
@@ -346,7 +345,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerRenameSupport(handle: number, selector: ISerializedDocumentFilter[], supportResolveLocation: boolean): void {
this._registrations[handle] = modes.RenameProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.RenameProvider>{
this._registrations[handle] = modes.RenameProviderRegistry.register(selector, <modes.RenameProvider>{
provideRenameEdits: (model: ITextModel, position: EditorPosition, newName: string, token: CancellationToken): Promise<modes.WorkspaceEdit> => {
return this._proxy.$provideRenameEdits(handle, model.uri, position, newName, token).then(reviveWorkspaceEditDto);
},
@@ -359,7 +358,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- suggest
$registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean): void {
this._registrations[handle] = modes.CompletionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.CompletionItemProvider>{
this._registrations[handle] = modes.CompletionProviderRegistry.register(selector, <modes.CompletionItemProvider>{
triggerCharacters,
provideCompletionItems: (model: ITextModel, position: EditorPosition, context: modes.CompletionContext, token: CancellationToken): Promise<modes.CompletionList | undefined> => {
return this._proxy.$provideCompletionItems(handle, model.uri, position, context, token).then(result => {
@@ -386,7 +385,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- parameter hints
$registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], metadata: ISerializedSignatureHelpProviderMetadata): void {
this._registrations[handle] = modes.SignatureHelpProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.SignatureHelpProvider>{
this._registrations[handle] = modes.SignatureHelpProviderRegistry.register(selector, <modes.SignatureHelpProvider>{
signatureHelpTriggerCharacters: metadata.triggerCharacters,
signatureHelpRetriggerCharacters: metadata.retriggerCharacters,
@@ -400,7 +399,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- links
$registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.LinkProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.LinkProvider>{
this._registrations[handle] = modes.LinkProviderRegistry.register(selector, <modes.LinkProvider>{
provideLinks: (model, token) => {
return this._proxy.$provideDocumentLinks(handle, model.uri, token).then(dto => {
if (dto) {
@@ -428,7 +427,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerDocumentColorProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
const proxy = this._proxy;
this._registrations[handle] = modes.ColorProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentColorProvider>{
this._registrations[handle] = modes.ColorProviderRegistry.register(selector, <modes.DocumentColorProvider>{
provideDocumentColors: (model, token) => {
return proxy.$provideDocumentColors(handle, model.uri, token)
.then(documentColors => {
@@ -462,7 +461,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerFoldingRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
const proxy = this._proxy;
this._registrations[handle] = modes.FoldingRangeProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.FoldingRangeProvider>{
this._registrations[handle] = modes.FoldingRangeProviderRegistry.register(selector, <modes.FoldingRangeProvider>{
provideFoldingRanges: (model, context, token) => {
return proxy.$provideFoldingRanges(handle, model.uri, context, token);
}
@@ -472,7 +471,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// -- smart select
$registerSelectionRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.SelectionRangeRegistry.register(typeConverters.LanguageSelector.from(selector), {
this._registrations[handle] = modes.SelectionRangeRegistry.register(selector, {
provideSelectionRanges: (model, positions, token) => {
return this._proxy.$provideSelectionRanges(handle, model.uri, positions, token);
}
@@ -482,7 +481,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- call hierarchy
$registerCallHierarchyProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = callh.CallHierarchyProviderRegistry.register(typeConverters.LanguageSelector.from(selector), {
this._registrations[handle] = callh.CallHierarchyProviderRegistry.register(selector, {
provideCallHierarchyItem: (document, position, token) => {
return this._proxy.$provideCallHierarchyItem(handle, document.uri, position, token).then(MainThreadLanguageFeatures._reviveCallHierarchyItemDto);
},

View File

@@ -263,7 +263,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
const timeout = this._configurationService.getValue<number>('editor.formatOnSaveTimeout', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() });
return new Promise<TextEdit[] | null | undefined>((resolve, reject) => {
return new Promise<TextEdit[] | null>((resolve, reject) => {
const source = new CancellationTokenSource();
const request = getDocumentFormattingEdits(this._telemetryService, this._editorWorkerService, model, model.getFormattingOptions(), FormatMode.Auto, source.token);

View File

@@ -8,7 +8,7 @@ import { extHostNamedCustomer } from '../common/extHostCustomers';
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
import { URI } from 'vs/base/common/uri';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler';
import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
class ExtensionUrlHandler implements IURLHandler {

View File

@@ -44,6 +44,8 @@ import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityReso
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { IRelativePattern } from 'vs/base/common/glob';
import { IRemoteConsoleLog } from 'vs/base/common/console';
// {{SQL CARBON EDIT}}
import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
@@ -310,7 +312,7 @@ export interface ISerializedDocumentFilter {
$serialized: true;
language?: string;
scheme?: string;
pattern?: GlobPattern;
pattern?: string | IRelativePattern;
exclusive?: boolean;
}
@@ -610,6 +612,7 @@ export interface MainThreadExtensionServiceShape extends IDisposable {
$onDidActivateExtension(extensionId: ExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string | null): void;
$onExtensionActivationError(extensionId: ExtensionIdentifier, error: ExtensionActivationError): Promise<void>;
$onExtensionRuntimeError(extensionId: ExtensionIdentifier, error: SerializedError): void;
$onExtensionHostExit(code: number): void;
}
export interface SCMProviderFeatures {

View File

@@ -35,11 +35,13 @@ namespace schema {
case 'editor/title/context': return MenuId.EditorTitleContext;
case 'debug/callstack/context': return MenuId.DebugCallStackContext;
case 'debug/toolbar': return MenuId.DebugToolbar;
case 'menuBar/file': return MenuId.MenubarFileMenu;
case 'scm/title': return MenuId.SCMTitle;
case 'scm/sourceControl': return MenuId.SCMSourceControl;
case 'scm/resourceGroup/context': return MenuId.SCMResourceGroupContext;
case 'scm/resourceState/context': return MenuId.SCMResourceContext;
case 'scm/change/title': return MenuId.SCMChangeContext;
case 'statusBar/windowIndicator': return MenuId.StatusBarWindowIndicatorMenu;
case 'view/title': return MenuId.ViewTitle;
case 'view/item/context': return MenuId.ViewItemContext;
// {{SQL CARBON EDIT}}

View File

@@ -14,19 +14,28 @@ import { ColorExtensionPoint } from 'vs/workbench/services/themes/common/colorEx
import { LanguageConfigurationFileHandler } from 'vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint';
// --- mainThread participants
import 'vs/workbench/api/node/apiCommands';
import '../browser/mainThreadClipboard';
import '../browser/mainThreadCommands';
import '../browser/mainThreadConfiguration';
import '../browser/mainThreadConsole';
// {{SQL CARBON EDIT}}
// import '../browser/mainThreadDebugService';
import '../browser/mainThreadDecorations';
import '../browser/mainThreadDiagnostics';
import '../browser/mainThreadDialogs';
import '../browser/mainThreadDocumentContentProviders';
import '../browser/mainThreadDocuments';
import '../browser/mainThreadDocumentsAndEditors';
import '../browser/mainThreadEditor';
import '../browser/mainThreadEditors';
import '../browser/mainThreadErrors';
import '../browser/mainThreadExtensionService';
import '../browser/mainThreadFileSystem';
import '../browser/mainThreadFileSystemEventService';
import '../browser/mainThreadHeapService';
import '../browser/mainThreadLanguageFeatures';
import '../browser/mainThreadLanguages';
import '../browser/mainThreadLogService';
import '../browser/mainThreadMessageService';
import '../browser/mainThreadOutputService';
import '../browser/mainThreadProgress';
@@ -36,25 +45,16 @@ import '../browser/mainThreadSCM';
import '../browser/mainThreadSearch';
import '../browser/mainThreadStatusBar';
import '../browser/mainThreadStorage';
import './mainThreadComments';
import './mainThreadConsole';
import './mainThreadDocuments';
import './mainThreadDocumentsAndEditors';
import './mainThreadEditor';
import './mainThreadEditors';
import './mainThreadExtensionService';
import './mainThreadHeapService';
import './mainThreadLanguageFeatures';
import '../browser/mainThreadLanguages';
import '../browser/mainThreadLogService';
import './mainThreadTask';
import '../browser/mainThreadTelemetry';
import '../browser/mainThreadTerminalService';
import '../browser/mainThreadTreeViews';
import './mainThreadUrls';
import './mainThreadWebview';
import '../browser/mainThreadUrls';
import '../browser/mainThreadWindow';
import '../browser/mainThreadWorkspace';
import './mainThreadComments';
import './mainThreadTask';
import './mainThreadWebview';
import 'vs/workbench/api/node/apiCommands';
export class ExtensionPoints implements IWorkbenchContribution {

View File

@@ -68,6 +68,25 @@ CommandsRegistry.registerCommand({
}
});
interface INewWindowAPICommandOptions {
}
export class NewWindowAPICommand {
public static ID = 'vscode.newWindow';
public static execute(executor: ICommandsExecutor, options?: INewWindowAPICommandOptions): Promise<any> {
return executor.executeCommand('_files.newWindow', [options]);
}
}
CommandsRegistry.registerCommand({
id: NewWindowAPICommand.ID,
handler: adjustHandler(NewWindowAPICommand.execute),
description: {
description: 'Opens an new window',
args: [
]
}
});
export class DiffAPICommand {
public static ID = 'vscode.diff';
public static execute(executor: ICommandsExecutor, left: URI, right: URI, label: string, options?: vscode.TextDocumentShowOptions): Promise<any> {

View File

@@ -67,6 +67,7 @@ import * as vscode from 'vscode';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { originalFSPath } from 'vs/base/common/resources';
import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
import { withNullAsUndefined } from 'vs/base/common/types';
export interface IExtensionApiFactory {
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
@@ -537,7 +538,7 @@ export function createApiFactory(
return extHostWorkspace.getRelativePath(pathOrUri, includeWorkspace);
},
findFiles: (include, exclude, maxResults?, token?) => {
return extHostWorkspace.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(exclude), maxResults, extension.identifier, token);
return extHostWorkspace.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(withNullAsUndefined(exclude)), maxResults, extension.identifier, token);
},
findTextInFiles: (query: vscode.TextSearchQuery, optionsOrCallback, callbackOrToken?, token?: vscode.CancellationToken) => {
let options: vscode.FindTextInFilesOptions;

View File

@@ -642,7 +642,14 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
private _gracefulExit(code: number): void {
// to give the PH process a chance to flush any outstanding console
// messages to the main process, we delay the exit() by some time
setTimeout(() => this._nativeExit(code), 500);
setTimeout(() => {
if (!!this._initData.environment.extensionTestsLocationURI) {
// If extension tests are running, give the exit code to the renderer
this._mainThreadExtensionsProxy.$onExtensionHostExit(code);
return;
}
this._nativeExit(code);
}, 500);
}
private _startExtensionHost(): Promise<void> {

View File

@@ -1082,7 +1082,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
$serialized: true,
language: selector.language,
scheme: this._transformScheme(selector.scheme),
pattern: selector.pattern,
pattern: typeof selector.pattern === 'undefined' ? undefined : typeConvert.GlobPattern.from(selector.pattern),
exclusive: selector.exclusive
};
}

View File

@@ -986,9 +986,9 @@ export namespace TextEditorOptions {
export namespace GlobPattern {
export function from(pattern: vscode.GlobPattern): string | types.RelativePattern;
export function from(pattern: undefined | null): undefined | null;
export function from(pattern: vscode.GlobPattern | undefined | null): string | types.RelativePattern | undefined | null;
export function from(pattern: vscode.GlobPattern | undefined | null): string | types.RelativePattern | undefined | null {
export function from(pattern: undefined): undefined;
export function from(pattern: vscode.GlobPattern | undefined): string | types.RelativePattern | undefined;
export function from(pattern: vscode.GlobPattern | undefined): string | types.RelativePattern | undefined {
if (pattern instanceof types.RelativePattern) {
return pattern;
}

View File

@@ -388,7 +388,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
// --- search ---
findFiles(include: string | RelativePattern | undefined | null, exclude: vscode.GlobPattern | undefined | null, maxResults: number | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.Uri[]> {
findFiles(include: string | RelativePattern | undefined, exclude: vscode.GlobPattern | undefined, maxResults: number | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.Uri[]> {
this._logService.trace(`extHostWorkspace#findFiles: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles`);
let includePattern: string | undefined;

View File

@@ -288,7 +288,9 @@ export class SimpleExtensionGalleryService implements IExtensionGalleryService {
return false;
}
query(options?: IQueryOptions): Promise<IPager<IGalleryExtension>> {
query(token: CancellationToken): Promise<IPager<IGalleryExtension>>;
query(options: IQueryOptions, token: CancellationToken): Promise<IPager<IGalleryExtension>>;
query(arg1: any, arg2?: any): Promise<IPager<IGalleryExtension>> {
// @ts-ignore
return Promise.resolve(undefined);
}

View File

@@ -28,7 +28,7 @@ export class BinaryResourceDiffEditor extends SideBySideEditor {
super(telemetryService, instantiationService, themeService, storageService);
}
getMetadata(): string | null {
getMetadata(): string | undefined {
const master = this.masterEditor;
const details = this.detailsEditor;
@@ -36,6 +36,6 @@ export class BinaryResourceDiffEditor extends SideBySideEditor {
return nls.localize('metadataDiff', "{0} ↔ {1}", details.getMetadata(), master.getMetadata());
}
return null;
return undefined;
}
}

View File

@@ -37,7 +37,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
get onDidOpenInPlace(): Event<void> { return this._onDidOpenInPlace.event; }
private callbacks: IOpenCallbacks;
private metadata: string | null;
private metadata: string | undefined;
private binaryContainer: HTMLElement;
private scrollbar: DomScrollableElement;
private resourceViewerContext: ResourceViewerContext;
@@ -110,20 +110,20 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
});
}
private handleMetadataChanged(meta: string | null): void {
private handleMetadataChanged(meta: string | undefined): void {
this.metadata = meta;
this._onMetadataChanged.fire();
}
getMetadata() {
getMetadata(): string | undefined {
return this.metadata;
}
clearInput(): void {
// Clear Meta
this.handleMetadataChanged(null);
this.handleMetadataChanged(undefined);
// Clear Resource Viewer
clearNode(this.binaryContainer);

View File

@@ -143,43 +143,35 @@ interface StateDelta {
indentation?: string;
tabFocusMode?: boolean;
screenReaderMode?: boolean;
metadata?: string | null;
metadata?: string | undefined;
}
class State {
private _selectionStatus: string | null | undefined;
get selectionStatus(): string | null | undefined { return this._selectionStatus; }
private _selectionStatus: string | undefined;
get selectionStatus(): string | undefined { return this._selectionStatus; }
private _mode: string | null | undefined;
get mode(): string | null | undefined { return this._mode; }
private _mode: string | undefined;
get mode(): string | undefined { return this._mode; }
private _encoding: string | null | undefined;
get encoding(): string | null | undefined { return this._encoding; }
private _encoding: string | undefined;
get encoding(): string | undefined { return this._encoding; }
private _EOL: string | null | undefined;
get EOL(): string | null | undefined { return this._EOL; }
private _EOL: string | undefined;
get EOL(): string | undefined { return this._EOL; }
private _indentation: string | null | undefined;
get indentation(): string | null | undefined { return this._indentation; }
private _indentation: string | undefined;
get indentation(): string | undefined { return this._indentation; }
private _tabFocusMode: boolean | null | undefined;
get tabFocusMode(): boolean | null | undefined { return this._tabFocusMode; }
private _tabFocusMode: boolean | undefined;
get tabFocusMode(): boolean | undefined { return this._tabFocusMode; }
private _screenReaderMode: boolean | null | undefined;
get screenReaderMode(): boolean | null | undefined { return this._screenReaderMode; }
private _screenReaderMode: boolean | undefined;
get screenReaderMode(): boolean | undefined { return this._screenReaderMode; }
private _metadata: string | null | undefined;
get metadata(): string | null | undefined { return this._metadata; }
private _metadata: string | undefined;
get metadata(): string | undefined { return this._metadata; }
constructor() {
this._selectionStatus = null;
this._mode = null;
this._encoding = null;
this._EOL = null;
this._tabFocusMode = false;
this._screenReaderMode = false;
this._metadata = null;
}
constructor() { }
update(update: StateDelta): StateChange {
const change = new StateChange();

View File

@@ -6,7 +6,7 @@
import 'vs/css!./media/statusbarpart';
import * as nls from 'vs/nls';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { dispose, IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { dispose, IDisposable, toDisposable, combinedDisposable, Disposable } from 'vs/base/common/lifecycle';
import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
import { Registry } from 'vs/platform/registry/common/platform';
import { ICommandService } from 'vs/platform/commands/common/commands';
@@ -49,6 +49,8 @@ export class StatusbarPart extends Part implements IStatusbarService {
private statusMsgDispose: IDisposable;
private styleElement: HTMLStyleElement;
private pendingEntries: { entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number, disposable: IDisposable }[] = [];
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@@ -67,6 +69,18 @@ export class StatusbarPart extends Part implements IStatusbarService {
addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IDisposable {
// As long as we have not been created into a container yet, record all entries
// that are pending so that they can get created at a later point
if (!this.element) {
const pendingEntry = { entry, alignment, priority, disposable: Disposable.None };
this.pendingEntries.push(pendingEntry);
return toDisposable(() => {
this.pendingEntries = this.pendingEntries.filter(e => e !== pendingEntry);
pendingEntry.disposable.dispose();
});
}
// Render entry in status bar
const el = this.doCreateStatusItem(alignment, priority, entry.showBeak ? 'has-beak' : undefined);
const item = this.instantiationService.createInstance(StatusBarEntryItem, entry);
@@ -146,6 +160,14 @@ export class StatusbarPart extends Part implements IStatusbarService {
this.element.appendChild(el);
}
// Fill in pending entries if any
while (this.pendingEntries.length) {
const entry = this.pendingEntries.shift();
if (entry) {
entry.disposable = this.addEntry(entry.entry, entry.alignment, entry.priority);
}
}
return this.element;
}

View File

@@ -123,6 +123,9 @@ export class MenubarControl extends Disposable {
this.menuUpdater = this._register(new RunOnceScheduler(() => this.doUpdateMenubar(false), 200));
this._onVisibilityChange = this._register(new Emitter<boolean>());
this._onFocusStateChange = this._register(new Emitter<boolean>());
if (isMacintosh || this.currentTitlebarStyleSetting !== 'custom') {
for (const topLevelMenuName of Object.keys(this.topLevelMenus)) {
const menu = this.topLevelMenus[topLevelMenuName];
@@ -130,15 +133,14 @@ export class MenubarControl extends Disposable {
this._register(menu.onDidChange(() => this.updateMenubar()));
}
}
this.doUpdateMenubar(true);
}
this._onVisibilityChange = this._register(new Emitter<boolean>());
this._onFocusStateChange = this._register(new Emitter<boolean>());
this.windowService.getRecentlyOpened().then((recentlyOpened) => {
this.recentlyOpened = recentlyOpened;
if (isMacintosh || this.currentTitlebarStyleSetting !== 'custom') {
this.doUpdateMenubar(true);
}
});
this.notifyExistingLinuxUser();

View File

@@ -179,7 +179,7 @@ export class TitlebarPart extends Part implements ITitleService {
}
private updateRepresentedFilename(): void {
const file = toResource(this.editorService.activeEditor || null, { supportSideBySide: true, filter: 'file' });
const file = toResource(this.editorService.activeEditor, { supportSideBySide: true, filter: 'file' });
const path = file ? file.fsPath : '';
// Apply to window
@@ -282,7 +282,7 @@ export class TitlebarPart extends Part implements ITitleService {
// Compute folder resource
// Single Root Workspace: always the root single workspace in this case
// Otherwise: root folder of the currently active file if any
const folder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? workspace.folders[0] : this.contextService.getWorkspaceFolder(toResource(editor || null, { supportSideBySide: true })!);
const folder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? workspace.folders[0] : this.contextService.getWorkspaceFolder(toResource(editor, { supportSideBySide: true })!);
// Variables
const activeEditorShort = editor ? editor.getTitle(Verbosity.SHORT) : '';

View File

@@ -17,7 +17,7 @@ import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { PeekContext } from 'vs/editor/contrib/referenceSearch/peekViewWidget';
const _ctxHasCompletionItemProvider = new RawContextKey<boolean>('editorHasCallHierarchyProvider', false);
const _ctxCallHierarchyVisible = new RawContextKey<boolean>('callHierarchyVisible', false);
@@ -101,7 +101,6 @@ class CallHierarchyController extends Disposable implements IEditorContribution
widget.showMessage(localize('no.item', "No results"));
return;
}
widget.showItem(item);
});
}
@@ -131,7 +130,10 @@ registerEditorAction(class extends EditorAction {
weight: KeybindingWeight.WorkbenchContrib,
primary: KeyMod.Shift + KeyMod.Alt + KeyCode.KEY_H
},
precondition: _ctxHasCompletionItemProvider
precondition: ContextKeyExpr.and(
_ctxHasCompletionItemProvider,
PeekContext.notInPeekEditor
)
});
}
@@ -150,7 +152,10 @@ registerEditorCommand(new class extends EditorCommand {
weight: KeybindingWeight.WorkbenchContrib + 10,
primary: KeyCode.Escape
},
precondition: ContextKeyExpr.and(_ctxCallHierarchyVisible, ContextKeyExpr.not('config.editor.stablePeek'))
precondition: ContextKeyExpr.and(
_ctxCallHierarchyVisible,
ContextKeyExpr.not('config.editor.stablePeek')
)
});
}

View File

@@ -7,7 +7,7 @@ import 'vs/css!./media/callHierarchy';
import { PeekViewWidget } from 'vs/editor/contrib/referenceSearch/peekViewWidget';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { CallHierarchyItem, CallHierarchyProvider, CallHierarchyDirection } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { CallHierarchyProvider, CallHierarchyDirection, CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
import { FuzzyScore } from 'vs/base/common/filters';
import * as callHTree from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyTree';
@@ -262,6 +262,22 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
localDispose.push({ dispose: () => this._editor.deltaDecorations(ids, []) });
localDispose.push(value);
});
let node: callHTree.Call | CallHierarchyItem = element;
let names = [element.item.name];
while (true) {
let parent = this._tree.getParentElement(node);
if (!(parent instanceof callHTree.Call)) {
break;
}
if (this._direction === CallHierarchyDirection.CallsTo) {
names.push(parent.item.name);
} else {
names.unshift(parent.item.name);
}
node = parent;
}
this.setMetaTitle(localize('meta', " {0}", names.join(' → ')));
}
}, undefined, this._disposables);
@@ -295,14 +311,14 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
this._tree.onDidChangeSelection(e => {
const [element] = e.elements;
// don't close on click
if (element && !(e.browserEvent instanceof MouseEvent)) {
if (element && isNonEmptyArray(element.locations) && !(e.browserEvent instanceof MouseEvent)) {
this.dispose();
this._editorService.openEditor({
resource: element.item.uri,
options: { selection: element.locations[0].range }
});
}
});
}, undefined, this._disposables);
}
showLoading(): void {
@@ -319,30 +335,29 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
this._show();
}
showItem(item: CallHierarchyItem) {
this._parent.dataset['state'] = State.Data;
async showItem(item: CallHierarchyItem): Promise<void> {
this._show();
this._tree.setInput(item).then(() => {
await this._tree.setInput(item);
if (!this._tree.getFirstElementChild(item)) {
//
this.showMessage(this._direction === CallHierarchyDirection.CallsFrom
? localize('empt.callsFrom', "No calls from '{0}'", item.name)
: localize('empt.callsTo', "No calls to '{0}'", item.name));
const [root] = this._tree.getNode(item).children;
await this._tree.expand(root.element as callHTree.Call);
const firstChild = this._tree.getFirstElementChild(root.element);
if (!(firstChild instanceof callHTree.Call)) {
//
this.showMessage(this._direction === CallHierarchyDirection.CallsFrom
? localize('empt.callsFrom', "No calls from '{0}'", item.name)
: localize('empt.callsTo', "No calls to '{0}'", item.name));
} else {
this._tree.domFocus();
this._tree.focusFirst();
this.setTitle(
item.name,
item.detail || this._labelService.getUriLabel(item.uri, { relative: true }),
);
this.setMetaTitle(this._direction === CallHierarchyDirection.CallsFrom
? localize('title.from', " calls from '{0}'", item.name)
: localize('title.to', " calls to '{0}'", item.name));
}
});
} else {
this._parent.dataset['state'] = State.Data;
this._tree.domFocus();
this._tree.setFocus([firstChild]);
this.setTitle(
item.name,
item.detail || this._labelService.getUriLabel(item.uri, { relative: true }),
);
}
if (!this._toggleDirection) {
this._toggleDirection = new ToggleHierarchyDirectionAction(

View File

@@ -11,10 +11,10 @@ import { FuzzyScore, createMatches } from 'vs/base/common/filters';
import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { symbolKindToCssClass, Location } from 'vs/editor/common/modes';
import { ILabelService } from 'vs/platform/label/common/label';
import { Range } from 'vs/editor/common/core/range';
export class Call {
constructor(
readonly direction: CallHierarchyDirection,
readonly item: CallHierarchyItem,
readonly locations: Location[]
) { }
@@ -24,22 +24,29 @@ export class SingleDirectionDataSource implements IAsyncDataSource<CallHierarchy
constructor(
public provider: CallHierarchyProvider,
public direction: () => CallHierarchyDirection
public getDirection: () => CallHierarchyDirection
) { }
hasChildren(_element: CallHierarchyItem): boolean {
hasChildren(): boolean {
return true;
}
async getChildren(element: CallHierarchyItem | Call): Promise<Call[]> {
if (element instanceof Call) {
element = element.item;
try {
const direction = this.getDirection();
const calls = await this.provider.resolveCallHierarchyItem(element.item, direction, CancellationToken.None);
if (!calls) {
return [];
}
return calls.map(([item, locations]) => new Call(item, locations));
} catch {
return [];
}
} else {
// 'root'
return [new Call(element, [{ uri: element.uri, range: Range.lift(element.range).collapseToStart() }])];
}
const direction = this.direction();
const calls = await this.provider.resolveCallHierarchyItem(element, direction, CancellationToken.None);
return calls
? calls.map(([item, locations]) => new Call(direction, item, locations))
: [];
}
}
@@ -50,7 +57,7 @@ export class IdentityProvider implements IIdentityProvider<Call> {
}
class CallRenderingTemplate {
iconLabel: IconLabel;
readonly iconLabel: IconLabel;
}
export class CallRenderer implements ITreeRenderer<Call, FuzzyScore, CallRenderingTemplate> {
@@ -59,7 +66,9 @@ export class CallRenderer implements ITreeRenderer<Call, FuzzyScore, CallRenderi
templateId: string = CallRenderer.id;
constructor(@ILabelService private readonly _labelService: ILabelService) { }
constructor(
@ILabelService private readonly _labelService: ILabelService,
) { }
renderTemplate(container: HTMLElement): CallRenderingTemplate {
const iconLabel = new IconLabel(container, { supportHighlights: true });

View File

@@ -104,7 +104,8 @@ export class SuggestEnabledInput extends Widget implements IThemable {
readonly onInputDidChange: Event<string | undefined> = this._onInputDidChange.event;
private disposables: IDisposable[] = [];
private inputWidget: CodeEditorWidget;
private readonly inputWidget: CodeEditorWidget;
private readonly inputModel: ITextModel;
private stylingContainer: HTMLDivElement;
private placeholderText: HTMLDivElement;
@@ -136,7 +137,8 @@ export class SuggestEnabledInput extends Widget implements IThemable {
this.disposables.push(this.inputWidget);
let scopeHandle = uri.parse(resourceHandle);
this.inputWidget.setModel(modelService.createModel('', null, scopeHandle, true));
this.inputModel = modelService.createModel('', null, scopeHandle, true);
this.inputWidget.setModel(this.inputModel);
this.disposables.push(this.inputWidget.onDidPaste(() => this.setValue(this.getValue()))); // setter cleanses
@@ -203,7 +205,7 @@ export class SuggestEnabledInput extends Widget implements IThemable {
public setValue(val: string) {
val = val.replace(/\s/g, ' ');
const fullRange = new Range(1, 1, 1, this.getValue().length + 1);
const fullRange = this.inputModel.getFullModelRange();
this.inputWidget.executeEdits('suggestEnabledInput.setValue', [EditOperation.replace(fullRange, val)]);
this.inputWidget.setScrollTop(0);
this.inputWidget.setPosition(new Position(1, val.length + 1));

View File

@@ -97,7 +97,7 @@ export class CallStackView extends ViewletPanel {
dom.addClass(container, 'debug-call-stack');
const treeContainer = renderViewTree(container);
this.dataSource = new CallStackDataSource();
this.dataSource = new CallStackDataSource(this.debugService);
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, treeContainer, new CallStackDelegate(), [
new SessionsRenderer(),
new ThreadsRenderer(),
@@ -562,6 +562,8 @@ function isDeemphasized(frame: IStackFrame): boolean {
class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem> {
deemphasizedStackFramesToShow: IStackFrame[];
constructor(private debugService: IDebugService) { }
hasChildren(element: IDebugModel | CallStackItem): boolean {
return isDebugModel(element) || isDebugSession(element) || (element instanceof Thread && element.stopped);
}
@@ -573,13 +575,18 @@ class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem
return Promise.resolve([]);
}
if (sessions.length > 1) {
return Promise.resolve(sessions);
return Promise.resolve(sessions.filter(s => !s.parentSession));
}
const threads = sessions[0].getAllThreads();
// Only show the threads in the call stack if there is more than 1 thread.
return threads.length === 1 ? this.getThreadChildren(<Thread>threads[0]) : Promise.resolve(threads);
} else if (isDebugSession(element)) {
const childSessions = this.debugService.getModel().getSessions().filter(s => s.parentSession === element);
if (childSessions.length) {
return Promise.resolve(childSessions);
}
return Promise.resolve(element.getAllThreads());
} else {
return this.getThreadChildren(<Thread>element);

View File

@@ -217,7 +217,15 @@ export class FocusSessionActionItem extends SelectActionItem {
private update() {
const session = this.debugService.getViewModel().focusedSession;
const sessions = this.getSessions();
const names = sessions.map(s => s.getLabel());
const names = sessions.map(s => {
const label = s.getLabel();
if (s.parentSession) {
// Indent child sessions so they look like children
return `\u00A0\u00A0${label}`;
}
return label;
});
this.setOptions(names.map(data => <ISelectOptionItem>{ text: data }), session ? sessions.indexOf(session) : undefined);
}

View File

@@ -516,6 +516,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
this.exceptionWidget = this.instantiationService.createInstance(ExceptionWidget, this.editor, exceptionInfo);
this.exceptionWidget.show({ lineNumber, column }, 0);
this.editor.revealLine(lineNumber);
}
private closeExceptionWidget(): void {

View File

@@ -37,7 +37,6 @@ export class ExceptionWidget extends ZoneWidget {
this._applyTheme(themeService.getTheme());
this._disposables.push(themeService.onThemeChange(this._applyTheme.bind(this)));
this.create();
const onDidLayoutChangeScheduler = new RunOnceScheduler(() => this._doLayout(undefined, undefined), 50);
this._disposables.push(this.editor.onDidLayoutChange(() => onDidLayoutChangeScheduler.schedule()));

View File

@@ -39,11 +39,6 @@
border: 1px solid white;
}
.vs-dark .monaco-workbench .debug-action.start,
.hc-black .monaco-workbench .debug-action.start {
background: url('continue-inverse.svg') center center no-repeat;
}
.vs-dark .monaco-workbench .debug-action.configure,
.hc-black .monaco-workbench .debug-action.configure {
background: url('configure-inverse.svg') center center no-repeat;

View File

@@ -24,7 +24,6 @@
.monaco-editor .zone-widget .zone-widget-container.exception-widget .stack-trace {
margin-top: 0.5em;
max-height: 500px;
}
.monaco-editor .zone-widget .zone-widget-container.exception-widget a {

View File

@@ -149,6 +149,7 @@ export interface IDebugSession extends ITreeElement {
readonly unresolvedConfiguration: IConfig | undefined;
readonly state: State;
readonly root: IWorkspaceFolder;
readonly parentSession: IDebugSession | undefined;
getLabel(): string;

View File

@@ -12,7 +12,7 @@ import { generateUuid } from 'vs/base/common/uuid';
import { RunOnceScheduler } from 'vs/base/common/async';
import severity from 'vs/base/common/severity';
import { isObject, isString, isUndefinedOrNull } from 'vs/base/common/types';
import { distinct } from 'vs/base/common/arrays';
import { distinct, lastIndex } from 'vs/base/common/arrays';
import { Range, IRange } from 'vs/editor/common/core/range';
import {
ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel, IReplElementSource,
@@ -797,7 +797,17 @@ export class DebugModel implements IDebugModel {
return true;
});
this.sessions.push(session);
let index = -1;
if (session.parentSession) {
// Make sure that child sessions are placed after the parent session
index = lastIndex(this.sessions, s => s.parentSession === session.parentSession || s === session.parentSession);
}
if (index >= 0) {
this.sessions.splice(index + 1, 0, session);
} else {
this.sessions.push(session);
}
this._onDidChangeCallStack.fire(undefined);
}

View File

@@ -25,7 +25,7 @@ export class ReplModel {
addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void> {
const expression = new Expression(name);
this.addReplElements([expression]);
this.addReplElement(expression);
return expression.evaluate(this.session, stackFrame, 'repl');
}
@@ -39,26 +39,18 @@ export class ReplModel {
}
if (typeof data === 'string') {
const previousElement = this.replElements.length && (this.replElements[this.replElements.length - 1] as SimpleReplElement);
const toAdd = data.split('\n').map((line, index) => new SimpleReplElement(`topReplElement:${topReplElementCounter++}`, line, sev, index === 0 ? source : undefined));
if (previousElement && previousElement.value === '') {
// remove potential empty lines between different repl types
this.replElements.pop();
} else if (previousElement instanceof SimpleReplElement && sev === previousElement.severity && toAdd.length && toAdd[0].sourceData === previousElement.sourceData) {
previousElement.value += toAdd.shift()!.value;
}
this.addReplElements(toAdd);
const element = new SimpleReplElement(`topReplElement:${topReplElementCounter++}`, data.trimRight(), sev, source);
this.addReplElement(element);
} else {
// TODO@Isidor hack, we should introduce a new type which is an output that can fetch children like an expression
(<any>data).severity = sev;
(<any>data).sourceData = source;
this.addReplElements([data]);
this.addReplElement(data);
}
}
private addReplElements(newElements: IReplElement[]): void {
this.replElements.push(...newElements);
private addReplElement(newElement: IReplElement): void {
this.replElements.push(newElement);
if (this.replElements.length > MAX_REPL_LENGTH) {
this.replElements.splice(0, this.replElements.length - MAX_REPL_LENGTH);
}

View File

@@ -34,8 +34,8 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost';
import { IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService';
import { IRemoteConsoleLog, parse, getFirstFrame } from 'vs/base/node/console';
import { IBroadcastService } from 'vs/workbench/services/broadcast/common/broadcast';
import { IRemoteConsoleLog, parse, getFirstFrame } from 'vs/base/common/console';
import { TaskEvent, TaskEventKind, TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -315,7 +315,7 @@ export class DebugService implements IDebugService {
}
}
return this.createSession(launchForName, launchForName!.getConfiguration(name), noDebug);
return this.createSession(launchForName, launchForName!.getConfiguration(name), noDebug, parentSession);
})).then(values => values.every(success => !!success)); // Compound launch is a success only if each configuration launched successfully
}
@@ -325,7 +325,7 @@ export class DebugService implements IDebugService {
return Promise.reject(new Error(message));
}
return this.createSession(launch, config, noDebug);
return this.createSession(launch, config, noDebug, parentSession);
});
}));
}).then(success => {
@@ -341,7 +341,7 @@ export class DebugService implements IDebugService {
/**
* gets the debugger for the type, resolves configurations by providers, substitutes variables and runs prelaunch tasks
*/
private createSession(launch: ILaunch | undefined, config: IConfig | undefined, noDebug: boolean): Promise<boolean> {
private createSession(launch: ILaunch | undefined, config: IConfig | undefined, noDebug: boolean, parentSession?: IDebugSession): Promise<boolean> {
// We keep the debug type in a separate variable 'type' so that a no-folder config has no attributes.
// Storing the type in the config would break extensions that assume that the no-folder case is indicated by an empty config.
let type: string | undefined;
@@ -386,7 +386,7 @@ export class DebugService implements IDebugService {
const workspace = launch ? launch.workspace : undefined;
return this.runTaskAndCheckErrors(workspace, resolvedConfig.preLaunchTask).then(result => {
if (result === TaskRunResult.Success) {
return this.doCreateSession(workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig });
return this.doCreateSession(workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, parentSession);
}
return false;
});
@@ -415,9 +415,9 @@ export class DebugService implements IDebugService {
/**
* instantiates the new session, initializes the session, registers session listeners and reports telemetry
*/
private doCreateSession(root: IWorkspaceFolder | undefined, configuration: { resolved: IConfig, unresolved: IConfig | undefined }): Promise<boolean> {
private doCreateSession(root: IWorkspaceFolder | undefined, configuration: { resolved: IConfig, unresolved: IConfig | undefined }, parentSession?: IDebugSession): Promise<boolean> {
const session = this.instantiationService.createInstance(DebugSession, configuration, root, this.model);
const session = this.instantiationService.createInstance(DebugSession, configuration, root, this.model, parentSession);
this.model.addSession(session);
// register listeners as the very first thing!
this.registerSessionListeners(session);

View File

@@ -57,6 +57,7 @@ export class DebugSession implements IDebugSession {
private _configuration: { resolved: IConfig, unresolved: IConfig | undefined },
public root: IWorkspaceFolder,
private model: DebugModel,
private _parentSession: IDebugSession | undefined,
@IDebugService private readonly debugService: IDebugService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IOutputService private readonly outputService: IOutputService,
@@ -83,6 +84,10 @@ export class DebugSession implements IDebugSession {
return this._configuration.unresolved;
}
get parentSession(): IDebugSession | undefined {
return this._parentSession;
}
setConfiguration(configuration: { resolved: IConfig, unresolved: IConfig | undefined }) {
this._configuration = configuration;
}
@@ -178,6 +183,10 @@ export class DebugSession implements IDebugSession {
});
});
});
}).then(undefined, err => {
this.initialized = true;
this._onDidChangeState.fire();
return Promise.reject(err);
});
}

View File

@@ -123,6 +123,11 @@ export class MockDebugService implements IDebugService {
}
export class MockSession implements IDebugSession {
get parentSession(): IDebugSession | undefined {
return undefined;
}
getReplElements(): IReplElement[] {
return [];
}

View File

@@ -13,6 +13,10 @@ import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
import { DebugSession } from 'vs/workbench/contrib/debug/electron-browser/debugSession';
import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
function createMockSession(model: DebugModel, name = 'mockSession', parentSession?: DebugSession | undefined): DebugSession {
return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, parentSession, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
}
suite('Debug - Model', () => {
let model: DebugModel;
let rawSession: MockRawSession;
@@ -109,7 +113,7 @@ suite('Debug - Model', () => {
test('threads simple', () => {
const threadId = 1;
const threadName = 'firstThread';
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
const session = createMockSession(model);
model.addSession(session);
assert.equal(model.getSessions(true).length, 1);
@@ -136,7 +140,7 @@ suite('Debug - Model', () => {
const stoppedReason = 'breakpoint';
// Add the threads
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
const session = createMockSession(model);
model.addSession(session);
session['raw'] = <any>rawSession;
@@ -224,7 +228,7 @@ suite('Debug - Model', () => {
const runningThreadId = 2;
const runningThreadName = 'runningThread';
const stoppedReason = 'breakpoint';
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
const session = createMockSession(model);
model.addSession(session);
session['raw'] = <any>rawSession;
@@ -338,7 +342,7 @@ suite('Debug - Model', () => {
});
test('repl expressions', () => {
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
const session = createMockSession(model);
assert.equal(session.getReplElements().length, 0);
model.addSession(session);
@@ -362,7 +366,7 @@ suite('Debug - Model', () => {
});
test('stack frame get specific source name', () => {
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
const session = createMockSession(model);
model.addSession(session);
let firstStackFrame: StackFrame;
@@ -390,10 +394,33 @@ suite('Debug - Model', () => {
assert.equal(secondStackFrame.getSpecificSourceName(), '.../x/c/d/internalModule.js');
});
test('debug child sessions are added in correct order', () => {
const session = createMockSession(model);
model.addSession(session);
const secondSession = createMockSession(model, 'mockSession2');
model.addSession(secondSession);
const firstChild = createMockSession(model, 'firstChild', session);
model.addSession(firstChild);
const secondChild = createMockSession(model, 'secondChild', session);
model.addSession(secondChild);
const thirdSession = createMockSession(model, 'mockSession3');
model.addSession(thirdSession);
const anotherChild = createMockSession(model, 'secondChild', secondSession);
model.addSession(anotherChild);
const sessions = model.getSessions();
assert.equal(sessions[0].getId(), session.getId());
assert.equal(sessions[1].getId(), firstChild.getId());
assert.equal(sessions[2].getId(), secondChild.getId());
assert.equal(sessions[3].getId(), secondSession.getId());
assert.equal(sessions[4].getId(), anotherChild.getId());
assert.equal(sessions[5].getId(), thirdSession.getId());
});
// Repl output
test('repl output', () => {
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
const repl = new ReplModel(session);
repl.appendToRepl('first line\n', severity.Error);
repl.appendToRepl('second line', severity.Error);

View File

@@ -24,7 +24,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { assign } from 'vs/base/common/objects';
import { URI } from 'vs/base/common/uri';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { lastSessionDateStorageKey } from 'vs/platform/telemetry/node/workbenchCommonProperties';
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
@@ -86,11 +86,11 @@ suite('Experiment Service', () => {
testConfigurationService = new TestConfigurationService();
instantiationService.stub(IConfigurationService, testConfigurationService);
instantiationService.stub(ILifecycleService, new TestLifecycleService());
instantiationService.stub(IStorageService, { get: (a, b, c) => c, getBoolean: (a, b, c) => c, store: () => { }, remove: () => { } });
instantiationService.stub(IStorageService, <Partial<IStorageService>>{ get: (a: string, b: StorageScope, c?: string) => c, getBoolean: (a: string, b: StorageScope, c?: boolean) => c, store: () => { }, remove: () => { } });
setup(() => {
instantiationService.stub(IEnvironmentService, {});
instantiationService.stub(IStorageService, { get: (a, b, c) => c, getBoolean: (a, b, c) => c, store: () => { }, remove: () => { } });
instantiationService.stub(IStorageService, <Partial<IStorageService>>{ get: (a: string, b: StorageScope, c?: string) => c, getBoolean: (a: string, b: StorageScope, c?: boolean) => c, store: () => { }, remove: () => { } });
});
teardown(() => {
@@ -196,11 +196,11 @@ suite('Experiment Service', () => {
]
};
instantiationService.stub(IStorageService, {
get: (a, b, c) => {
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
get: (a: string, b: StorageScope, c?: string) => {
return a === lastSessionDateStorageKey ? 'some-date' : undefined;
},
getBoolean: (a, b, c) => c, store: () => { }, remove: () => { }
getBoolean: (a: string, b: StorageScope, c?: boolean) => c, store: () => { }, remove: () => { }
});
testObject = instantiationService.createInstance(TestExperimentService);
return testObject.getExperimentById('experiment1').then(result => {
@@ -240,11 +240,11 @@ suite('Experiment Service', () => {
]
};
instantiationService.stub(IStorageService, {
get: (a, b, c) => {
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
get: (a: string, b: StorageScope, c: string | undefined) => {
return a === lastSessionDateStorageKey ? 'some-date' : undefined;
},
getBoolean: (a, b, c) => c, store: () => { }, remove: () => { }
getBoolean: (a: string, b: StorageScope, c?: boolean) => c, store: () => { }, remove: () => { }
});
testObject = instantiationService.createInstance(TestExperimentService);
return testObject.getExperimentById('experiment1').then(result => {
@@ -372,9 +372,9 @@ suite('Experiment Service', () => {
]
};
instantiationService.stub(IStorageService, {
get: (a, b, c) => a === 'experiments.experiment1' ? JSON.stringify({ state: ExperimentState.Complete }) : c,
store: (a, b, c) => { }
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
get: (a: string, b: StorageScope, c?: string) => a === 'experiments.experiment1' ? JSON.stringify({ state: ExperimentState.Complete }) : c,
store: () => { }
});
testObject = instantiationService.createInstance(TestExperimentService);
@@ -400,9 +400,9 @@ suite('Experiment Service', () => {
]
};
instantiationService.stub(IStorageService, {
get: (a, b, c) => a === 'experiments.experiment1' ? JSON.stringify({ enabled: true, state: ExperimentState.Run }) : c,
store: (a, b, c) => { }
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
get: (a: string, b: StorageScope, c?: string) => a === 'experiments.experiment1' ? JSON.stringify({ enabled: true, state: ExperimentState.Run }) : c,
store: () => { }
});
testObject = instantiationService.createInstance(TestExperimentService);
return testObject.getExperimentById('experiment1').then(result => {
@@ -508,8 +508,8 @@ suite('Experiment Service', () => {
let storageDataExperiment1: ExperimentSettings | null = { enabled: false };
let storageDataExperiment2: ExperimentSettings | null = { enabled: false };
let storageDataAllExperiments: string[] | null = ['experiment1', 'experiment2', 'experiment3'];
instantiationService.stub(IStorageService, {
get: (a, b, c) => {
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
get: (a: string, b: StorageScope, c?: string) => {
switch (a) {
case 'experiments.experiment1':
return JSON.stringify(storageDataExperiment1);
@@ -522,7 +522,7 @@ suite('Experiment Service', () => {
}
return c;
},
store: (a, b, c) => {
store: (a: string, b: any, c: StorageScope) => {
switch (a) {
case 'experiments.experiment1':
storageDataExperiment1 = JSON.parse(b);
@@ -537,7 +537,7 @@ suite('Experiment Service', () => {
break;
}
},
remove: a => {
remove: (a: string) => {
switch (a) {
case 'experiments.experiment1':
storageDataExperiment1 = null;
@@ -580,8 +580,8 @@ suite('Experiment Service', () => {
let storageDataExperiment3: ExperimentSettings | null = { enabled: true, state: ExperimentState.Evaluating };
let storageDataExperiment4: ExperimentSettings | null = { enabled: true, state: ExperimentState.Complete };
let storageDataAllExperiments: string[] | null = ['experiment1', 'experiment2', 'experiment3', 'experiment4'];
instantiationService.stub(IStorageService, {
get: (a, b, c) => {
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
get: (a: string, b: StorageScope, c?: string) => {
switch (a) {
case 'experiments.experiment1':
return JSON.stringify(storageDataExperiment1);
@@ -601,19 +601,19 @@ suite('Experiment Service', () => {
store: (a, b, c) => {
switch (a) {
case 'experiments.experiment1':
storageDataExperiment1 = JSON.parse(b);
storageDataExperiment1 = JSON.parse(b + '');
break;
case 'experiments.experiment2':
storageDataExperiment2 = JSON.parse(b);
storageDataExperiment2 = JSON.parse(b + '');
break;
case 'experiments.experiment3':
storageDataExperiment3 = JSON.parse(b);
storageDataExperiment3 = JSON.parse(b + '');
break;
case 'experiments.experiment4':
storageDataExperiment4 = JSON.parse(b);
storageDataExperiment4 = JSON.parse(b + '');
break;
case 'allExperiments':
storageDataAllExperiments = JSON.parse(b);
storageDataAllExperiments = JSON.parse(b + '');
break;
default:
break;
@@ -768,8 +768,8 @@ suite('Experiment Service', () => {
let storageDataExperiment3 = { enabled: true, state: ExperimentState.Evaluating };
let storageDataExperiment4 = { enabled: true, state: ExperimentState.Evaluating };
instantiationService.stub(IStorageService, {
get: (a, b, c) => {
instantiationService.stub(IStorageService, <Partial<IStorageService>>{
get: (a: string, b: StorageScope, c?: string) => {
switch (a) {
case 'currentOrPreviouslyRunExperiments':
return JSON.stringify(['experiment1', 'experiment2']);
@@ -781,10 +781,10 @@ suite('Experiment Service', () => {
store: (a, b, c) => {
switch (a) {
case 'experiments.experiment3':
storageDataExperiment3 = JSON.parse(b);
storageDataExperiment3 = JSON.parse(b + '');
break;
case 'experiments.experiment4':
storageDataExperiment4 = JSON.parse(b);
storageDataExperiment4 = JSON.parse(b + '');
break;
default:
break;

View File

@@ -95,6 +95,7 @@ suite('Experimental Prompts', () => {
assert.equal(b, promptText);
assert.equal(c.length, 2);
c[0].run();
return undefined!;
}
});
@@ -119,6 +120,7 @@ suite('Experimental Prompts', () => {
assert.equal(b, promptText);
assert.equal(c.length, 2);
c[1].run();
return undefined!;
}
});
@@ -143,6 +145,7 @@ suite('Experimental Prompts', () => {
assert.equal(b, promptText);
assert.equal(c.length, 2);
options.onCancel();
return undefined!;
}
});

View File

@@ -84,7 +84,7 @@ export class GalleryExtensionsHandler extends QuickOpenHandler {
getResults(text: string, token: CancellationToken): Promise<IModel<any>> {
if (/\./.test(text)) {
return this.galleryService.query({ names: [text], pageSize: 1 })
return this.galleryService.query({ names: [text], pageSize: 1 }, token)
.then(galleryResult => {
const entries: SimpleEntry[] = [];
const galleryExtension = galleryResult.firstPage[0];

View File

@@ -85,7 +85,8 @@ export interface IExtensionsWorkbenchService {
onChange: Event<IExtension | undefined>;
local: IExtension[];
queryLocal(): Promise<IExtension[]>;
queryGallery(options?: IQueryOptions): Promise<IPager<IExtension>>;
queryGallery(token: CancellationToken): Promise<IPager<IExtension>>;
queryGallery(options: IQueryOptions, token: CancellationToken): Promise<IPager<IExtension>>;
canInstall(extension: IExtension): boolean;
install(vsix: string): Promise<IExtension>;
install(extension: IExtension, promptToInstallDependencies?: boolean): Promise<IExtension>;

View File

@@ -739,7 +739,7 @@ export class ExtensionEditor extends BaseEditor {
getChildren(): Promise<IExtensionData[] | null> {
if (this.hasChildren) {
const names = arrays.distinct(this.extension.extensionPack, e => e.toLowerCase());
return extensionsWorkbenchService.queryGallery({ names, pageSize: names.length })
return extensionsWorkbenchService.queryGallery({ names, pageSize: names.length }, CancellationToken.None)
.then(result => result.firstPage.map(extension => new ExtensionData(extension, this)));
}
return Promise.resolve(null);

View File

@@ -387,7 +387,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
if (filteredWanted.length) {
try {
let validRecommendations = (await this._galleryService.query({ names: filteredWanted, pageSize: filteredWanted.length })).firstPage
let validRecommendations = (await this._galleryService.query({ names: filteredWanted, pageSize: filteredWanted.length }, CancellationToken.None)).firstPage
.map(extension => extension.identifier.id.toLowerCase());
if (validRecommendations.length !== filteredWanted.length) {
@@ -776,7 +776,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
const lookup = product.extensionKeywords || {};
const keywords = lookup[fileExtension] || [];
this._galleryService.query({ text: `tag:"__ext_${fileExtension}" ${keywords.map(tag => `tag:"${tag}"`)}` }).then(pager => {
this._galleryService.query({ text: `tag:"__ext_${fileExtension}" ${keywords.map(tag => `tag:"${tag}"`)}` }, CancellationToken.None).then(pager => {
if (!pager || !pager.firstPage || !pager.firstPage.length) {
return;
}

View File

@@ -49,6 +49,7 @@ import { ExtensionActivationProgress } from 'vs/workbench/contrib/extensions/ele
import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler';
import { onUnexpectedError } from 'vs/base/common/errors';
import { ExtensionDependencyChecker } from 'vs/workbench/contrib/extensions/electron-browser/extensionsDependencyChecker';
import { CancellationToken } from 'vs/base/common/cancellation';
// Singletons
registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService);
@@ -268,7 +269,7 @@ CommandsRegistry.registerCommand('_extensions.manage', (accessor: ServicesAccess
CommandsRegistry.registerCommand('extension.open', (accessor: ServicesAccessor, extensionId: string) => {
const extensionService = accessor.get(IExtensionsWorkbenchService);
return extensionService.queryGallery({ names: [extensionId], pageSize: 1 }).then(pager => {
return extensionService.queryGallery({ names: [extensionId], pageSize: 1 }, CancellationToken.None).then(pager => {
if (pager.total !== 1) {
return;
}

View File

@@ -1538,7 +1538,7 @@ export class InstallWorkspaceRecommendedExtensionsAction extends Action {
viewlet.search('@recommended ');
viewlet.focus();
const names = this.recommendations.map(({ extensionId }) => extensionId);
return this.extensionWorkbenchService.queryGallery({ names, source: 'install-all-workspace-recommendations' }).then(pager => {
return this.extensionWorkbenchService.queryGallery({ names, source: 'install-all-workspace-recommendations' }, CancellationToken.None).then(pager => {
let installPromises: Promise<any>[] = [];
let model = new PagedModel(pager);
for (let i = 0; i < pager.total; i++) {
@@ -1580,7 +1580,7 @@ export class InstallRecommendedExtensionAction extends Action {
.then(viewlet => {
viewlet.search('@recommended ');
viewlet.focus();
return this.extensionWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation', pageSize: 1 })
return this.extensionWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation', pageSize: 1 }, CancellationToken.None)
.then(pager => {
if (pager && pager.firstPage && pager.firstPage.length) {
const extension = pager.firstPage[0];

View File

@@ -15,6 +15,7 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/
import { Action } from 'vs/base/common/actions';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { Disposable } from 'vs/base/common/lifecycle';
import { CancellationToken } from 'vs/base/common/cancellation';
export class ExtensionDependencyChecker extends Disposable implements IWorkbenchContribution {
@@ -60,7 +61,7 @@ export class ExtensionDependencyChecker extends Disposable implements IWorkbench
private async installMissingDependencies(): Promise<void> {
const missingDependencies = await this.getUninstalledMissingDependencies();
if (missingDependencies.length) {
const extensions = (await this.extensionsWorkbenchService.queryGallery({ names: missingDependencies, pageSize: missingDependencies.length })).firstPage;
const extensions = (await this.extensionsWorkbenchService.queryGallery({ names: missingDependencies, pageSize: missingDependencies.length }, CancellationToken.None)).firstPage;
if (extensions.length) {
await Promise.all(extensions.map(extension => this.extensionsWorkbenchService.install(extension)));
this.notificationService.notify({

View File

@@ -5,7 +5,7 @@
import 'vs/css!./media/extensionsViewlet';
import { localize } from 'vs/nls';
import { ThrottledDelayer, timeout } from 'vs/base/common/async';
import { timeout, Delayer } from 'vs/base/common/async';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
@@ -271,7 +271,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
private recommendedExtensionsContextKey: IContextKey<boolean>;
private defaultRecommendedExtensionsContextKey: IContextKey<boolean>;
private searchDelayer: ThrottledDelayer<any>;
private searchDelayer: Delayer<void>;
private root: HTMLElement;
private searchBox: SuggestEnabledInput;
@@ -300,7 +300,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
) {
super(VIEWLET_ID, `${VIEWLET_ID}.state`, true, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
this.searchDelayer = new ThrottledDelayer(500);
this.searchDelayer = new Delayer(500);
this.nonEmptyWorkspaceContextKey = NonEmptyWorkspaceContext.bindTo(contextKeyService);
this.searchExtensionsContextKey = SearchExtensionsContext.bindTo(contextKeyService);
this.hasInstalledExtensionsContextKey = HasInstalledExtensionsContext.bindTo(contextKeyService);

View File

@@ -44,6 +44,7 @@ import { IAction } from 'vs/base/common/actions';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import product from 'vs/platform/product/node/product';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
class ExtensionsViewState extends Disposable implements IExtensionsViewState {
@@ -69,6 +70,7 @@ export class ExtensionsListView extends ViewletPanel {
private badge: CountBadge;
protected badgeContainer: HTMLElement;
private list: WorkbenchPagedList<IExtension> | null;
private queryRequest: { query: string, request: CancelablePromise<IPagedModel<IExtension>> } | null;
constructor(
private options: IViewletViewOptions,
@@ -139,6 +141,14 @@ export class ExtensionsListView extends ViewletPanel {
}
async show(query: string): Promise<IPagedModel<IExtension>> {
if (this.queryRequest) {
if (this.queryRequest.query === query) {
return this.queryRequest.request;
}
this.queryRequest.request.cancel();
this.queryRequest = null;
}
const parsedQuery = Query.parse(query);
let options: IQueryOptions = {
@@ -152,21 +162,24 @@ export class ExtensionsListView extends ViewletPanel {
}
const successCallback = model => {
this.queryRequest = null;
this.setModel(model);
return model;
};
const errorCallback = e => {
console.warn('Error querying extensions gallery', e);
const model = new PagedModel([]);
this.setModel(model, true);
return model;
if (!isPromiseCanceledError(e)) {
this.queryRequest = null;
console.warn('Error querying extensions gallery', e);
this.setModel(model, true);
}
return this.list ? this.list.model : model;
};
if (ExtensionsListView.isInstalledExtensionsQuery(query) || /@builtin/.test(query)) {
return await this.queryLocal(parsedQuery, options).then(successCallback).catch(errorCallback);
}
return await this.queryGallery(parsedQuery, options).then(successCallback).catch(errorCallback);
const isLocalQuery = ExtensionsListView.isInstalledExtensionsQuery(query) || /@builtin/.test(query);
const request = createCancelablePromise(token => (isLocalQuery ? this.queryLocal(parsedQuery, options) : this.queryGallery(parsedQuery, options, token)).then(successCallback).catch(errorCallback));
this.queryRequest = { query, request };
return request.then(successCallback).catch(errorCallback);
}
count(): number {
@@ -326,7 +339,7 @@ export class ExtensionsListView extends ViewletPanel {
return new PagedModel([]);
}
private async queryGallery(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
private async queryGallery(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
const hasUserDefinedSortOrder = options.sortBy !== undefined;
if (!hasUserDefinedSortOrder && !query.value.trim()) {
options.sortBy = SortBy.InstallCount;
@@ -343,25 +356,25 @@ export class ExtensionsListView extends ViewletPanel {
}
if (names.length) {
return this.extensionsWorkbenchService.queryGallery({ names, source: 'queryById' })
return this.extensionsWorkbenchService.queryGallery({ names, source: 'queryById' }, token)
.then(pager => this.getPagedModel(pager));
}
if (ExtensionsListView.isWorkspaceRecommendedExtensionsQuery(query.value)) {
return this.getWorkspaceRecommendationsModel(query, options);
return this.getWorkspaceRecommendationsModel(query, options, token);
} else if (ExtensionsListView.isKeymapsRecommendedExtensionsQuery(query.value)) {
return this.getKeymapRecommendationsModel(query, options);
return this.getKeymapRecommendationsModel(query, options, token);
} else if (/@recommended:all/i.test(query.value) || ExtensionsListView.isSearchRecommendedExtensionsQuery(query.value)) {
return this.getAllRecommendationsModel(query, options);
return this.getAllRecommendationsModel(query, options, token);
} else if (ExtensionsListView.isRecommendedExtensionsQuery(query.value)) {
return this.getRecommendationsModel(query, options);
return this.getRecommendationsModel(query, options, token);
// {{SQL CARBON EDIT}}
} else if (ExtensionsListView.isAllMarketplaceExtensionsQuery(query.value)) {
return this.getAllMarketplaceModel(query, options);
return this.getAllMarketplaceModel(query, options, token);
}
if (/\bcurated:([^\s]+)\b/.test(query.value)) {
return this.getCuratedModel(query, options);
return this.getCuratedModel(query, options, token);
}
let text = query.value;
@@ -385,7 +398,7 @@ export class ExtensionsListView extends ViewletPanel {
if (text !== query.value) {
options = assign(options, { text: text.substr(0, 350), source: 'file-extension-tags' });
return this.extensionsWorkbenchService.queryGallery(options).then(pager => this.getPagedModel(pager));
return this.extensionsWorkbenchService.queryGallery(options, token).then(pager => this.getPagedModel(pager));
}
}
@@ -406,7 +419,7 @@ export class ExtensionsListView extends ViewletPanel {
options.source = 'viewlet';
}
const pager = await this.extensionsWorkbenchService.queryGallery(options);
const pager = await this.extensionsWorkbenchService.queryGallery(options, token);
let positionToUpdate = 0;
for (const preferredResult of preferredResults) {
@@ -453,7 +466,7 @@ export class ExtensionsListView extends ViewletPanel {
}
// Get All types of recommendations, trimmed to show a max of 8 at any given time
private getAllRecommendationsModel(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
private getAllRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
const value = query.value.replace(/@recommended:all/g, '').replace(/@recommended/g, '').trim().toLowerCase();
return this.extensionsWorkbenchService.queryLocal()
@@ -486,7 +499,7 @@ export class ExtensionsListView extends ViewletPanel {
return Promise.resolve(new PagedModel([]));
}
options.source = 'recommendations-all';
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }))
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }), token)
.then(pager => {
this.sortFirstPage(pager, names);
return this.getPagedModel(pager || []);
@@ -495,12 +508,12 @@ export class ExtensionsListView extends ViewletPanel {
});
}
private async getCuratedModel(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
private async getCuratedModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
const value = query.value.replace(/curated:/g, '').trim();
const names = await this.experimentService.getCuratedExtensionsList(value);
if (Array.isArray(names) && names.length) {
options.source = `curated:${value}`;
const pager = await this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }));
const pager = await this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }), token);
this.sortFirstPage(pager, names);
return this.getPagedModel(pager || []);
}
@@ -508,7 +521,7 @@ export class ExtensionsListView extends ViewletPanel {
}
// Get All types of recommendations other than Workspace recommendations, trimmed to show a max of 8 at any given time
private getRecommendationsModel(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
private getRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
const value = query.value.replace(/@recommended/g, '').trim().toLowerCase();
return this.extensionsWorkbenchService.queryLocal()
@@ -546,7 +559,7 @@ export class ExtensionsListView extends ViewletPanel {
return Promise.resolve(new PagedModel([]));
}
options.source = 'recommendations';
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }))
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }), token)
.then(pager => {
this.sortFirstPage(pager, names);
return this.getPagedModel(pager || []);
@@ -556,7 +569,7 @@ export class ExtensionsListView extends ViewletPanel {
}
// {{SQL CARBON EDIT}}
private getAllMarketplaceModel(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
private getAllMarketplaceModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
const value = query.value.trim().toLowerCase();
return this.extensionsWorkbenchService.queryLocal()
.then(result => result.filter(e => e.type === ExtensionType.User))
@@ -564,7 +577,7 @@ export class ExtensionsListView extends ViewletPanel {
return this.tipsService.getOtherRecommendations().then((recommmended) => {
const installedExtensions = local.map(x => `${x.publisher}.${x.name}`);
options = assign(options, { text: value, source: 'searchText' });
return this.extensionsWorkbenchService.queryGallery(options).then((pager) => {
return this.extensionsWorkbenchService.queryGallery(options, token).then((pager) => {
// filter out installed extensions
pager.firstPage = pager.firstPage.filter((p) => {
return installedExtensions.indexOf(`${p.publisher}.${p.name}`) === -1;
@@ -624,7 +637,7 @@ export class ExtensionsListView extends ViewletPanel {
return installed.some(i => areSameExtensions(i.identifier, { id: recommendation.extensionId }));
}
private getWorkspaceRecommendationsModel(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
private getWorkspaceRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
const value = query.value.replace(/@recommended:workspace/g, '').trim().toLowerCase();
return this.tipsService.getWorkspaceRecommendations()
.then(recommendations => {
@@ -640,12 +653,12 @@ export class ExtensionsListView extends ViewletPanel {
return Promise.resolve(new PagedModel([]));
}
options.source = 'recommendations-workspace';
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }))
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }), token)
.then(pager => this.getPagedModel(pager || []));
});
}
private getKeymapRecommendationsModel(query: Query, options: IQueryOptions): Promise<IPagedModel<IExtension>> {
private getKeymapRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
const value = query.value.replace(/@recommended:keymaps/g, '').trim().toLowerCase();
const names: string[] = this.tipsService.getKeymapRecommendations().map(({ extensionId }) => extensionId)
.filter(extensionId => extensionId.toLowerCase().indexOf(value) > -1);
@@ -654,7 +667,7 @@ export class ExtensionsListView extends ViewletPanel {
return Promise.resolve(new PagedModel([]));
}
options.source = 'recommendations-keymaps';
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }))
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }), token)
.then(result => this.getPagedModel(result));
}
@@ -735,6 +748,10 @@ export class ExtensionsListView extends ViewletPanel {
dispose(): void {
super.dispose();
if (this.queryRequest) {
this.queryRequest.request.cancel();
this.queryRequest = null;
}
this.disposables = dispose(this.disposables);
this.list = null;
}

View File

@@ -463,12 +463,16 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
});
}
queryGallery(options: IQueryOptions = {}): Promise<IPager<IExtension>> {
queryGallery(token: CancellationToken): Promise<IPager<IExtension>>;
queryGallery(options: IQueryOptions, token: CancellationToken): Promise<IPager<IExtension>>;
queryGallery(arg1: any, arg2?: any): Promise<IPager<IExtension>> {
const options: IQueryOptions = CancellationToken.isCancellationToken(arg1) ? {} : arg1;
const token: CancellationToken = CancellationToken.isCancellationToken(arg1) ? arg1 : arg2;
return this.extensionService.getExtensionsReport()
.then(report => {
const maliciousSet = getMaliciousExtensionsSet(report);
return this.galleryService.query(options)
return this.galleryService.query(options, token)
.then(result => mapPager(result, gallery => this.fromGallery(gallery, maliciousSet)))
.then(undefined, err => {
if (/No extension gallery service configured/.test(err.message)) {
@@ -610,10 +614,10 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
const promises: Promise<IPager<IExtension>>[] = [];
if (ids.length) {
promises.push(this.queryGallery({ ids, pageSize: ids.length }));
promises.push(this.queryGallery({ ids, pageSize: ids.length }, CancellationToken.None));
}
if (names.length) {
promises.push(this.queryGallery({ names, pageSize: names.length }));
promises.push(this.queryGallery({ names, pageSize: names.length }, CancellationToken.None));
}
return Promise.all(promises).then(() => undefined);
@@ -1056,7 +1060,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
.then(() => this.open(extension));
}
return this.queryGallery({ names: [extensionId], source: 'uri' }).then(result => {
return this.queryGallery({ names: [extensionId], source: 'uri' }, CancellationToken.None).then(result => {
if (result.total < 1) {
return Promise.resolve(null);
}

Some files were not shown because too many files have changed in this diff Show More