Merge from vscode a5cf1da01d5db3d2557132be8d30f89c38019f6c (#8525)

* Merge from vscode a5cf1da01d5db3d2557132be8d30f89c38019f6c

* remove files we don't want

* fix hygiene

* update distro

* update distro

* fix hygiene

* fix strict nulls

* distro

* distro

* fix tests

* fix tests

* add another edit

* fix viewlet icon

* fix azure dialog

* fix some padding

* fix more padding issues
This commit is contained in:
Anthony Dresser
2019-12-04 19:28:22 -08:00
committed by GitHub
parent a8818ab0df
commit f5ce7fb2a5
1507 changed files with 42813 additions and 27370 deletions

View File

@@ -82,12 +82,16 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance
const QUICKOPEN_HISTORY_LIMIT_CONFIG = 'task.quickOpen.history';
const QUICKOPEN_DETAIL_CONFIG = 'task.quickOpen.detail';
const PROBLEM_MATCHER_NEVER_CONFIG = 'task.problemMatchers.neverPrompt';
const QUICKOPEN_SKIP_CONFIG = 'task.quickOpen.skip';
export namespace ConfigureTaskAction {
export const ID = 'workbench.action.tasks.configureTaskRunner';
export const TEXT = nls.localize('ConfigureTaskRunnerAction.label', "Configure Task");
}
type TaskQuickPickEntryType = (IQuickPickItem & { task: Task; }) | (IQuickPickItem & { folder: IWorkspaceFolder; });
class ProblemReporter implements TaskConfig.IProblemReporter {
private _validationStatus: ValidationStatus;
@@ -184,6 +188,13 @@ interface TaskQuickPickEntry extends IQuickPickItem {
task: Task | undefined | null;
}
interface ProblemMatcherDisableMetrics {
type: string;
}
type ProblemMatcherDisableMetricsClassification = {
type: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
};
export abstract class AbstractTaskService extends Disposable implements ITaskService {
// private static autoDetectTelemetryName: string = 'taskServer.autoDetect';
@@ -286,9 +297,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
this.updateSetup(folderSetup);
this.updateWorkspaceTasks();
}));
this._register(Event.debounce(this.configurationService.onDidChangeConfiguration, () => {
return;
}, 1000)(() => {
this._register(this.configurationService.onDidChangeConfiguration(() => {
if (!this._taskSystem && !this._workspaceTasksPromise) {
return;
}
@@ -690,7 +699,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
});
}
public run(task: Task | undefined, options?: ProblemMatcherRunOptions, runSource: TaskRunSource = TaskRunSource.System): Promise<ITaskSummary> {
public run(task: Task | undefined, options?: ProblemMatcherRunOptions, runSource: TaskRunSource = TaskRunSource.System): Promise<ITaskSummary | undefined> {
if (!task) {
throw new TaskError(Severity.Info, nls.localize('TaskServer.noTask', 'Task to execute is undefined'), TaskErrors.TaskNotFound);
}
@@ -721,14 +730,35 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
private isProvideTasksEnabled(): boolean {
const settingValue = this.configurationService.getValue('task.autoDetect');
return settingValue === true;
return settingValue === 'on';
}
private isProblemMatcherPromptEnabled(type?: string): boolean {
const settingValue = this.configurationService.getValue(PROBLEM_MATCHER_NEVER_CONFIG);
if (Types.isBoolean(settingValue)) {
return !settingValue;
}
if (type === undefined) {
return true;
}
const settingValueMap: IStringDictionary<boolean> = <any>settingValue;
return !settingValueMap[type];
}
private getTypeForTask(task: Task): string {
let type: string;
if (CustomTask.is(task)) {
let configProperties: TaskConfig.ConfigurationProperties = task._source.config.element;
type = (<any>configProperties).type;
} else {
type = task.getDefinition()!.type;
}
return type;
}
private shouldAttachProblemMatcher(task: Task): boolean {
const settingValue = this.configurationService.getValue('task.problemMatchers.neverPrompt');
if (settingValue === true) {
return false;
} else if (task.type && Types.isStringArray(settingValue) && (settingValue.indexOf(task.type) >= 0)) {
const enabled = this.isProblemMatcherPromptEnabled(this.getTypeForTask(task));
if (enabled === false) {
return false;
}
if (!this.canCustomize(task)) {
@@ -745,17 +775,33 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}
if (CustomTask.is(task)) {
let configProperties: TaskConfig.ConfigurationProperties = task._source.config.element;
const type: string = (<any>configProperties).type;
return configProperties.problemMatcher === undefined && !task.hasDefinedMatchers && (Types.isStringArray(settingValue) && (settingValue.indexOf(type) < 0));
return configProperties.problemMatcher === undefined && !task.hasDefinedMatchers;
}
return false;
}
private async updateNeverProblemMatcherSetting(type: string): Promise<void> {
this.telemetryService.publicLog2<ProblemMatcherDisableMetrics, ProblemMatcherDisableMetricsClassification>('problemMatcherDisabled', { type });
const current = this.configurationService.getValue(PROBLEM_MATCHER_NEVER_CONFIG);
if (current === true) {
return;
}
let newValue: IStringDictionary<boolean>;
if (current !== false) {
newValue = <any>current;
} else {
newValue = Object.create(null);
}
newValue[type] = true;
return this.configurationService.updateValue(PROBLEM_MATCHER_NEVER_CONFIG, newValue, ConfigurationTarget.USER);
}
private attachProblemMatcher(task: ContributedTask | CustomTask): Promise<Task | undefined> {
interface ProblemMatcherPickEntry extends IQuickPickItem {
matcher: NamedProblemMatcher | undefined;
never?: boolean;
learnMore?: boolean;
setting?: string;
}
let entries: QuickPickInput<ProblemMatcherPickEntry>[] = [];
for (let key of ProblemMatcherRegistry.keys()) {
@@ -782,14 +828,22 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}
});
entries.unshift({ type: 'separator', label: nls.localize('TaskService.associate', 'associate') });
let taskType: string;
if (CustomTask.is(task)) {
let configProperties: TaskConfig.ConfigurationProperties = task._source.config.element;
taskType = (<any>configProperties).type;
} else {
taskType = task.getDefinition().type;
}
entries.unshift(
{ label: nls.localize('TaskService.attachProblemMatcher.continueWithout', 'Continue without scanning the task output'), matcher: undefined },
{ label: nls.localize('TaskService.attachProblemMatcher.never', 'Never scan the task output'), matcher: undefined, never: true },
{ label: nls.localize('TaskService.attachProblemMatcher.never', 'Never scan the task output for this task'), matcher: undefined, never: true },
{ label: nls.localize('TaskService.attachProblemMatcher.neverType', 'Never scan the task output for {0} tasks', taskType), matcher: undefined, setting: taskType },
{ label: nls.localize('TaskService.attachProblemMatcher.learnMoreAbout', 'Learn more about scanning the task output'), matcher: undefined, learnMore: true }
);
return this.quickInputService.pick(entries, {
placeHolder: nls.localize('selectProblemMatcher', 'Select for which kind of errors and warnings to scan the task output'),
}).then((selected) => {
}).then(async (selected) => {
if (selected) {
if (selected.learnMore) {
this.openDocumentation();
@@ -809,6 +863,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}
this.customize(task, properties, true);
return newTask;
} else if (selected.setting) {
await this.updateNeverProblemMatcherSetting(selected.setting);
return task;
} else {
return task;
}
@@ -1177,7 +1234,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
private executeTask(task: Task, resolver: ITaskResolver): Promise<ITaskSummary> {
return ProblemMatcherRegistry.onReady().then(() => {
return this.textFileService.saveAll().then((value) => { // make sure all dirty files are saved
return this.editorService.saveAll().then((value) => { // make sure all dirty editors are saved
let executeResult = this.getTaskSystem().run(task, resolver);
return this.handleExecuteResult(executeResult);
});
@@ -1286,7 +1343,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
setTimeout(() => {
if (!isDone) {
const settings: IPromptChoice = { label: nls.localize('TaskSystem.slowProvider.settings', "Settings"), run: () => this.preferencesService.openSettings(false, undefined) };
const disableAll: IPromptChoice = { label: nls.localize('TaskSystem.slowProvider.disableAll', "Disable All"), run: () => this.configurationService.updateValue('task.autoDetect', false) };
const disableAll: IPromptChoice = { label: nls.localize('TaskSystem.slowProvider.disableAll', "Disable All"), run: () => this.configurationService.updateValue('task.autoDetect', 'off') };
const dontShow: IPromptChoice = {
label: nls.localize('TaskSystem.slowProvider.dontShow', "Don't warn again for {0} tasks", type), run: () => {
if (!Types.isStringArray(settingValue)) {
@@ -1299,13 +1356,13 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
this.notificationService.prompt(Severity.Warning, nls.localize('TaskSystem.slowProvider', "The {0} task provider is slow. The extension that provides {0} tasks may provide a setting to disable it, or you can disable all tasks providers", type),
[settings, disableAll, dontShow]);
}
}, 2000);
}, 4000);
}
});
}
private getGroupedTasks(type?: string): Promise<TaskMap> {
return Promise.all([this.extensionService.activateByEvent('onCommand:workbench.action.tasks.runTask'), TaskDefinitionRegistry.onReady()]).then(() => {
return Promise.all([this.extensionService.activateByEvent('onCommand:workbench.action.tasks.runTask'), this.extensionService.whenInstalledExtensionsRegistered()]).then(() => {
let validTypes: IStringDictionary<boolean> = Object.create(null);
TaskDefinitionRegistry.all().forEach(definition => validTypes[definition.taskType] = true);
validTypes['shell'] = true;
@@ -1907,7 +1964,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}
for (let task of tasks) {
let entry: TaskQuickPickEntry = TaskQuickPickEntry(task);
entry.buttons = [{ iconClass: 'quick-open-task-configure', tooltip: nls.localize('configureTask', "Configure Task") }];
entry.buttons = [{ iconClass: 'codicon-gear', tooltip: nls.localize('configureTask', "Configure Task") }];
if (selectedEntry && (task === selectedEntry.task)) {
entries.unshift(selectedEntry);
} else {
@@ -1941,7 +1998,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
for (let task of tasks) {
let key = task.getRecentlyUsedKey();
if (!key || !recentlyUsedTasks.has(key)) {
if (task._source.kind === TaskSourceKind.Workspace) {
if ((task._source.kind === TaskSourceKind.Workspace) || (task._source.kind === TaskSourceKind.User)) {
configured.push(task);
} else {
detected.push(task);
@@ -1965,23 +2022,43 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
return entries;
}
private showQuickPick(tasks: Promise<Task[]> | Task[], placeHolder: string, defaultEntry?: TaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry, additionalEntries?: TaskQuickPickEntry[]): Promise<TaskQuickPickEntry | undefined | null> {
let _createEntries = (): Promise<QuickPickInput<TaskQuickPickEntry>[]> => {
private async showQuickPick(tasks: Promise<Task[]> | Task[], placeHolder: string, defaultEntry?: TaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry, additionalEntries?: TaskQuickPickEntry[]): Promise<TaskQuickPickEntry | undefined | null> {
const tokenSource = new CancellationTokenSource();
const cancellationToken: CancellationToken = tokenSource.token;
let _createEntries = new Promise<QuickPickInput<TaskQuickPickEntry>[]>((resolve) => {
if (Array.isArray(tasks)) {
return Promise.resolve(this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry));
resolve(this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry));
} else {
return tasks.then((tasks) => this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry));
resolve(tasks.then((tasks) => this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry)));
}
};
return this.quickInputService.pick(_createEntries().then((entries) => {
if ((entries.length === 0) && defaultEntry) {
});
const timeout: boolean = await Promise.race([new Promise<boolean>(async (resolve) => {
await _createEntries;
resolve(false);
}), new Promise<boolean>((resolve) => {
const timer = setTimeout(() => {
clearTimeout(timer);
resolve(true);
}, 200);
})]);
if (!timeout && ((await _createEntries).length === 1) && this.configurationService.getValue<boolean>(QUICKOPEN_SKIP_CONFIG)) {
return (<TaskQuickPickEntry>(await _createEntries)[0]);
}
const pickEntries = _createEntries.then((entries) => {
if ((entries.length === 1) && this.configurationService.getValue<boolean>(QUICKOPEN_SKIP_CONFIG)) {
tokenSource.cancel();
} else if ((entries.length === 0) && defaultEntry) {
entries.push(defaultEntry);
} else if (entries.length > 1 && additionalEntries && additionalEntries.length > 0) {
entries.push({ type: 'separator', label: '' });
entries.push(additionalEntries[0]);
}
return entries;
}), {
});
return this.quickInputService.pick(pickEntries, {
placeHolder,
matchOnDescription: true,
onDidTriggerItemButton: context => {
@@ -1993,6 +2070,18 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
this.openConfig(task);
}
}
}, cancellationToken).then(async (selection) => {
if (cancellationToken.isCancellationRequested) {
// canceled when there's only one task
const task = (await pickEntries)[0];
if ((<any>task).task) {
selection = <TaskQuickPickEntry>task;
}
}
if (!selection) {
return undefined; //{{SQL CARBON EDIT}} strict-null-check
}
return selection;
});
}
@@ -2075,7 +2164,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}
ProblemMatcherRegistry.onReady().then(() => {
return this.textFileService.saveAll().then((value) => { // make sure all dirty files are saved
return this.editorService.saveAll().then((value) => { // make sure all dirty editors are saved
let executeResult = this.getTaskSystem().rerun();
if (executeResult) {
return this.handleExecuteResult(executeResult);
@@ -2374,8 +2463,33 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
});
}
private isTaskEntry(value: IQuickPickItem): value is IQuickPickItem & { task: Task } {
let candidate: IQuickPickItem & { task: Task } = value as any;
return candidate && !!candidate.task;
}
private runConfigureTasks(): void {
private configureTask(task: Task) {
if (ContributedTask.is(task)) {
this.customize(task, undefined, true);
} else if (CustomTask.is(task)) {
this.openConfig(task);
} else if (ConfiguringTask.is(task)) {
// Do nothing.
}
}
private handleSelection(selection: TaskQuickPickEntryType) {
if (!selection) {
return;
}
if (this.isTaskEntry(selection)) {
this.configureTask(selection.task);
} else {
this.openTaskFile(selection.folder.toResource('.vscode/tasks.json'));
}
}
private async runConfigureTasks(): Promise<void> {
if (!this.canRunCommand()) {
return undefined;
}
@@ -2386,21 +2500,6 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
taskPromise = Promise.resolve(new TaskMap());
}
let configureTask = (task: Task): void => {
if (ContributedTask.is(task)) {
this.customize(task, undefined, true);
} else if (CustomTask.is(task)) {
this.openConfig(task);
} else if (ConfiguringTask.is(task)) {
// Do nothing.
}
};
function isTaskEntry(value: IQuickPickItem): value is IQuickPickItem & { task: Task } {
let candidate: IQuickPickItem & { task: Task } = value as any;
return candidate && !!candidate.task;
}
let stats = this.contextService.getWorkspace().folders.map<Promise<IFileStat | undefined>>((folder) => {
return this.fileService.resolve(folder.toResource('.vscode/tasks.json')).then(stat => stat, () => undefined);
});
@@ -2409,13 +2508,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
let openLabel = nls.localize('TaskService.openJsonFile', 'Open tasks.json file');
const tokenSource = new CancellationTokenSource();
const cancellationToken: CancellationToken = tokenSource.token;
type EntryType = (IQuickPickItem & { task: Task; }) | (IQuickPickItem & { folder: IWorkspaceFolder; });
let entries = Promise.all(stats).then((stats) => {
return taskPromise.then((taskMap) => {
let entries: QuickPickInput<EntryType>[] = [];
let entries: QuickPickInput<TaskQuickPickEntryType>[] = [];
let needsCreateOrOpen: boolean = true;
if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY) {
let tasks = taskMap.all();
let needsCreateOrOpen: boolean = true;
if (tasks.length > 0) {
tasks = tasks.sort((a, b) => a._label.localeCompare(b._label));
for (let task of tasks) {
@@ -2440,7 +2538,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
if (tasks.length > 0) {
tasks = tasks.slice().sort((a, b) => a._label.localeCompare(b._label));
for (let i = 0; i < tasks.length; i++) {
let entry: EntryType = { label: tasks[i]._label, task: tasks[i], description: folder.name };
let entry: TaskQuickPickEntryType = { label: tasks[i]._label, task: tasks[i], description: folder.name };
if (i === 0) {
entries.push({ type: 'separator', label: folder.name });
}
@@ -2448,20 +2546,38 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}
} else {
let label = stats[index] !== undefined ? openLabel : createLabel;
let entry: EntryType = { label, folder: folder };
let entry: TaskQuickPickEntryType = { label, folder: folder };
entries.push({ type: 'separator', label: folder.name });
entries.push(entry);
}
index++;
}
}
if (entries.length === 1) {
if ((entries.length === 1) && !needsCreateOrOpen) {
tokenSource.cancel();
}
return entries;
});
});
const timeout: boolean = await Promise.race([new Promise<boolean>(async (resolve) => {
await entries;
resolve(false);
}), new Promise<boolean>((resolve) => {
const timer = setTimeout(() => {
clearTimeout(timer);
resolve(true);
}, 200);
})]);
if (!timeout && ((await entries).length === 1) && this.configurationService.getValue<boolean>(QUICKOPEN_SKIP_CONFIG)) {
const entry: any = <any>((await entries)[0]);
if (entry.task) {
this.handleSelection(entry);
return;
}
}
this.quickInputService.pick(entries,
{ placeHolder: nls.localize('TaskService.pickTask', 'Select a task to configure') }, cancellationToken).
then(async (selection) => {
@@ -2469,17 +2585,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
// canceled when there's only one task
const task = (await entries)[0];
if ((<any>task).task) {
selection = <EntryType>task;
selection = <TaskQuickPickEntryType>task;
}
}
if (!selection) {
return;
}
if (isTaskEntry(selection)) {
configureTask(selection.task);
} else {
this.openTaskFile(selection.folder.toResource('.vscode/tasks.json'));
}
this.handleSelection(selection);
});
}