提交 b16ec92a 编写于 作者: B Benjamin Pasero

Merge branch 'master' into ben/editor

......@@ -17,7 +17,7 @@
"request": "attach",
"name": "Attach to Extension Host",
"protocol": "inspector",
"port": 5871,
"port": 5870,
// "restart": true,
"outFiles": [
"${workspaceFolder}/out/**/*.js"
......
......@@ -69,7 +69,7 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache<HTMLDocume
},
doValidation(document: TextDocument): Diagnostic[] {
updateCurrentTextDocument(document);
const syntaxDiagnostics = jsLanguageService.getSyntacticDiagnostics(FILE_NAME);
const syntaxDiagnostics: ts.Diagnostic[] = jsLanguageService.getSyntacticDiagnostics(FILE_NAME);
const semanticDiagnostics = jsLanguageService.getSemanticDiagnostics(FILE_NAME);
return syntaxDiagnostics.concat(semanticDiagnostics).map((diag: ts.Diagnostic): Diagnostic => {
return {
......
......@@ -3,11 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as path from 'path';
import { Slug } from './tableOfContentsProvider';
import { MarkdownIt, Token } from 'markdown-it';
import * as path from 'path';
import * as vscode from 'vscode';
import { MarkdownContributions } from './markdownExtensions';
import { stripSlugifier } from './slugify';
const FrontMatterRegex = /^---\s*[^]*?(-{3}|\.{3})\s*/;
......@@ -49,7 +49,7 @@ export class MarkdownEngine {
return `<pre class="hljs"><code><div>${this.md!.utils.escapeHtml(str)}</div></code></pre>`;
}
}).use(mdnh, {
slugify: (header: string) => Slug.fromHeading(header).value
slugify: (header: string) => stripSlugifier.fromHeading(header).value
});
for (const plugin of this.extensionPreviewResourceProvider.markdownItPlugins) {
......@@ -145,13 +145,13 @@ export class MarkdownEngine {
if (fragment) {
uri = uri.with({
fragment: Slug.fromHeading(fragment).value
fragment: stripSlugifier.fromHeading(fragment).value
});
}
return normalizeLink(uri.with({ scheme: 'vscode-resource' }).toString(true));
} else if (!uri.scheme && !uri.path && uri.fragment) {
return normalizeLink(uri.with({
fragment: Slug.fromHeading(uri.fragment).value
fragment: stripSlugifier.fromHeading(uri.fragment).value
}).toString(true));
}
} catch (e) {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export class Slug {
public constructor(
public readonly value: string
) { }
public equals(other: Slug): boolean {
return this.value === other.value;
}
}
export interface Slugifier {
fromHeading(heading: string): Slug;
}
export const stripSlugifier: Slugifier = new class implements Slugifier {
private readonly specialChars: any = { 'à': 'a', 'ä': 'a', 'ã': 'a', 'á': 'a', 'â': 'a', 'æ': 'a', 'å': 'a', 'ë': 'e', 'è': 'e', 'é': 'e', 'ê': 'e', 'î': 'i', 'ï': 'i', 'ì': 'i', 'í': 'i', 'ò': 'o', 'ó': 'o', 'ö': 'o', 'ô': 'o', 'ø': 'o', 'ù': 'o', 'ú': 'u', 'ü': 'u', 'û': 'u', 'ñ': 'n', 'ç': 'c', 'ß': 's', 'ÿ': 'y', 'œ': 'o', 'ŕ': 'r', 'ś': 's', 'ń': 'n', '': 'p', '': 'w', 'ǵ': 'g', 'ǹ': 'n', 'ḿ': 'm', 'ǘ': 'u', '': 'x', 'ź': 'z', '': 'h', '·': '-', '/': '-', '_': '-', ',': '-', ':': '-', ';': '-', 'З': '3', 'з': '3' };
public fromHeading(heading: string): Slug {
const slugifiedHeading = encodeURI(heading.trim()
.toLowerCase()
.replace(/./g, c => this.specialChars[c] || c)
.replace(/[\]\[\!\'\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\_\{\|\}\~\`]/g, '')
.replace(/\s+/g, '-') // Replace whitespace with -
.replace(/[^\w\-]+/g, '') // Remove remaining non-word chars
.replace(/^\-+/, '') // Remove leading -
.replace(/\-+$/, '') // Remove trailing -
);
return new Slug(slugifiedHeading);
}
};
\ No newline at end of file
......@@ -4,34 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { MarkdownEngine } from './markdownEngine';
export class Slug {
private static specialChars: any = { 'à': 'a', 'ä': 'a', 'ã': 'a', 'á': 'a', 'â': 'a', 'æ': 'a', 'å': 'a', 'ë': 'e', 'è': 'e', 'é': 'e', 'ê': 'e', 'î': 'i', 'ï': 'i', 'ì': 'i', 'í': 'i', 'ò': 'o', 'ó': 'o', 'ö': 'o', 'ô': 'o', 'ø': 'o', 'ù': 'o', 'ú': 'u', 'ü': 'u', 'û': 'u', 'ñ': 'n', 'ç': 'c', 'ß': 's', 'ÿ': 'y', 'œ': 'o', 'ŕ': 'r', 'ś': 's', 'ń': 'n', '': 'p', '': 'w', 'ǵ': 'g', 'ǹ': 'n', 'ḿ': 'm', 'ǘ': 'u', '': 'x', 'ź': 'z', '': 'h', '·': '-', '/': '-', '_': '-', ',': '-', ':': '-', ';': '-', 'З': '3', 'з': '3' };
public static fromHeading(heading: string): Slug {
const slugifiedHeading = encodeURI(heading.trim()
.toLowerCase()
.replace(/./g, c => Slug.specialChars[c] || c)
.replace(/[\]\[\!\'\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\_\{\|\}\~\`]/g, '')
.replace(/\s+/g, '-') // Replace whitespace with -
.replace(/[^\w\-]+/g, '') // Remove remaining non-word chars
.replace(/^\-+/, '') // Remove leading -
.replace(/\-+$/, '') // Remove trailing -
);
return new Slug(slugifiedHeading);
}
private constructor(
public readonly value: string
) { }
public equals(other: Slug): boolean {
return this.value === other.value;
}
}
import { Slug, stripSlugifier } from './slugify';
export interface TocEntry {
readonly slug: Slug;
......@@ -62,7 +36,7 @@ export class TableOfContentsProvider {
public async lookup(fragment: string): Promise<TocEntry | undefined> {
const toc = await this.getToc();
const slug = Slug.fromHeading(fragment);
const slug = stripSlugifier.fromHeading(fragment);
return toc.find(entry => entry.slug.equals(slug));
}
......@@ -74,7 +48,7 @@ export class TableOfContentsProvider {
const lineNumber = heading.map[0];
const line = document.lineAt(lineNumber);
toc.push({
slug: Slug.fromHeading(line.text),
slug: stripSlugifier.fromHeading(line.text),
text: TableOfContentsProvider.getHeaderText(line.text),
level: TableOfContentsProvider.getHeaderLevel(heading.markup),
line: lineNumber,
......
......@@ -3,7 +3,7 @@
"version": "0.0.1",
"description": "Dependencies shared by all extensions",
"dependencies": {
"typescript": "2.9.1-insiders.20180521"
"typescript": "2.9.1-insiders.20180525"
},
"scripts": {
"postinstall": "node ./postinstall"
......
......@@ -256,6 +256,24 @@ export default class BufferSyncSupport {
}, 200);
}
public getErr(resources: Uri[]): any {
const handledResources = resources.filter(resource => this.handles(resource));
if (!handledResources.length) {
return;
}
for (const resource of handledResources) {
const file = this.client.normalizePath(resource);
if (file) {
this.pendingDiagnostics.set(file, Date.now());
}
}
this.diagnosticDelayer.trigger(() => {
this.sendPendingDiagnostics();
}, 200);
}
public requestDiagnostic(resource: Uri): void {
if (!this._validate) {
return;
......
......@@ -105,8 +105,6 @@ export class DiagnosticsManager {
return;
}
collection.set(file, diagnostics);
if (diagnostics.length === 0) {
const existing = collection.get(file);
if (existing.length === 0) {
......@@ -115,6 +113,8 @@ export class DiagnosticsManager {
}
}
collection.set(file, diagnostics);
this.scheduleDiagnosticsUpdate(file);
}
......
......@@ -116,34 +116,30 @@ export class UpdateImportsOnFileRenameHandler {
Never = 4,
}
interface Item extends vscode.QuickPickItem {
interface Item extends vscode.MessageItem {
choice: Choice;
}
const response = await vscode.window.showQuickPick<Item>([
{
label: localize('accept.label', "Yes"),
description: localize('accept.description', "Update imports."),
choice: Choice.Accept,
const response = await vscode.window.showInformationMessage<Item>(
localize('prompt', "Automatically update imports for moved file: '{0}'?", path.basename(newDocument.fileName)), {
modal: true,
},
{
label: localize('reject.label', "No"),
description: localize('reject.description', "Do not update imports."),
title: localize('reject.title', "No"),
choice: Choice.Reject,
isCloseAffordance: true,
},
{
title: localize('accept.title', "Yes"),
choice: Choice.Accept,
},
{
label: localize('always.label', "Always"),
description: localize('always.description', "Yes, and always automatically update imports."),
title: localize('always.title', "Yes, always update imports"),
choice: Choice.Always,
},
{
label: localize('never.label', "Never"),
description: localize('never.description', "No, and do not prompt me again."),
title: localize('never.title', "No, never update imports"),
choice: Choice.Never,
},
], {
placeHolder: localize('prompt', "Update import paths for moved file: '{0}'?", path.basename(newDocument.fileName)),
ignoreFocusOut: true,
});
if (!response) {
......
......@@ -247,6 +247,10 @@ export default class LanguageProvider {
this.registerVersionDependentProviders();
}
public getErr(resources: Uri[]) {
this.bufferSyncSupport.getErr(resources);
}
private async registerVersionDependentProviders(): Promise<void> {
disposeAll(this.versionDependentDisposables);
......
......@@ -78,6 +78,13 @@ export default class TypeScriptServiceClientHost {
this.client.onConfigDiagnosticsReceived(diag => this.configFileDiagnosticsReceived(diag), null, this.disposables);
this.client.onResendModelsRequested(() => this.populateService(), null, this.disposables);
this.client.onProjectUpdatedInBackground(files => {
const resources = files.openFiles.map(Uri.file);
for (const language of this.languagePerId.values()) {
language.getErr(resources);
}
}, null, this.disposables);
this.versionStatus = new VersionStatus(resource => this.client.normalizePath(resource));
this.disposables.push(this.versionStatus);
......
......@@ -184,9 +184,6 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
private callbacks: CallbackMap;
private readonly _onTsServerStarted = new EventEmitter<API>();
private readonly _onProjectLanguageServiceStateChanged = new EventEmitter<Proto.ProjectLanguageServiceStateEventBody>();
private readonly _onDidBeginInstallTypings = new EventEmitter<Proto.BeginInstallTypesEventBody>();
private readonly _onDidEndInstallTypings = new EventEmitter<Proto.EndInstallTypesEventBody>();
private readonly _onTypesInstallerInitializationFailed = new EventEmitter<Proto.TypesInstallerInitializationFailedEventBody>();
public readonly telemetryReporter: TelemetryReporter;
......@@ -307,17 +304,17 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
return this._onTsServerStarted.event;
}
get onProjectLanguageServiceStateChanged(): Event<Proto.ProjectLanguageServiceStateEventBody> {
return this._onProjectLanguageServiceStateChanged.event;
}
private readonly _onProjectUpdatedInBackground = new EventEmitter<Proto.ProjectsUpdatedInBackgroundEventBody>();
public readonly onProjectUpdatedInBackground = this._onProjectUpdatedInBackground.event;
get onDidBeginInstallTypings(): Event<Proto.BeginInstallTypesEventBody> {
return this._onDidBeginInstallTypings.event;
}
private readonly _onProjectLanguageServiceStateChanged = new EventEmitter<Proto.ProjectLanguageServiceStateEventBody>();
public readonly onProjectLanguageServiceStateChanged = this._onProjectLanguageServiceStateChanged.event;
get onDidEndInstallTypings(): Event<Proto.EndInstallTypesEventBody> {
return this._onDidEndInstallTypings.event;
}
private readonly _onDidBeginInstallTypings = new EventEmitter<Proto.BeginInstallTypesEventBody>();
public readonly onDidBeginInstallTypings = this._onDidBeginInstallTypings.event;
private readonly _onDidEndInstallTypings = new EventEmitter<Proto.EndInstallTypesEventBody>();
public readonly onDidEndInstallTypings = this._onDidEndInstallTypings.event;
get onTypesInstallerInitializationFailed(): Event<Proto.TypesInstallerInitializationFailedEventBody> {
return this._onTypesInstallerInitializationFailed.event;
......@@ -875,6 +872,12 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
}
break;
case 'projectsUpdatedInBackground':
if (event.body) {
this._onProjectUpdatedInBackground.fire((event as Proto.ProjectsUpdatedInBackgroundEvent).body);
}
break;
case 'beginInstallTypes':
if (event.body) {
this._onDidBeginInstallTypings.fire((event as Proto.BeginInstallTypesEvent).body);
......@@ -1015,6 +1018,11 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
args.push('--locale', tsLocale);
}
}
if (this.apiVersion.has291Features()) {
args.push('--noGetErrOnBackgroundUpdate');
}
return args;
}
......
......@@ -106,4 +106,9 @@ export default class API {
public has290Features(): boolean {
return semver.gte(this.version, '2.9.0');
}
@memoize
public has291Features(): boolean {
return semver.gte(this.version, '2.9.1');
}
}
\ No newline at end of file
......@@ -2,6 +2,6 @@
# yarn lockfile v1
typescript@2.9.1-insiders.20180521:
version "2.9.1-insiders.20180521"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.1-insiders.20180521.tgz#37e9c05f00aa99864c3f66781e607ae0097c2b0a"
typescript@2.9.1-insiders.20180525:
version "2.9.1-insiders.20180525"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.1-insiders.20180525.tgz#f28e73af2b9f2411c872a1a79a7a84ee54e5f7d8"
......@@ -16,6 +16,8 @@ cd $ROOT
./scripts/code.sh $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
./scripts/code.sh $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
./scripts/code.sh $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
./scripts/code.sh $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started
mkdir $ROOT/extensions/emmet/test-fixtures
./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disableExtensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started .
rm -r $ROOT/extensions/emmet/test-fixtures
......
......@@ -12,6 +12,7 @@ import URI from 'vs/base/common/uri';
import * as Objects from 'vs/base/common/objects';
import { TPromise } from 'vs/base/common/winjs.base';
import * as Types from 'vs/base/common/types';
import * as Platform from 'vs/base/common/platform';
import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
......@@ -21,12 +22,11 @@ import {
} from 'vs/workbench/parts/tasks/common/tasks';
import { ITaskService, TaskFilter } from 'vs/workbench/parts/tasks/common/taskService';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, MainThreadTaskShape, ExtHostTaskShape, MainContext, IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
import {
TaskDefinitionDTO, TaskExecutionDTO, ProcessExecutionOptionsDTO, TaskPresentationOptionsDTO,
ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO
ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO
} from 'vs/workbench/api/shared/tasks';
export { TaskDTO, TaskHandleDTO, TaskExecutionDTO, TaskFilterDTO };
......@@ -357,6 +357,7 @@ namespace TaskFilterDTO {
@extHostNamedCustomer(MainContext.MainThreadTask)
export class MainThreadTask implements MainThreadTaskShape {
private _extHostContext: IExtHostContext;
private _proxy: ExtHostTaskShape;
private _activeHandles: { [handle: number]: boolean; };
......@@ -471,4 +472,26 @@ export class MainThreadTask implements MainThreadTaskShape {
});
});
}
public $registerTaskSystem(key: string, info: TaskSystemInfoDTO): void {
let platform: Platform.Platform;
switch (info.platform) {
case 'win32':
platform = Platform.Platform.Windows;
break;
case 'darwin':
platform = Platform.Platform.Mac;
break;
case 'linux':
platform = Platform.Platform.Linux;
break;
default:
platform = Platform.platform;
}
this._taskService.registerTaskSystem(key, {
platform: platform,
fileSystemScheme: key,
context: this._extHostContext
});
}
}
......@@ -48,7 +48,7 @@ import { CommentRule, CharacterPair, EnterAction } from 'vs/editor/common/modes/
import { ISingleEditOperation } from 'vs/editor/common/model';
import { IPatternInfo, IRawSearchQuery, IRawFileMatch2, ISearchCompleteStats } from 'vs/platform/search/common/search';
import { LogLevel } from 'vs/platform/log/common/log';
import { TaskExecutionDTO, TaskDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO } from 'vs/workbench/api/shared/tasks';
import { TaskExecutionDTO, TaskDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO } from 'vs/workbench/api/shared/tasks';
export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
......@@ -410,10 +410,11 @@ export interface MainThreadSearchShape extends IDisposable {
export interface MainThreadTaskShape extends IDisposable {
$registerTaskProvider(handle: number): TPromise<void>;
$unregisterTaskProvider(handle: number): TPromise<void>;
$fetchTasks(filter?: TaskFilterDTO): TPromise<TaskDTO[]>;
$executeTask(task: TaskHandleDTO | TaskDTO): TPromise<TaskExecutionDTO>;
$terminateTask(id: string): TPromise<void>;
$unregisterTaskProvider(handle: number): TPromise<void>;
$registerTaskSystem(scheme: string, info: TaskSystemInfoDTO): void;
}
export interface MainThreadExtensionServiceShape extends IDisposable {
......
......@@ -12,7 +12,7 @@ import { asWinJsPromise } from 'vs/base/common/async';
import { Event, Emitter } from 'vs/base/common/event';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import * as TaskSystem from 'vs/workbench/parts/tasks/common/tasks';
import * as tasks from 'vs/workbench/parts/tasks/common/tasks';
import { MainContext, MainThreadTaskShape, ExtHostTaskShape, IMainContext } from 'vs/workbench/api/node/extHost.protocol';
......@@ -21,7 +21,7 @@ import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import * as vscode from 'vscode';
import {
TaskDefinitionDTO, TaskExecutionDTO, TaskPresentationOptionsDTO, ProcessExecutionOptionsDTO, ProcessExecutionDTO,
ShellExecutionOptionsDTO, ShellExecutionDTO, TaskDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO
ShellExecutionOptionsDTO, ShellExecutionDTO, TaskDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO
} from '../shared/tasks';
export { TaskExecutionDTO };
......@@ -197,40 +197,40 @@ namespace ProblemMatcher {
*/
namespace TaskRevealKind {
export function from(value: vscode.TaskRevealKind): TaskSystem.RevealKind {
export function from(value: vscode.TaskRevealKind): tasks.RevealKind {
if (value === void 0 || value === null) {
return TaskSystem.RevealKind.Always;
return tasks.RevealKind.Always;
}
switch (value) {
case types.TaskRevealKind.Silent:
return TaskSystem.RevealKind.Silent;
return tasks.RevealKind.Silent;
case types.TaskRevealKind.Never:
return TaskSystem.RevealKind.Never;
return tasks.RevealKind.Never;
}
return TaskSystem.RevealKind.Always;
return tasks.RevealKind.Always;
}
}
namespace TaskPanelKind {
export function from(value: vscode.TaskPanelKind): TaskSystem.PanelKind {
export function from(value: vscode.TaskPanelKind): tasks.PanelKind {
if (value === void 0 || value === null) {
return TaskSystem.PanelKind.Shared;
return tasks.PanelKind.Shared;
}
switch (value) {
case types.TaskPanelKind.Dedicated:
return TaskSystem.PanelKind.Dedicated;
return tasks.PanelKind.Dedicated;
case types.TaskPanelKind.New:
return TaskSystem.PanelKind.New;
return tasks.PanelKind.New;
default:
return TaskSystem.PanelKind.Shared;
return tasks.PanelKind.Shared;
}
}
}
namespace PresentationOptions {
export function from(value: vscode.TaskPresentationOptions): TaskSystem.PresentationOptions {
export function from(value: vscode.TaskPresentationOptions): tasks.PresentationOptions {
if (value === void 0 || value === null) {
return { reveal: TaskSystem.RevealKind.Always, echo: true, focus: false, panel: TaskSystem.PanelKind.Shared };
return { reveal: tasks.RevealKind.Always, echo: true, focus: false, panel: tasks.PanelKind.Shared };
}
return {
reveal: TaskRevealKind.from(value.reveal),
......@@ -259,11 +259,11 @@ namespace CommandOptions {
function isShellConfiguration(value: any): value is { executable: string; shellArgs?: string[] } {
return value && typeof value.executable === 'string';
}
export function from(value: vscode.ShellExecutionOptions | vscode.ProcessExecutionOptions): TaskSystem.CommandOptions {
export function from(value: vscode.ShellExecutionOptions | vscode.ProcessExecutionOptions): tasks.CommandOptions {
if (value === void 0 || value === null) {
return undefined;
}
let result: TaskSystem.CommandOptions = {
let result: tasks.CommandOptions = {
};
if (typeof value.cwd === 'string') {
result.cwd = value.cwd;
......@@ -285,7 +285,7 @@ namespace CommandOptions {
}
namespace ShellQuoteOptions {
export function from(value: vscode.ShellQuotingOptions): TaskSystem.ShellQuotingOptions {
export function from(value: vscode.ShellQuotingOptions): tasks.ShellQuotingOptions {
if (value === void 0 || value === null) {
return undefined;
}
......@@ -298,12 +298,12 @@ namespace ShellQuoteOptions {
}
namespace ShellConfiguration {
export function from(value: { executable?: string, shellArgs?: string[], quotes?: vscode.ShellQuotingOptions }): TaskSystem.ShellConfiguration {
export function from(value: { executable?: string, shellArgs?: string[], quotes?: vscode.ShellQuotingOptions }): tasks.ShellConfiguration {
if (value === void 0 || value === null || !value.executable) {
return undefined;
}
let result: TaskSystem.ShellConfiguration = {
let result: tasks.ShellConfiguration = {
executable: value.executable,
args: Strings.from(value.shellArgs),
quoting: ShellQuoteOptions.from(value.quotes)
......@@ -313,7 +313,7 @@ namespace ShellConfiguration {
}
namespace ShellString {
export function from(value: (string | vscode.ShellQuotedString)[]): TaskSystem.CommandString[] {
export function from(value: (string | vscode.ShellQuotedString)[]): tasks.CommandString[] {
if (value === void 0 || value === null) {
return undefined;
}
......@@ -323,11 +323,11 @@ namespace ShellString {
namespace Tasks {
export function from(tasks: vscode.Task[], rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): TaskSystem.ContributedTask[] {
export function from(tasks: vscode.Task[], rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): tasks.ContributedTask[] {
if (tasks === void 0 || tasks === null) {
return [];
}
let result: TaskSystem.ContributedTask[] = [];
let result: tasks.ContributedTask[] = [];
for (let task of tasks) {
let converted = fromSingle(task, rootFolder, extension);
if (converted) {
......@@ -337,11 +337,11 @@ namespace Tasks {
return result;
}
function fromSingle(task: vscode.Task, rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): TaskSystem.ContributedTask {
function fromSingle(task: vscode.Task, rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): tasks.ContributedTask {
if (typeof task.name !== 'string') {
return undefined;
}
let command: TaskSystem.CommandConfiguration;
let command: tasks.CommandConfiguration;
let execution = task.execution;
if (execution instanceof types.ProcessExecution) {
command = getProcessCommand(execution);
......@@ -357,21 +357,21 @@ namespace Tasks {
let taskScope: types.TaskScope.Global | types.TaskScope.Workspace | vscode.WorkspaceFolder | undefined = task.scope;
let workspaceFolder: vscode.WorkspaceFolder | undefined;
let scope: TaskSystem.TaskScope;
let scope: tasks.TaskScope;
// For backwards compatibility
if (taskScope === void 0) {
scope = TaskSystem.TaskScope.Folder;
scope = tasks.TaskScope.Folder;
workspaceFolder = rootFolder;
} else if (taskScope === types.TaskScope.Global) {
scope = TaskSystem.TaskScope.Global;
scope = tasks.TaskScope.Global;
} else if (taskScope === types.TaskScope.Workspace) {
scope = TaskSystem.TaskScope.Workspace;
scope = tasks.TaskScope.Workspace;
} else {
scope = TaskSystem.TaskScope.Folder;
scope = tasks.TaskScope.Folder;
workspaceFolder = taskScope;
}
let source: TaskSystem.ExtensionTaskSource = {
kind: TaskSystem.TaskSourceKind.Extension,
let source: tasks.ExtensionTaskSource = {
kind: tasks.TaskSourceKind.Extension,
label: typeof task.source === 'string' ? task.source : extension.name,
extension: extension.id,
scope: scope,
......@@ -380,17 +380,17 @@ namespace Tasks {
// We can't transfer a workspace folder object from the extension host to main since they differ
// in shape and we don't have backwards converting function. So transfer the URI and resolve the
// workspace folder on the main side.
(source as any as TaskSystem.ExtensionTaskSourceTransfer).__workspaceFolder = workspaceFolder ? workspaceFolder.uri as URI : undefined;
(source as any as tasks.ExtensionTaskSourceTransfer).__workspaceFolder = workspaceFolder ? workspaceFolder.uri as URI : undefined;
let label = nls.localize('task.label', '{0}: {1}', source.label, task.name);
let key = (task as types.Task).definitionKey;
let kind = (task as types.Task).definition;
let id = `${extension.id}.${key}`;
let taskKind: TaskSystem.TaskIdentifier = {
let taskKind: tasks.TaskIdentifier = {
_key: key,
type: kind.type
};
Objects.assign(taskKind, kind);
let result: TaskSystem.ContributedTask = {
let result: tasks.ContributedTask = {
_id: id, // uuidMap.getUUID(identifier),
_source: source,
_label: label,
......@@ -407,14 +407,14 @@ namespace Tasks {
return result;
}
function getProcessCommand(value: vscode.ProcessExecution): TaskSystem.CommandConfiguration {
function getProcessCommand(value: vscode.ProcessExecution): tasks.CommandConfiguration {
if (typeof value.process !== 'string') {
return undefined;
}
let result: TaskSystem.CommandConfiguration = {
let result: tasks.CommandConfiguration = {
name: value.process,
args: Strings.from(value.args),
runtime: TaskSystem.RuntimeType.Process,
runtime: tasks.RuntimeType.Process,
suppressTaskName: true,
presentation: undefined
};
......@@ -424,15 +424,15 @@ namespace Tasks {
return result;
}
function getShellCommand(value: vscode.ShellExecution): TaskSystem.CommandConfiguration {
function getShellCommand(value: vscode.ShellExecution): tasks.CommandConfiguration {
if (value.args) {
if (typeof value.command !== 'string' && typeof value.command.value !== 'string') {
return undefined;
}
let result: TaskSystem.CommandConfiguration = {
let result: tasks.CommandConfiguration = {
name: value.command,
args: ShellString.from(value.args),
runtime: TaskSystem.RuntimeType.Shell,
runtime: tasks.RuntimeType.Shell,
presentation: undefined
};
if (value.options) {
......@@ -443,9 +443,9 @@ namespace Tasks {
if (typeof value.commandLine !== 'string') {
return undefined;
}
let result: TaskSystem.CommandConfiguration = {
let result: tasks.CommandConfiguration = {
name: value.commandLine,
runtime: TaskSystem.RuntimeType.Shell,
runtime: tasks.RuntimeType.Shell,
presentation: undefined
};
if (value.options) {
......@@ -728,7 +728,7 @@ interface HandlerData {
export class ExtHostTask implements ExtHostTaskShape {
private _proxy: MainThreadTaskShape;
private _extHostWorkspace: ExtHostWorkspace;
private _workspaceService: ExtHostWorkspace;
private _handleCounter: number;
private _handlers: Map<number, HandlerData>;
private _taskExecutions: Map<string, TaskExecutionImpl>;
......@@ -739,16 +739,16 @@ export class ExtHostTask implements ExtHostTaskShape {
private readonly _onDidTaskProcessStarted: Emitter<vscode.TaskProcessStartEvent> = new Emitter<vscode.TaskProcessStartEvent>();
private readonly _onDidTaskProcessEnded: Emitter<vscode.TaskProcessEndEvent> = new Emitter<vscode.TaskProcessEndEvent>();
constructor(mainContext: IMainContext, extHostWorkspace: ExtHostWorkspace) {
constructor(mainContext: IMainContext, workspaceService: ExtHostWorkspace) {
this._proxy = mainContext.getProxy(MainContext.MainThreadTask);
this._extHostWorkspace = extHostWorkspace;
this._workspaceService = workspaceService;
this._handleCounter = 0;
this._handlers = new Map<number, HandlerData>();
this._taskExecutions = new Map<string, TaskExecutionImpl>();
}
public get extHostWorkspace(): ExtHostWorkspace {
return this._extHostWorkspace;
return this._workspaceService;
}
public registerTaskProvider(extension: IExtensionDescription, provider: vscode.TaskProvider): vscode.Disposable {
......@@ -764,11 +764,15 @@ export class ExtHostTask implements ExtHostTaskShape {
});
}
public registerTaskSystem(scheme: string, info: TaskSystemInfoDTO): void {
this._proxy.$registerTaskSystem(scheme, info);
}
public fetchTasks(filter?: vscode.TaskFilter): Thenable<vscode.Task[]> {
return this._proxy.$fetchTasks(TaskFilterDTO.from(filter)).then((values) => {
let result: vscode.Task[] = [];
for (let value of values) {
let task = TaskDTO.to(value, this._extHostWorkspace);
let task = TaskDTO.to(value, this._workspaceService);
if (task) {
result.push(task);
}
......@@ -854,13 +858,13 @@ export class ExtHostTask implements ExtHostTaskShape {
}
}
public $provideTasks(handle: number): TPromise<TaskSystem.TaskSet> {
public $provideTasks(handle: number): TPromise<tasks.TaskSet> {
let handler = this._handlers.get(handle);
if (!handler) {
return TPromise.wrapError<TaskSystem.TaskSet>(new Error('no handler found'));
return TPromise.wrapError<tasks.TaskSet>(new Error('no handler found'));
}
return asWinJsPromise(token => handler.provider.provideTasks(token)).then(value => {
let workspaceFolders = this._extHostWorkspace.getWorkspaceFolders();
let workspaceFolders = this._workspaceService.getWorkspaceFolders();
return {
tasks: Tasks.from(value, workspaceFolders && workspaceFolders.length > 0 ? workspaceFolders[0] : undefined, handler.extension),
extension: handler.extension
......@@ -881,7 +885,7 @@ export class ExtHostTask implements ExtHostTaskShape {
if (result) {
return result;
}
result = new TaskExecutionImpl(this, execution.id, task ? task : TaskDTO.to(execution.task, this._extHostWorkspace));
result = new TaskExecutionImpl(this, execution.id, task ? task : TaskDTO.to(execution.task, this._workspaceService));
this._taskExecutions.set(execution.id, result);
return result;
}
......
......@@ -102,4 +102,8 @@ export interface TaskProcessEndedDTO {
export interface TaskFilterDTO {
version?: string;
type?: string;
}
export interface TaskSystemInfoDTO {
platform: string;
}
\ No newline at end of file
......@@ -20,7 +20,7 @@ import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import {
IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, IExtensionManifest,
InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier, EnablementState, IExtensionTipsService
InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier, EnablementState, IExtensionTipsService, InstallOperation
} from 'vs/platform/extensionManagement/common/extensionManagement';
import { getGalleryExtensionIdFromLocal, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
......@@ -805,11 +805,11 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
private onDidInstallExtension(event: DidInstallExtensionEvent): void {
const { local, zipPath, error, gallery } = event;
const installingExtension = gallery ? this.installing.filter(e => areSameExtensions(e, gallery.identifier))[0] : null;
const extension: Extension = installingExtension ? installingExtension : zipPath ? new Extension(this.galleryService, this.stateProvider, null, null, this.telemetryService) : null;
const extension: Extension = installingExtension ? installingExtension : zipPath ? new Extension(this.galleryService, this.stateProvider, local, null, this.telemetryService) : null;
if (extension) {
this.installing = installingExtension ? this.installing.filter(e => e !== installingExtension) : this.installing;
const installed = this.installed.filter(e => e.id === extension.id)[0];
if (!error) {
const installed = this.installed.filter(e => e.id === extension.id)[0];
extension.local = local;
if (installed) {
installed.local = local;
......@@ -817,7 +817,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
this.installed.push(extension);
}
}
if (extension.gallery && !installed) {
if (extension.gallery && event.operation === InstallOperation.Install) {
// Report recommendation telemetry only for gallery extensions that are first time installs
this.reportExtensionRecommendationsTelemetry(installingExtension);
}
......@@ -930,7 +930,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
const extensionId = match[1];
this.queryLocal().then(local => {
const extension = local.filter(local => local.id === extensionId)[0];
const extension = local.filter(local => areSameExtensions({ id: local.id }, { id: extensionId }))[0];
if (extension) {
return this.windowService.show()
......
......@@ -132,10 +132,6 @@
bottom: 10px;
}
.settings-editor > .settings-body > .settings-tree-container .monaco-tree .monaco-tree-row {
background-color: initial !important;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.odd:not(.focused):not(.selected):not(:hover),
.settings-editor > .settings-body > .settings-tree-container .monaco-tree:not(:focus) .setting-item.focused.odd:not(.selected):not(:hover),
.settings-editor > .settings-body > .settings-tree-container .monaco-tree:not(.focused) .setting-item.focused.odd:not(.selected):not(:hover) {
......
......@@ -11,6 +11,8 @@ import { Color } from 'vs/base/common/color';
import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors';
import { KeyCode } from 'vs/base/common/keyCodes';
import { TPromise } from 'vs/base/common/winjs.base';
import { ITreeConfiguration } from 'vs/base/parts/tree/browser/tree';
import { DefaultTreestyler } from 'vs/base/parts/tree/browser/treeDefaults';
import 'vs/css!./media/settingsEditor2';
import { localize } from 'vs/nls';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
......@@ -18,6 +20,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { WorkbenchTree } from 'vs/platform/list/browser/listService';
import { ILogService } from 'vs/platform/log/common/log';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { editorBackground, foreground } from 'vs/platform/theme/common/colorRegistry';
import { attachButtonStyler, attachStyler } from 'vs/platform/theme/common/styler';
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
......@@ -187,13 +190,15 @@ export class SettingsEditor2 extends BaseEditor {
this._register(renderer.onDidChangeSetting(e => this.onDidChangeSetting(e.key, e.value)));
this._register(renderer.onDidClickButton(e => this.onDidClickShowAllSettings()));
const treeClass = 'settings-editor-tree';
this.settingsTree = this.instantiationService.createInstance(WorkbenchTree, this.settingsTreeContainer,
{
<ITreeConfiguration>{
dataSource: this.treeDataSource,
renderer: renderer,
controller: this.instantiationService.createInstance(SettingsTreeController),
accessibilityProvider: this.instantiationService.createInstance(SettingsAccessibilityProvider),
filter: this.instantiationService.createInstance(SettingsTreeFilter, this.viewState)
filter: this.instantiationService.createInstance(SettingsTreeFilter, this.viewState),
styler: new DefaultTreestyler(DOM.createStyleSheet(), treeClass)
},
{
ariaLabel: localize('treeAriaLabel', "Settings"),
......@@ -214,17 +219,19 @@ export class SettingsEditor2 extends BaseEditor {
}
}));
this.settingsTree.getHTMLElement().classList.add(treeClass);
attachStyler(this.themeService, {
listActiveSelectionBackground: null,
listActiveSelectionForeground: null,
listFocusAndSelectionBackground: null,
listFocusAndSelectionForeground: null,
listFocusBackground: null,
listFocusForeground: null,
listHoverForeground: null,
listHoverBackground: null,
listInactiveSelectionBackground: null,
listInactiveSelectionForeground: null
listActiveSelectionBackground: editorBackground,
listActiveSelectionForeground: foreground,
listFocusAndSelectionBackground: editorBackground,
listFocusAndSelectionForeground: foreground,
listFocusBackground: editorBackground,
listFocusForeground: foreground,
listHoverForeground: foreground,
listHoverBackground: editorBackground,
listInactiveSelectionBackground: editorBackground,
listInactiveSelectionForeground: foreground
}, colors => {
this.settingsTree.style(colors);
});
......
......@@ -134,6 +134,7 @@ export interface ProblemMatcher {
pattern: ProblemPattern | ProblemPattern[];
severity?: Severity;
watching?: WatchingMatcher;
fileSystemScheme?: string;
}
export interface NamedProblemMatcher extends ProblemMatcher {
......@@ -195,7 +196,11 @@ export function getResource(filename: string, matcher: ProblemMatcher): URI {
if (fullPath[0] !== '/') {
fullPath = '/' + fullPath;
}
return URI.parse('file://' + fullPath);
if (matcher.fileSystemScheme !== void 0) {
return URI.parse(`${matcher.fileSystemScheme}://${fullPath}`);
} else {
return URI.file(fullPath);
}
}
export interface ILineMatcher {
......
......@@ -12,7 +12,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { Task, ContributedTask, CustomTask, TaskSet, TaskSorter, TaskEvent } from 'vs/workbench/parts/tasks/common/tasks';
import { ITaskSummary, TaskTerminateResponse } from 'vs/workbench/parts/tasks/common/taskSystem';
import { ITaskSummary, TaskTerminateResponse, TaskSystemInfo } from 'vs/workbench/parts/tasks/common/taskSystem';
export { ITaskSummary, Task, TaskTerminateResponse };
......@@ -66,4 +66,6 @@ export interface ITaskService {
registerTaskProvider(handle: number, taskProvider: ITaskProvider): void;
unregisterTaskProvider(handle: number): boolean;
registerTaskSystem(scheme: string, taskSystemInfo: TaskSystemInfo): void;
}
\ No newline at end of file
......@@ -8,6 +8,7 @@ import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
import { TerminateResponse } from 'vs/base/common/processes';
import { Event } from 'vs/base/common/event';
import { Platform } from 'vs/base/common/platform';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
......@@ -101,6 +102,16 @@ export interface TaskTerminateResponse extends TerminateResponse {
task: Task | undefined;
}
export interface TaskSystemInfo {
fileSystemScheme: string;
platform: Platform;
context: any;
}
export interface TaskSystemInfoResovler {
(workspaceFolder: IWorkspaceFolder): TaskSystemInfo;
}
export interface ITaskSystem {
onDidStateChange: Event<TaskEvent>;
run(task: Task, resolver: ITaskResolver): ITaskExecuteResult;
......
......@@ -25,6 +25,7 @@ import { TerminateResponseCode } from 'vs/base/common/processes';
import * as strings from 'vs/base/common/strings';
import { ValidationStatus, ValidationState } from 'vs/base/common/parsers';
import * as UUID from 'vs/base/common/uuid';
import * as Platform from 'vs/base/common/platform';
import { LinkedMap, Touch } from 'vs/base/common/map';
import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
......@@ -70,7 +71,7 @@ import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs
import { ITerminalService } from 'vs/workbench/parts/terminal/common/terminal';
import { ITaskSystem, ITaskResolver, ITaskSummary, TaskExecuteKind, TaskError, TaskErrors, TaskTerminateResponse } from 'vs/workbench/parts/tasks/common/taskSystem';
import { ITaskSystem, ITaskResolver, ITaskSummary, TaskExecuteKind, TaskError, TaskErrors, TaskTerminateResponse, TaskSystemInfo } from 'vs/workbench/parts/tasks/common/taskSystem';
import {
Task, CustomTask, ConfiguringTask, ContributedTask, InMemoryTask, TaskEvent,
TaskEventKind, TaskSet, TaskGroup, GroupType, ExecutionEngine, JsonSchemaVersion, TaskSourceKind,
......@@ -442,12 +443,13 @@ class TaskService implements ITaskService {
public static OutputChannelLabel: string = nls.localize('tasks', "Tasks");
private _configHasErrors: boolean;
private __schemaVersion: JsonSchemaVersion;
private __executionEngine: ExecutionEngine;
private __workspaceFolders: IWorkspaceFolder[];
private __ignoredWorkspaceFolders: IWorkspaceFolder[];
private __showIgnoreMessage: boolean;
private _schemaVersion: JsonSchemaVersion;
private _executionEngine: ExecutionEngine;
private _workspaceFolders: IWorkspaceFolder[];
private _ignoredWorkspaceFolders: IWorkspaceFolder[];
private _showIgnoreMessage: boolean;
private _providers: Map<number, ITaskProvider>;
private _taskSystemInfos: Map<string, TaskSystemInfo>;
private _workspaceTasksPromise: TPromise<Map<string, WorkspaceFolderTaskResult>>;
......@@ -486,6 +488,7 @@ class TaskService implements ITaskService {
this._taskSystemListener = undefined;
this._outputChannel = this.outputService.getChannel(TaskService.OutputChannelId);
this._providers = new Map<number, ITaskProvider>();
this._taskSystemInfos = new Map<string, TaskSystemInfo>();
this.configurationService.onDidChangeConfiguration(() => {
if (!this._taskSystem && !this._workspaceTasksPromise) {
return;
......@@ -584,62 +587,62 @@ class TaskService implements ITaskService {
}
private get workspaceFolders(): IWorkspaceFolder[] {
if (!this.__workspaceFolders) {
if (!this._workspaceFolders) {
this.updateSetup();
}
return this.__workspaceFolders;
return this._workspaceFolders;
}
private get ignoredWorkspaceFolders(): IWorkspaceFolder[] {
if (!this.__ignoredWorkspaceFolders) {
if (!this._ignoredWorkspaceFolders) {
this.updateSetup();
}
return this.__ignoredWorkspaceFolders;
return this._ignoredWorkspaceFolders;
}
private get executionEngine(): ExecutionEngine {
if (this.__executionEngine === void 0) {
if (this._executionEngine === void 0) {
this.updateSetup();
}
return this.__executionEngine;
return this._executionEngine;
}
private get schemaVersion(): JsonSchemaVersion {
if (this.__schemaVersion === void 0) {
if (this._schemaVersion === void 0) {
this.updateSetup();
}
return this.__schemaVersion;
return this._schemaVersion;
}
private get showIgnoreMessage(): boolean {
if (this.__showIgnoreMessage === void 0) {
this.__showIgnoreMessage = !this.storageService.getBoolean(TaskService.IgnoreTask010DonotShowAgain_key, StorageScope.WORKSPACE, false);
if (this._showIgnoreMessage === void 0) {
this._showIgnoreMessage = !this.storageService.getBoolean(TaskService.IgnoreTask010DonotShowAgain_key, StorageScope.WORKSPACE, false);
}
return this.__showIgnoreMessage;
return this._showIgnoreMessage;
}
private updateSetup(setup?: [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion]): void {
if (!setup) {
setup = this.computeWorkspaceFolderSetup();
}
this.__workspaceFolders = setup[0];
if (this.__ignoredWorkspaceFolders) {
if (this.__ignoredWorkspaceFolders.length !== setup[1].length) {
this.__showIgnoreMessage = undefined;
this._workspaceFolders = setup[0];
if (this._ignoredWorkspaceFolders) {
if (this._ignoredWorkspaceFolders.length !== setup[1].length) {
this._showIgnoreMessage = undefined;
} else {
let set: Set<string> = new Set();
this.__ignoredWorkspaceFolders.forEach(folder => set.add(folder.uri.toString()));
this._ignoredWorkspaceFolders.forEach(folder => set.add(folder.uri.toString()));
for (let folder of setup[1]) {
if (!set.has(folder.uri.toString())) {
this.__showIgnoreMessage = undefined;
this._showIgnoreMessage = undefined;
break;
}
}
}
}
this.__ignoredWorkspaceFolders = setup[1];
this.__executionEngine = setup[2];
this.__schemaVersion = setup[3];
this._ignoredWorkspaceFolders = setup[1];
this._executionEngine = setup[2];
this._schemaVersion = setup[3];
}
private showOutput(): void {
......@@ -663,6 +666,10 @@ class TaskService implements ITaskService {
return this._providers.delete(handle);
}
public registerTaskSystem(key: string, info: TaskSystemInfo): void {
this._taskSystemInfos.set(key, info);
}
public getTask(folder: IWorkspaceFolder | string, alias: string, compareId: boolean = false): TPromise<Task> {
let name = Types.isString(folder) ? folder : folder.name;
if (this.ignoredWorkspaceFolders.some(ignored => ignored.name === name)) {
......@@ -1244,7 +1251,13 @@ class TaskService implements ITaskService {
this._taskSystem = new TerminalTaskSystem(
this.terminalService, this.outputService, this.markerService,
this.modelService, this.configurationResolverService, this.telemetryService,
this.contextService, TaskService.OutputChannelId
this.contextService, TaskService.OutputChannelId,
(workspaceFolder: IWorkspaceFolder) => {
if (!workspaceFolder) {
return undefined;
}
return this._taskSystemInfos.get(workspaceFolder.uri.scheme);
}
);
} else {
let system = new ProcessTaskSystem(
......@@ -1472,8 +1485,9 @@ class TaskService implements ITaskService {
return TPromise.as({ workspaceFolder, set: undefined, configurations: undefined, hasErrors: workspaceFolderConfiguration ? workspaceFolderConfiguration.hasErrors : false });
}
return ProblemMatcherRegistry.onReady().then((): WorkspaceFolderTaskResult => {
let taskSystemInfo: TaskSystemInfo = this._taskSystemInfos.get(workspaceFolder.uri.scheme);
let problemReporter = new ProblemReporter(this._outputChannel);
let parseResult = TaskConfig.parse(workspaceFolder, workspaceFolderConfiguration.config, problemReporter);
let parseResult = TaskConfig.parse(workspaceFolder, taskSystemInfo ? taskSystemInfo.platform : Platform.platform, workspaceFolderConfiguration.config, problemReporter);
let hasErrors = false;
if (!parseResult.validationStatus.isOK()) {
hasErrors = true;
......@@ -1869,7 +1883,7 @@ class TaskService implements ITaskService {
isSecondary: true,
run: () => {
this.storageService.store(TaskService.IgnoreTask010DonotShowAgain_key, true, StorageScope.WORKSPACE);
this.__showIgnoreMessage = false;
this._showIgnoreMessage = false;
}
}]
);
......
......@@ -37,7 +37,7 @@ import {
} from 'vs/workbench/parts/tasks/common/tasks';
import {
ITaskSystem, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, ITaskResolver,
TelemetryEvent, Triggers, TaskTerminateResponse
TelemetryEvent, Triggers, TaskTerminateResponse, TaskSystemInfoResovler, TaskSystemInfo
} from 'vs/workbench/parts/tasks/common/taskSystem';
interface TerminalData {
......@@ -96,6 +96,7 @@ export class TerminalTaskSystem implements ITaskSystem {
private terminals: IStringDictionary<TerminalData>;
private idleTaskTerminals: LinkedMap<string, string>;
private sameTaskTerminals: IStringDictionary<string>;
private taskSystemInfoResolver: TaskSystemInfoResovler;
private readonly _onDidStateChange: Emitter<TaskEvent>;
......@@ -104,7 +105,8 @@ export class TerminalTaskSystem implements ITaskSystem {
private configurationResolverService: IConfigurationResolverService,
private telemetryService: ITelemetryService,
private contextService: IWorkspaceContextService,
outputChannelId: string) {
outputChannelId: string,
taskSystemInfoResolver: TaskSystemInfoResovler) {
this.outputChannel = this.outputService.getChannel(outputChannelId);
this.activeTasks = Object.create(null);
......@@ -113,6 +115,7 @@ export class TerminalTaskSystem implements ITaskSystem {
this.sameTaskTerminals = Object.create(null);
this._onDidStateChange = new Emitter();
this.taskSystemInfoResolver = taskSystemInfoResolver;
}
public get onDidStateChange(): Event<TaskEvent> {
......@@ -830,11 +833,23 @@ export class TerminalTaskSystem implements ITaskSystem {
this.outputChannel.append(nls.localize('unkownProblemMatcher', 'Problem matcher {0} can\'t be resolved. The matcher will be ignored'));
return;
}
if (!matcher.filePrefix) {
let workspaceFolder = Task.getWorkspaceFolder(task);
let taskSystemInfo: TaskSystemInfo;
if (workspaceFolder) {
taskSystemInfo = this.taskSystemInfoResolver(workspaceFolder);
}
let hasFilePrefix = matcher.filePrefix !== void 0;
let hasScheme = taskSystemInfo !== void 0 && taskSystemInfo.fileSystemScheme !== void 0 && taskSystemInfo.fileSystemScheme === 'file';
if (!hasFilePrefix && !hasScheme) {
result.push(matcher);
} else {
let copy = Objects.deepClone(matcher);
copy.filePrefix = this.resolveVariable(task, copy.filePrefix);
if (hasScheme) {
copy.fileSystemScheme = taskSystemInfo.fileSystemScheme;
}
if (hasFilePrefix) {
copy.filePrefix = this.resolveVariable(task, copy.filePrefix);
}
result.push(copy);
}
});
......
......@@ -10,7 +10,7 @@ import * as nls from 'vs/nls';
import * as Objects from 'vs/base/common/objects';
import { IStringDictionary } from 'vs/base/common/collections';
import * as Platform from 'vs/base/common/platform';
import { Platform } from 'vs/base/common/platform';
import * as Types from 'vs/base/common/types';
import * as UUID from 'vs/base/common/uuid';
......@@ -614,6 +614,7 @@ interface ParseContext {
uuidMap: UUIDMap;
engine: Tasks.ExecutionEngine;
schemaVersion: Tasks.JsonSchemaVersion;
platform: Platform;
}
......@@ -829,11 +830,11 @@ namespace CommandConfiguration {
let result: Tasks.CommandConfiguration = fromBase(config, context);
let osConfig: Tasks.CommandConfiguration = undefined;
if (config.windows && Platform.platform === Platform.Platform.Windows) {
if (config.windows && context.platform === Platform.Windows) {
osConfig = fromBase(config.windows, context);
} else if (config.osx && Platform.platform === Platform.Platform.Mac) {
} else if (config.osx && context.platform === Platform.Mac) {
osConfig = fromBase(config.osx, context);
} else if (config.linux && Platform.platform === Platform.Platform.Linux) {
} else if (config.linux && context.platform === Platform.Linux) {
osConfig = fromBase(config.linux, context);
}
if (osConfig) {
......@@ -1553,11 +1554,11 @@ namespace Globals {
export function from(config: ExternalTaskRunnerConfiguration, context: ParseContext): Globals {
let result = fromBase(config, context);
let osGlobals: Globals = undefined;
if (config.windows && Platform.platform === Platform.Platform.Windows) {
if (config.windows && context.platform === Platform.Windows) {
osGlobals = fromBase(config.windows, context);
} else if (config.osx && Platform.platform === Platform.Platform.Mac) {
} else if (config.osx && context.platform === Platform.Mac) {
osGlobals = fromBase(config.osx, context);
} else if (config.linux && Platform.platform === Platform.Platform.Linux) {
} else if (config.linux && context.platform === Platform.Linux) {
osGlobals = fromBase(config.linux, context);
}
if (osGlobals) {
......@@ -1742,9 +1743,11 @@ class ConfigurationParser {
private workspaceFolder: IWorkspaceFolder;
private problemReporter: IProblemReporter;
private uuidMap: UUIDMap;
private platform: Platform;
constructor(workspaceFolder: IWorkspaceFolder, problemReporter: IProblemReporter, uuidMap: UUIDMap) {
constructor(workspaceFolder: IWorkspaceFolder, platform: Platform, problemReporter: IProblemReporter, uuidMap: UUIDMap) {
this.workspaceFolder = workspaceFolder;
this.platform = platform;
this.problemReporter = problemReporter;
this.uuidMap = uuidMap;
}
......@@ -1758,7 +1761,8 @@ class ConfigurationParser {
uuidMap: this.uuidMap,
namedProblemMatchers: undefined,
engine,
schemaVersion
schemaVersion,
platform: this.platform
};
let taskParseResult = this.createTaskRunnerConfiguration(fileConfig, context);
return {
......@@ -1777,13 +1781,13 @@ class ConfigurationParser {
context.namedProblemMatchers = ProblemMatcherConverter.namedFrom(fileConfig.declares, context);
let globalTasks: Tasks.CustomTask[];
let externalGlobalTasks: (ConfiguringTask | CustomTask)[];
if (fileConfig.windows && Platform.platform === Platform.Platform.Windows) {
if (fileConfig.windows && context.platform === Platform.Windows) {
globalTasks = TaskParser.from(fileConfig.windows.tasks, globals, context).custom;
externalGlobalTasks = fileConfig.windows.tasks;
} else if (fileConfig.osx && Platform.platform === Platform.Platform.Mac) {
} else if (fileConfig.osx && context.platform === Platform.Mac) {
globalTasks = TaskParser.from(fileConfig.osx.tasks, globals, context).custom;
externalGlobalTasks = fileConfig.osx.tasks;
} else if (fileConfig.linux && Platform.platform === Platform.Platform.Linux) {
} else if (fileConfig.linux && context.platform === Platform.Linux) {
globalTasks = TaskParser.from(fileConfig.linux.tasks, globals, context).custom;
externalGlobalTasks = fileConfig.linux.tasks;
}
......@@ -1846,7 +1850,7 @@ class ConfigurationParser {
}
let uuidMaps: Map<string, UUIDMap> = new Map();
export function parse(workspaceFolder: IWorkspaceFolder, configuration: ExternalTaskRunnerConfiguration, logger: IProblemReporter): ParseResult {
export function parse(workspaceFolder: IWorkspaceFolder, platform: Platform, configuration: ExternalTaskRunnerConfiguration, logger: IProblemReporter): ParseResult {
let uuidMap = uuidMaps.get(workspaceFolder.uri.toString());
if (!uuidMap) {
uuidMap = new UUIDMap();
......@@ -1854,7 +1858,7 @@ export function parse(workspaceFolder: IWorkspaceFolder, configuration: External
}
try {
uuidMap.start();
return (new ConfigurationParser(workspaceFolder, logger, uuidMap)).run(configuration);
return (new ConfigurationParser(workspaceFolder, platform, logger, uuidMap)).run(configuration);
} finally {
uuidMap.finish();
}
......
......@@ -350,7 +350,7 @@ class PatternBuilder {
function testDefaultProblemMatcher(external: ExternalTaskRunnerConfiguration, resolved: number) {
let reporter = new ProblemReporter();
let result = parse(workspaceFolder, external, reporter);
let result = parse(workspaceFolder, Platform.platform, external, reporter);
assert.ok(!reporter.receivedMessage);
assert.strictEqual(result.custom.length, 1);
let task = result.custom[0];
......@@ -361,7 +361,7 @@ function testDefaultProblemMatcher(external: ExternalTaskRunnerConfiguration, re
function testConfiguration(external: ExternalTaskRunnerConfiguration, builder: ConfiguationBuilder): void {
builder.done();
let reporter = new ProblemReporter();
let result = parse(workspaceFolder, external, reporter);
let result = parse(workspaceFolder, Platform.platform, external, reporter);
if (reporter.receivedMessage) {
assert.ok(false, reporter.lastMessage);
}
......
......@@ -160,9 +160,7 @@ export class Configuration extends BaseConfiguration {
const { added, updated, removed } = compare(this.user, user);
let changedKeys = [...added, ...updated, ...removed];
if (changedKeys.length) {
const oldValues = changedKeys.map(key => this.getValue(key));
super.updateUserConfiguration(user);
changedKeys = changedKeys.filter((key, index) => !equals(oldValues[index], this.getValue(key)));
}
return new ConfigurationChangeEvent().change(changedKeys);
}
......@@ -171,9 +169,7 @@ export class Configuration extends BaseConfiguration {
const { added, updated, removed } = compare(this.workspace, workspaceConfiguration);
let changedKeys = [...added, ...updated, ...removed];
if (changedKeys.length) {
const oldValues = changedKeys.map(key => this.getValue(key));
super.updateWorkspaceConfiguration(workspaceConfiguration);
changedKeys = changedKeys.filter((key, index) => !equals(oldValues[index], this.getValue(key)));
}
return new ConfigurationChangeEvent().change(changedKeys);
}
......@@ -184,9 +180,7 @@ export class Configuration extends BaseConfiguration {
const { added, updated, removed } = compare(currentFolderConfiguration, folderConfiguration);
let changedKeys = [...added, ...updated, ...removed];
if (changedKeys.length) {
const oldValues = changedKeys.map(key => this.getValue(key, { resource }));
super.updateFolderConfiguration(resource, folderConfiguration);
changedKeys = changedKeys.filter((key, index) => !equals(oldValues[index], this.getValue(key, { resource })));
}
return new ConfigurationChangeEvent().change(changedKeys, resource);
} else {
......
......@@ -12,7 +12,7 @@ import * as pfs from 'vs/base/node/pfs';
import * as errors from 'vs/base/common/errors';
import * as collections from 'vs/base/common/collections';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { RunOnceScheduler } from 'vs/base/common/async';
import { RunOnceScheduler, Delayer } from 'vs/base/common/async';
import { FileChangeType, FileChangesEvent, IContent, IFileService } from 'vs/platform/files/common/files';
import { isLinux } from 'vs/base/common/platform';
import { ConfigWatcher } from 'vs/base/node/config';
......@@ -258,35 +258,33 @@ export class NodeBasedFolderConfiguration extends AbstractFolderConfiguration {
export class FileServiceBasedFolderConfiguration extends AbstractFolderConfiguration {
private bulkContentFetchromise: TPromise<any>;
private workspaceFilePathToConfiguration: { [relativeWorkspacePath: string]: TPromise<IContent> };
private reloadConfigurationScheduler: RunOnceScheduler;
private readonly folderConfigurationPath: URI;
private readonly loadConfigurationDelayer: Delayer<{ resource: URI, value: string }[]> = new Delayer<{ resource: URI, value: string }[]>(50);
constructor(folder: URI, private configFolderRelativePath: string, workbenchState: WorkbenchState, private fileService: IFileService, from?: AbstractFolderConfiguration) {
super(folder, workbenchState, from);
this.folderConfigurationPath = folder.with({ path: paths.join(this.folder.path, configFolderRelativePath) });
this.workspaceFilePathToConfiguration = Object.create(null);
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50));
this._register(fileService.onFileChanges(e => this.handleWorkspaceFileEvents(e)));
}
protected loadFolderConfigurationContents(): TPromise<{ resource: URI, value: string }[]> {
// once: when invoked for the first time we fetch json files that contribute settings
if (!this.bulkContentFetchromise) {
this.bulkContentFetchromise = this.fileService.resolveFile(this.folderConfigurationPath)
.then(stat => {
if (stat.isDirectory && stat.children) {
stat.children
.filter(child => isFolderConfigurationFile(child.resource))
.forEach(child => this.workspaceFilePathToConfiguration[this.toFolderRelativePath(child.resource)] = this.fileService.resolveContent(child.resource).then(null, errors.onUnexpectedError));
}
}).then(null, err => [] /* never fail this call */);
}
return this.loadConfigurationDelayer.trigger(() => this.doLoadFolderConfigurationContents());
}
private doLoadFolderConfigurationContents(): TPromise<{ resource: URI, value: string }[]> {
const workspaceFilePathToConfiguration: { [relativeWorkspacePath: string]: TPromise<IContent> } = Object.create(null);
const bulkContentFetchromise = this.fileService.resolveFile(this.folderConfigurationPath)
.then(stat => {
if (stat.isDirectory && stat.children) {
stat.children
.filter(child => isFolderConfigurationFile(child.resource))
.forEach(child => workspaceFilePathToConfiguration[this.toFolderRelativePath(child.resource)] = this.fileService.resolveContent(child.resource).then(null, errors.onUnexpectedError));
}
}).then(null, err => [] /* never fail this call */);
// on change: join on *all* configuration file promises so that we can merge them into a single configuration object. this
// happens whenever a config file changes, is deleted, or added
return this.bulkContentFetchromise.then(() => TPromise.join(this.workspaceFilePathToConfiguration).then(result => collections.values(result)));
return bulkContentFetchromise.then(() => TPromise.join(workspaceFilePathToConfiguration).then(result => collections.values(result)));
}
private handleWorkspaceFileEvents(event: FileChangesEvent): void {
......@@ -312,7 +310,6 @@ export class FileServiceBasedFolderConfiguration extends AbstractFolderConfigura
// Handle case where ".vscode" got deleted
if (isDeletedSettingsFolder) {
this.workspaceFilePathToConfiguration = Object.create(null);
affectedByChanges = true;
}
......@@ -321,15 +318,10 @@ export class FileServiceBasedFolderConfiguration extends AbstractFolderConfigura
continue;
}
// insert 'fetch-promises' for add and update events and
// remove promises for delete events
switch (events[i].type) {
case FileChangeType.DELETED:
affectedByChanges = collections.remove(this.workspaceFilePathToConfiguration, folderRelativePath);
break;
case FileChangeType.UPDATED:
case FileChangeType.ADDED:
this.workspaceFilePathToConfiguration[folderRelativePath] = this.fileService.resolveContent(resource).then(null, errors.onUnexpectedError);
affectedByChanges = true;
}
}
......
......@@ -152,10 +152,12 @@ suite('WorkspaceContextService - Workspace', () => {
return workspaceService.initialize({ id: configPath, configPath }).then(() => {
instantiationService.stub(IFileService, new FileService(<IWorkspaceContextService>workspaceService, TestEnvironmentService, new TestTextResourceConfigurationService(), workspaceService, new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true }));
const fileService = new FileService(<IWorkspaceContextService>workspaceService, TestEnvironmentService, new TestTextResourceConfigurationService(), workspaceService, new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true });
instantiationService.stub(IFileService, fileService);
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
workspaceService.acquireInstantiationService(instantiationService);
workspaceService.acquireFileService(fileService);
testObject = workspaceService;
});
......@@ -410,10 +412,12 @@ suite('WorkspaceService - Initialization', () => {
instantiationService.stub(IEnvironmentService, environmentService);
return workspaceService.initialize(<IWindowConfiguration>{}).then(() => {
instantiationService.stub(IFileService, new FileService(<IWorkspaceContextService>workspaceService, TestEnvironmentService, new TestTextResourceConfigurationService(), workspaceService, new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true }));
const fileService = new FileService(<IWorkspaceContextService>workspaceService, TestEnvironmentService, new TestTextResourceConfigurationService(), workspaceService, new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true });
instantiationService.stub(IFileService, fileService);
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
workspaceService.acquireInstantiationService(instantiationService);
workspaceService.acquireFileService(fileService);
testObject = workspaceService;
});
});
......@@ -663,10 +667,12 @@ suite('WorkspaceConfigurationService - Folder', () => {
instantiationService.stub(IEnvironmentService, environmentService);
return workspaceService.initialize(folderDir).then(() => {
instantiationService.stub(IFileService, new FileService(<IWorkspaceContextService>workspaceService, TestEnvironmentService, new TestTextResourceConfigurationService(), workspaceService, new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true }));
const fileService = new FileService(<IWorkspaceContextService>workspaceService, TestEnvironmentService, new TestTextResourceConfigurationService(), workspaceService, new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true });
instantiationService.stub(IFileService, fileService);
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
workspaceService.acquireInstantiationService(instantiationService);
workspaceService.acquireFileService(fileService);
testObject = workspaceService;
});
});
......@@ -895,7 +901,7 @@ suite('WorkspaceConfigurationService - Folder', () => {
});
suite('WorkspaceConfigurationService - Multiroot', () => {
suite('WorkspaceConfigurationService-Multiroot', () => {
let parentResource: string, workspaceContextService: IWorkspaceContextService, environmentService: IEnvironmentService, jsonEditingServce: IJSONEditingService, testObject: IWorkspaceConfigurationService;
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
......@@ -939,10 +945,12 @@ suite('WorkspaceConfigurationService - Multiroot', () => {
return workspaceService.initialize({ id: configPath, configPath }).then(() => {
instantiationService.stub(IFileService, new FileService(<IWorkspaceContextService>workspaceService, TestEnvironmentService, new TestTextResourceConfigurationService(), workspaceService, new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true }));
const fileService = new FileService(<IWorkspaceContextService>workspaceService, TestEnvironmentService, new TestTextResourceConfigurationService(), workspaceService, new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true });
instantiationService.stub(IFileService, fileService);
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
workspaceService.acquireInstantiationService(instantiationService);
workspaceService.acquireFileService(fileService);
workspaceContextService = workspaceService;
jsonEditingServce = instantiationService.createInstance(JSONEditingService);
......@@ -1177,6 +1185,17 @@ suite('WorkspaceConfigurationService - Multiroot', () => {
.then(() => assert.ok(target.called));
});
test('update workspace folder configuration second time should trigger change event before promise is resolve', () => {
const workspace = workspaceContextService.getWorkspace();
return testObject.updateValue('configurationService.workspace.testResourceSetting', 'workspaceFolderValue', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER)
.then(() => {
const target = sinon.spy();
testObject.onDidChangeConfiguration(target);
return testObject.updateValue('configurationService.workspace.testResourceSetting', 'workspaceFolderValue2', { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER)
.then(() => assert.ok(target.called));
});
});
test('update tasks configuration in a folder', () => {
const workspace = workspaceContextService.getWorkspace();
return testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER)
......
......@@ -6,6 +6,7 @@
import { PPromise, TPromise } from 'vs/base/common/winjs.base';
import uri from 'vs/base/common/uri';
import * as arrays from 'vs/base/common/arrays';
import * as objects from 'vs/base/common/objects';
import * as strings from 'vs/base/common/strings';
import { getNextTickChannel } from 'vs/base/parts/ipc/common/ipc';
......@@ -96,11 +97,7 @@ export class SearchService implements ISearchService {
const startTime = Date.now();
const searchWithProvider = (provider: ISearchResultProvider) => TPromise.wrap(provider.search(query)).then(e => e,
err => {
// TODO@joh
// single provider fail. fail all?
onError(err);
},
null,
progress => {
if (progress.resource) {
// Match
......@@ -123,7 +120,19 @@ export class SearchService implements ISearchService {
// If no search providers are registered, fall back on DiskSearch
// TODO@roblou this is not properly waiting for search-rg to finish registering itself
if (this.searchProvider.length) {
return searchWithProvider(this.searchProvider[0]);
return TPromise.join(this.searchProvider.map(p => searchWithProvider(p)))
.then(complete => {
const first: ISearchComplete = complete[0];
if (!first) {
return null;
}
return <ISearchComplete>{
limitHit: first && first.limitHit,
stats: first.stats,
results: arrays.flatten(complete.map(c => c.results))
};
});
} else {
return searchWithProvider(this.diskSearch);
}
......
......@@ -5,11 +5,6 @@
import { ISuiteCallbackContext, ITestCallbackContext } from 'mocha';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export function describeRepeat(n: number, description: string, callback: (this: ISuiteCallbackContext) => void): void {
for (let i = 0; i < n; i++) {
describe(`${description} (iteration ${i})`, callback);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册