提交 95deca76 编写于 作者: D Dirk Baeumer

More work to make task multi folder aware

上级 351b05d6
......@@ -6,6 +6,9 @@
import { TPromise } from 'vs/base/common/winjs.base';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ContributedTask, ExtensionTaskSourceTransfer } from 'vs/workbench/parts/tasks/common/tasks';
import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService';
import { ExtHostContext, MainThreadTaskShape, ExtHostTaskShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
......@@ -19,7 +22,8 @@ export class MainThreadTask implements MainThreadTaskShape {
constructor(
extHostContext: IExtHostContext,
@ITaskService private _taskService: ITaskService
@ITaskService private _taskService: ITaskService,
@IWorkspaceContextService private _workspaceContextServer: IWorkspaceContextService
) {
this._proxy = extHostContext.get(ExtHostContext.ExtHostTask);
this._activeHandles = Object.create(null);
......@@ -35,7 +39,17 @@ export class MainThreadTask implements MainThreadTaskShape {
public $registerTaskProvider(handle: number): TPromise<void> {
this._taskService.registerTaskProvider(handle, {
provideTasks: () => {
return this._proxy.$provideTasks(handle);
return this._proxy.$provideTasks(handle).then((value) => {
for (let task of value.tasks) {
if (ContributedTask.is(task)) {
let uri = (task._source as any as ExtensionTaskSourceTransfer).__workspaceFolder;
if (uri) {
(task._source as any).workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(uri);
}
}
}
return value;
});
}
});
this._activeHandles[handle] = true;
......
......@@ -348,8 +348,12 @@ namespace Tasks {
label: typeof task.source === 'string' ? task.source : extension.name,
extension: extension.id,
scope: scope,
workspaceFolder: workspaceFolder ? { uri: workspaceFolder.uri as URI } : undefined
workspaceFolder: undefined
};
// 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).__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;
......
......@@ -748,7 +748,7 @@ export class DebugService implements debug.IDebugService {
return TPromise.wrapError(errors.create(message, { actions: [this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL), CloseAction] }));
}
return this.runPreLaunchTask(resolvedConfig.preLaunchTask).then((taskSummary: ITaskSummary) => {
return this.runPreLaunchTask(root, resolvedConfig.preLaunchTask).then((taskSummary: ITaskSummary) => {
const errorCount = resolvedConfig.preLaunchTask ? this.markerService.getStatistics().errors : 0;
const successExitCode = taskSummary && taskSummary.exitCode === 0;
const failureExitCode = taskSummary && taskSummary.exitCode !== undefined && taskSummary.exitCode !== 0;
......@@ -921,13 +921,13 @@ export class DebugService implements debug.IDebugService {
});
}
private runPreLaunchTask(taskName: string): TPromise<ITaskSummary> {
private runPreLaunchTask(root: WorkspaceFolder, taskName: string): TPromise<ITaskSummary> {
if (!taskName) {
return TPromise.as(null);
}
// run a task before starting a debug session
return this.taskService.getTask(taskName).then(task => {
return this.taskService.getTask(root, taskName).then(task => {
if (!task) {
return TPromise.wrapError(errors.create(nls.localize('DebugTaskNotFound', "Could not find the preLaunchTask \'{0}\'.", taskName)));
}
......
......@@ -5,7 +5,6 @@
'use strict';
import * as nls from 'vs/nls';
import * as Paths from 'vs/base/common/paths';
import * as Filters from 'vs/base/common/filters';
import { TPromise } from 'vs/base/common/winjs.base';
import { Action, IAction } from 'vs/base/common/actions';
......@@ -38,7 +37,7 @@ export class TaskEntry extends Model.QuickOpenEntry {
if (!workspaceFolder) {
return null;
}
return `(${Paths.basename(workspaceFolder.uri.fsPath)})`;
return `(${workspaceFolder.name})`;
}
public getAriaLabel(): string {
......@@ -115,12 +114,13 @@ export abstract class QuickOpenHandler extends Quickopen.QuickOpenHandler {
}
}
}
const sorter = this.taskService.createSorter();
let hasRecentlyUsed: boolean = recent.length > 0;
this.fillEntries(entries, input, recent, nls.localize('recentlyUsed', 'recently used tasks'));
configured = configured.sort((a, b) => a._label.localeCompare(b._label));
configured = configured.sort((a, b) => sorter.compare(a, b));
let hasConfigured = configured.length > 0;
this.fillEntries(entries, input, configured, nls.localize('configured', 'configured tasks'), hasRecentlyUsed);
detected = detected.sort((a, b) => a._label.localeCompare(b._label));
detected = detected.sort((a, b) => sorter.compare(a, b));
this.fillEntries(entries, input, detected, nls.localize('detected', 'detected tasks'), hasRecentlyUsed || hasConfigured);
return new Model.QuickOpenModel(entries, new ContributableActionProvider());
});
......@@ -158,7 +158,7 @@ class CustomizeTaskAction extends Action {
private static ID = 'workbench.action.tasks.customizeTask';
private static LABEL = nls.localize('customizeTask', "Configure Task");
constructor(private taskService: ITaskService, private quickOpenService: IQuickOpenService, private task: CustomTask | ContributedTask) {
constructor(private taskService: ITaskService, private quickOpenService: IQuickOpenService) {
super(CustomizeTaskAction.ID, CustomizeTaskAction.LABEL);
this.updateClass();
}
......@@ -167,23 +167,36 @@ class CustomizeTaskAction extends Action {
this.class = 'quick-open-task-configure';
}
public run(context: any): TPromise<any> {
if (ContributedTask.is(this.task)) {
return this.taskService.customize(this.task, undefined, true).then(() => {
public run(element: any): TPromise<any> {
let task = this.getTask(element);
if (ContributedTask.is(task)) {
return this.taskService.customize(task, undefined, true).then(() => {
this.quickOpenService.close();
});
} else {
return this.taskService.openConfig(this.task).then(() => {
return this.taskService.openConfig(task).then(() => {
this.quickOpenService.close();
});
}
}
private getTask(element: any): CustomTask | ContributedTask {
if (element instanceof TaskEntry) {
return element.task;
} else if (element instanceof TaskGroupEntry) {
return (element.getEntry() as TaskEntry).task;
}
return undefined;
}
}
export class QuickOpenActionContributor extends ActionBarContributor {
private action: CustomizeTaskAction;
constructor( @ITaskService private taskService: ITaskService, @IQuickOpenService private quickOpenService: IQuickOpenService) {
super();
this.action = new CustomizeTaskAction(taskService, quickOpenService);
}
public hasActions(context: any): boolean {
......@@ -196,7 +209,7 @@ export class QuickOpenActionContributor extends ActionBarContributor {
let actions: Action[] = [];
let task = this.getTask(context);
if (task && ContributedTask.is(task) || CustomTask.is(task)) {
actions.push(new CustomizeTaskAction(this.taskService, this.quickOpenService, task));
actions.push(this.action);
}
return actions;
}
......
......@@ -9,7 +9,9 @@ import { Action } from 'vs/base/common/actions';
import { IEventEmitter } from 'vs/base/common/eventEmitter';
import { LinkedMap } from 'vs/base/common/map';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Task, ContributedTask, CustomTask, TaskSet } from 'vs/workbench/parts/tasks/common/tasks';
import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { Task, ContributedTask, CustomTask, TaskSet, TaskSorter } from 'vs/workbench/parts/tasks/common/tasks';
import { ITaskSummary, TaskEvent, TaskType, TaskTerminateResponse } from 'vs/workbench/parts/tasks/common/taskSystem';
export { ITaskSummary, Task, TaskEvent, TaskType, TaskTerminateResponse };
......@@ -55,9 +57,10 @@ export interface ITaskService extends IEventEmitter {
/**
* @param identifier The task's name, label or defined identifier.
*/
getTask(identifier: string): TPromise<Task>;
getTask(workspaceFolder: WorkspaceFolder | string, identifier: string): TPromise<Task>;
getTasksForGroup(group: string): TPromise<Task[]>;
getRecentlyUsedTasks(): LinkedMap<string, string>;
createSorter(): TaskSorter;
hasMultipleFolders();
canCustomize(task: ContributedTask | CustomTask): boolean;
......
......@@ -8,6 +8,9 @@ import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
import { TerminateResponse } from 'vs/base/common/processes';
import { IEventEmitter } from 'vs/base/common/eventEmitter';
import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { Task } from './tasks';
export enum TaskErrors {
......@@ -101,7 +104,7 @@ export interface TaskEvent {
}
export interface ITaskResolver {
resolve(identifier: string): Task;
resolve(workspaceFolder: WorkspaceFolder, identifier: string): Task;
}
export interface TaskTerminateResponse extends TerminateResponse {
......
......@@ -11,6 +11,7 @@ import * as Objects from 'vs/base/common/objects';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ProblemMatcher } from 'vs/platform/markers/common/problemMatcher';
import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
export interface ShellConfiguration {
/**
......@@ -229,10 +230,6 @@ export namespace TaskSourceKind {
export const Composite: 'composite' = 'composite';
}
export interface WorkspaceFolder {
uri: URI;
}
export interface TaskSourceConfigElement {
workspaceFolder: WorkspaceFolder;
file: string;
......@@ -255,6 +252,10 @@ export interface ExtensionTaskSource {
readonly workspaceFolder: WorkspaceFolder | undefined;
}
export interface ExtensionTaskSourceTransfer {
__workspaceFolder: URI;
}
export interface CompositeTaskSource {
readonly kind: 'composite';
readonly label: string;
......@@ -267,6 +268,11 @@ export interface TaskIdentifier {
type: string;
}
export interface TaskDependency {
workspaceFolder: WorkspaceFolder;
task: string;
}
export interface ConfigurationProperties {
/**
......@@ -307,7 +313,7 @@ export interface ConfigurationProperties {
/**
* The other tasks this task depends on.
*/
dependsOn?: string[];
dependsOn?: TaskDependency[];
/**
* The problem watchers to use for this task
......@@ -455,6 +461,10 @@ export namespace Task {
return 'unknown';
}
}
export function matches(task: Task, alias: string): boolean {
return alias === task._label || alias === task.identifier;
}
}
......@@ -481,4 +491,37 @@ export interface TaskDefinition {
taskType: string;
required: string[];
properties: IJSONSchemaMap;
}
export class TaskSorter {
private _order: Map<string, number> = new Map();
constructor(workspaceFolders: WorkspaceFolder[]) {
for (let i = 0; i < workspaceFolders.length; i++) {
this._order.set(workspaceFolders[i].uri.toString(), i);
}
}
public compare(a: Task, b: Task): number {
let aw = Task.getWorkspaceFolder(a);
let bw = Task.getWorkspaceFolder(b);
if (aw && bw) {
let ai = this._order.get(aw.uri.toString());
ai = ai === void 0 ? 0 : ai + 1;
let bi = this._order.get(bw.uri.toString());
bi = bi === void 0 ? 0 : bi + 1;
if (ai === bi) {
return a._label.localeCompare(b._label);
} else {
return ai - bi;
}
} else if (!aw && bw) {
return -1;
} else if (aw && !bw) {
return +1;
} else {
return 0;
}
}
}
\ No newline at end of file
......@@ -245,8 +245,8 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem {
private executeTask(startedTasks: IStringDictionary<TPromise<ITaskSummary>>, task: Task, resolver: ITaskResolver, trigger: string): TPromise<ITaskSummary> {
let promises: TPromise<ITaskSummary>[] = [];
if (task.dependsOn) {
task.dependsOn.forEach((identifier) => {
let task = resolver.resolve(identifier);
task.dependsOn.forEach((dependency) => {
let task = resolver.resolve(dependency.workspaceFolder, dependency.task);
if (task) {
let promise = startedTasks[task._id];
if (!promise) {
......@@ -254,6 +254,9 @@ export class TerminalTaskSystem extends EventEmitter implements ITaskSystem {
startedTasks[task._id] = promise;
}
promises.push(promise);
} else {
this.log(nls.localize('dependencyFailed', 'Couldn\'t resolve dependent task \'{0}\' in workspace folder \'{1}\'', dependency.task, dependency.workspaceFolder.name));
this.showOutput();
}
});
}
......
......@@ -20,6 +20,8 @@ import {
isNamedProblemMatcher, ProblemMatcherRegistry
} from 'vs/platform/markers/common/problemMatcher';
import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import * as Tasks from '../common/tasks';
import { TaskDefinitionRegistry } from '../common/taskDefinitionRegistry';
......@@ -561,7 +563,7 @@ function _freeze<T>(this: void, target: T, properties: MetaData<T, any>[]): Read
}
interface ParseContext {
workspaceFolder: Tasks.WorkspaceFolder;
workspaceFolder: WorkspaceFolder;
problemReporter: IProblemReporter;
namedProblemMatchers: IStringDictionary<NamedProblemMatcher>;
uuidMap: UUIDMap;
......@@ -1088,9 +1090,9 @@ namespace ConfigurationProperties {
}
if (external.dependsOn !== void 0) {
if (Types.isString(external.dependsOn)) {
result.dependsOn = [external.dependsOn];
result.dependsOn = [{ workspaceFolder: context.workspaceFolder, task: external.dependsOn }];
} else if (Types.isStringArray(external.dependsOn)) {
result.dependsOn = external.dependsOn.slice();
result.dependsOn = external.dependsOn.map((task) => { return { workspaceFolder: context.workspaceFolder, task: task }; });
}
}
if (includePresentation && (external.presentation !== void 0 || (external as LegacyCommandProperties).terminal !== void 0)) {
......@@ -1680,11 +1682,11 @@ class UUIDMap {
class ConfigurationParser {
private workspaceFolder: Tasks.WorkspaceFolder;
private workspaceFolder: WorkspaceFolder;
private problemReporter: IProblemReporter;
private uuidMap: UUIDMap;
constructor(workspaceFolder: Tasks.WorkspaceFolder, problemReporter: IProblemReporter, uuidMap: UUIDMap) {
constructor(workspaceFolder: WorkspaceFolder, problemReporter: IProblemReporter, uuidMap: UUIDMap) {
this.workspaceFolder = workspaceFolder;
this.problemReporter = problemReporter;
this.uuidMap = uuidMap;
......@@ -1789,7 +1791,7 @@ class ConfigurationParser {
}
let uuidMaps: Map<string, UUIDMap> = new Map();
export function parse(workspaceFolder: Tasks.WorkspaceFolder, configuration: ExternalTaskRunnerConfiguration, logger: IProblemReporter): ParseResult {
export function parse(workspaceFolder: WorkspaceFolder, configuration: ExternalTaskRunnerConfiguration, logger: IProblemReporter): ParseResult {
let uuidMap = uuidMaps.get(workspaceFolder.uri.toString());
if (!uuidMap) {
uuidMap = new UUIDMap();
......
......@@ -12,10 +12,18 @@ import * as UUID from 'vs/base/common/uuid';
import * as Platform from 'vs/base/common/platform';
import { ValidationStatus } from 'vs/base/common/parsers';
import { ProblemMatcher, FileLocationKind, ProblemPattern, ApplyToKind } from 'vs/platform/markers/common/problemMatcher';
import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import * as Tasks from 'vs/workbench/parts/tasks/common/tasks';
import { parse, ParseResult, IProblemReporter, ExternalTaskRunnerConfiguration, CustomTask } from 'vs/workbench/parts/tasks/node/taskConfiguration';
const workspaceFolder: WorkspaceFolder = {
uri: URI.file('/workspace/folderOne'),
name: 'folderOne',
index: 0,
raw: { path: '../folderOne', name: 'folderOne' }
};
class ProblemReporter implements IProblemReporter {
private _validationStatus: ValidationStatus = new ValidationStatus();
......@@ -178,7 +186,7 @@ class CustomTaskBuilder {
this.commandBuilder = new CommandConfigurationBuilder(this, command);
this.result = {
_id: name,
_source: { kind: Tasks.TaskSourceKind.Workspace, label: 'workspace', config: { workspaceFolder: { uri: undefined }, element: undefined, index: -1, file: '.vscode/tasks.json' } },
_source: { kind: Tasks.TaskSourceKind.Workspace, label: 'workspace', config: { workspaceFolder: workspaceFolder, element: undefined, index: -1, file: '.vscode/tasks.json' } },
_label: name,
type: 'custom',
identifier: name,
......@@ -348,7 +356,7 @@ class PatternBuilder {
function testDefaultProblemMatcher(external: ExternalTaskRunnerConfiguration, resolved: number) {
let reporter = new ProblemReporter();
let result = parse({ uri: URI.file('/Workspace/folderOne') }, external, reporter);
let result = parse(workspaceFolder, external, reporter);
assert.ok(!reporter.receivedMessage);
assert.strictEqual(result.custom.length, 1);
let task = result.custom[0];
......@@ -359,7 +367,7 @@ function testDefaultProblemMatcher(external: ExternalTaskRunnerConfiguration, re
function testConfiguration(external: ExternalTaskRunnerConfiguration, builder: ConfiguationBuilder): void {
builder.done();
let reporter = new ProblemReporter();
let result = parse({ uri: URI.file('/Workspace/folderOne') }, external, reporter);
let result = parse(workspaceFolder, external, reporter);
if (reporter.receivedMessage) {
assert.ok(false, reporter.lastMessage);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册