quickOpen.ts 8.0 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

import nls = require('vs/nls');
import Filters = require('vs/base/common/filters');
import { TPromise } from 'vs/base/common/winjs.base';
D
Dirk Baeumer 已提交
10
import { Action, IAction } from 'vs/base/common/actions';
11
import { IStringDictionary } from 'vs/base/common/collections';
12
import * as Objects from 'vs/base/common/objects';
13

14 15 16
import Quickopen = require('vs/workbench/browser/quickopen');
import QuickOpen = require('vs/base/parts/quickopen/common/quickOpen');
import Model = require('vs/base/parts/quickopen/browser/quickOpenModel');
17 18
import { IQuickOpenService, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen';
import { ProblemMatcherRegistry, NamedProblemMatcher } from 'vs/platform/markers/common/problemMatcher';
19

20
import { Task, TaskSourceKind } from 'vs/workbench/parts/tasks/common/tasks';
21
import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService';
22
import { ActionBarContributor, ContributableActionProvider } from 'vs/workbench/browser/actions';
23

24 25
interface ProblemMatcherPickEntry extends IPickOpenEntry {
	matcher: NamedProblemMatcher;
26
	learnMore?: boolean;
27 28
}

29 30
export class TaskEntry extends Model.QuickOpenEntry {

31
	constructor(protected taskService: ITaskService, protected quickOpenService: IQuickOpenService, protected _task: Task, highlights: Model.IHighlight[] = []) {
32 33 34 35
		super(highlights);
	}

	public getLabel(): string {
36
		return this.task._label;
37 38 39 40 41
	}

	public getAriaLabel(): string {
		return nls.localize('entryAriaLabel', "{0}, tasks", this.getLabel());
	}
D
Dirk Baeumer 已提交
42 43 44 45

	public get task(): Task {
		return this._task;
	}
46 47 48 49 50 51 52 53

	protected attachProblemMatcher(task: Task): TPromise<Task> {
		let entries: ProblemMatcherPickEntry[] = [];
		for (let key of ProblemMatcherRegistry.keys()) {
			let matcher = ProblemMatcherRegistry.get(key);
			if (matcher.name === matcher.label) {
				entries.push({ label: matcher.name, matcher: matcher });
			} else {
54 55 56 57 58
				entries.push({
					label: matcher.label,
					description: `$${matcher.name}`,
					matcher: matcher
				});
59 60 61
			}
		}
		if (entries.length > 0) {
62 63 64 65 66 67
			entries = entries.sort((a, b) => a.label.localeCompare(b.label));
			entries[0].separator = { border: true };
			entries.unshift(
				{ label: nls.localize('continueWithout', 'Continue without scanning the build output'), matcher: undefined },
				{ label: nls.localize('learnMoreAbout', 'Learn more about scanning the build output'), matcher: undefined, learnMore: true }
			);
68 69 70
			return this.quickOpenService.pick(entries, {
				placeHolder: nls.localize('selectProblemMatcher', 'Select for which kind of errors and warnings to scan the build output')
			}).then((selected) => {
71 72 73 74 75 76 77 78 79 80 81 82 83
				if (selected) {
					if (selected.learnMore) {
						this.taskService.openDocumentation();
						return undefined;
					} else if (selected.matcher) {
						let newTask = Objects.deepClone(task);
						let matcherReference = `$${selected.matcher.name}`;
						newTask.problemMatchers = [matcherReference];
						this.taskService.customize(task, { problemMatcher: [matcherReference] }, true);
						return newTask;
					} else {
						return task;
					}
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
				} else {
					return task;
				}
			});
		}
		return TPromise.as(task);
	}

	protected doRun(task: Task): boolean {
		this.taskService.run(task);
		if (task.command.presentation.focus) {
			this.quickOpenService.close();
			return false;
		}
		return true;
	}
100 101
}

102 103 104 105 106 107
export class TaskGroupEntry extends Model.QuickOpenEntryGroup {
	constructor(entry: TaskEntry, groupLabel: string, withBorder: boolean) {
		super(entry, groupLabel, withBorder);
	}
}

108 109
export abstract class QuickOpenHandler extends Quickopen.QuickOpenHandler {

110 111 112
	private tasks: TPromise<Task[]>;


113
	constructor(
114
		protected quickOpenService: IQuickOpenService,
115
		protected taskService: ITaskService
116 117 118 119 120 121 122
	) {
		super();

		this.quickOpenService = quickOpenService;
		this.taskService = taskService;
	}

123 124 125 126 127 128 129 130
	public onOpen(): void {
		this.tasks = this.getTasks();
	}

	public onClose(canceled: boolean): void {
		this.tasks = undefined;
	}

131
	public getResults(input: string): TPromise<Model.QuickOpenModel> {
132 133 134 135 136
		return this.tasks.then((tasks) => {
			let entries: Model.QuickOpenEntry[] = [];
			if (tasks.length === 0) {
				return new Model.QuickOpenModel(entries);
			}
137 138
			let recentlyUsedTasks = this.taskService.getRecentlyUsedTasks();
			let recent: Task[] = [];
139 140
			let configured: Task[] = [];
			let detected: Task[] = [];
141
			let taskMap: IStringDictionary<Task> = Object.create(null);
142
			tasks.forEach(task => taskMap[Task.getKey(task)] = task);
143 144 145 146
			recentlyUsedTasks.keys().forEach(key => {
				let task = taskMap[key];
				if (task) {
					recent.push(task);
147 148 149
				}
			});
			for (let task of tasks) {
150
				if (!recentlyUsedTasks.has(Task.getKey(task))) {
151 152 153 154 155
					if (task._source.kind === TaskSourceKind.Workspace) {
						configured.push(task);
					} else {
						detected.push(task);
					}
156 157
				}
			}
158 159 160 161
			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));
			let hasConfigured = configured.length > 0;
162
			this.fillEntries(entries, input, configured, nls.localize('configured', 'custom tasks'), hasRecentlyUsed);
163 164
			detected = detected.sort((a, b) => a._label.localeCompare(b._label));
			this.fillEntries(entries, input, detected, nls.localize('detected', 'detected tasks'), hasRecentlyUsed || hasConfigured);
165
			return new Model.QuickOpenModel(entries, new ContributableActionProvider());
166
		});
167 168
	}

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
	private fillEntries(entries: Model.QuickOpenEntry[], input: string, tasks: Task[], groupLabel: string, withBorder: boolean = false) {
		let first = true;
		for (let task of tasks) {
			let highlights = Filters.matchesContiguousSubString(input, task._label);
			if (!highlights) {
				continue;
			}
			if (first) {
				first = false;
				entries.push(new TaskGroupEntry(this.createEntry(task, highlights), groupLabel, withBorder));
			} else {
				entries.push(this.createEntry(task, highlights));
			}
		}
	}

185 186
	protected abstract getTasks(): TPromise<Task[]>;

187
	protected abstract createEntry(task: Task, highlights: Model.IHighlight[]): TaskEntry;
188 189 190 191 192 193

	public getAutoFocus(input: string): QuickOpen.IAutoFocus {
		return {
			autoFocusFirstEntry: !!input
		};
	}
D
Dirk Baeumer 已提交
194 195 196 197 198 199 200
}

class CustomizeTaskAction extends Action {

	private static ID = 'workbench.action.tasks.customizeTask';
	private static LABEL = nls.localize('customizeTask', "Customize Task");

D
Dirk Baeumer 已提交
201
	constructor(private taskService: ITaskService, private quickOpenService: IQuickOpenService, private task: Task) {
D
Dirk Baeumer 已提交
202 203 204 205 206
		super(CustomizeTaskAction.ID, CustomizeTaskAction.LABEL);
		this.updateClass();
	}

	public updateClass(): void {
207
		this.class = 'quick-open-task-configure';
D
Dirk Baeumer 已提交
208 209
	}

D
Dirk Baeumer 已提交
210
	public run(context: any): TPromise<any> {
211
		return this.taskService.customize(this.task, undefined, true).then(() => {
D
Dirk Baeumer 已提交
212 213
			this.quickOpenService.close();
		});
D
Dirk Baeumer 已提交
214 215 216 217 218
	}
}

export class QuickOpenActionContributor extends ActionBarContributor {

D
Dirk Baeumer 已提交
219
	constructor( @ITaskService private taskService: ITaskService, @IQuickOpenService private quickOpenService: IQuickOpenService) {
D
Dirk Baeumer 已提交
220 221 222 223
		super();
	}

	public hasActions(context: any): boolean {
D
Dirk Baeumer 已提交
224
		let task = this.getTask(context);
D
Dirk Baeumer 已提交
225

D
Dirk Baeumer 已提交
226
		return !!task;
D
Dirk Baeumer 已提交
227 228 229
	}

	public getActions(context: any): IAction[] {
D
Dirk Baeumer 已提交
230 231 232 233
		let actions: Action[] = [];
		let task = this.getTask(context);
		if (task && task._source.kind === TaskSourceKind.Extension) {
			actions.push(new CustomizeTaskAction(this.taskService, this.quickOpenService, task));
D
Dirk Baeumer 已提交
234 235 236 237
		}
		return actions;
	}

D
Dirk Baeumer 已提交
238 239
	private getTask(context: any): Task {
		if (!context) {
D
Dirk Baeumer 已提交
240 241
			return undefined;
		}
D
Dirk Baeumer 已提交
242 243 244 245 246 247 248
		let element = context.element;
		if (element instanceof TaskEntry) {
			return element.task;
		} else if (element instanceof TaskGroupEntry) {
			return (element.getEntry() as TaskEntry).task;
		}
		return undefined;
D
Dirk Baeumer 已提交
249
	}
250
}