From 180356641c5b286be761b1072375bdb9c10f8208 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Sun, 5 Jun 2022 15:29:43 +0200 Subject: [PATCH 01/32] Makes diff editor more reactive. Now, changes to inputs or base are handled gracefully. --- .../contrib/audioCues/browser/observable.ts | 104 +++- .../mergeEditor/browser/mergeEditor.ts | 107 ++-- .../mergeEditor/browser/mergeEditorInput.ts | 22 +- .../mergeEditor/browser/mergeEditorModel.ts | 538 ++++++------------ .../mergeEditor/browser/textModelDiffs.ts | 233 ++++++++ 5 files changed, 569 insertions(+), 435 deletions(-) create mode 100644 src/vs/workbench/contrib/mergeEditor/browser/textModelDiffs.ts diff --git a/src/vs/workbench/contrib/audioCues/browser/observable.ts b/src/vs/workbench/contrib/audioCues/browser/observable.ts index c3974606057..32fe7ccda98 100644 --- a/src/vs/workbench/contrib/audioCues/browser/observable.ts +++ b/src/vs/workbench/contrib/audioCues/browser/observable.ts @@ -3,10 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { BugIndicatingError } from 'vs/base/common/errors'; import { Event } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -export interface IObservable { +export interface IObservable { + _change: TChange; + /** * Reads the current value. * @@ -39,7 +42,7 @@ export interface IReader { * * Is called by `Observable.read`. */ - handleBeforeReadObservable(observable: IObservable): void; + handleBeforeReadObservable(observable: IObservable): void; } export interface IObserver { @@ -61,7 +64,7 @@ export interface IObserver { * Implementations must not call into other observables! * The change should be processed when {@link IObserver.endUpdate} is called. */ - handleChange(observable: IObservable): void; + handleChange(observable: IObservable, change: TChange): void; /** * Indicates that an update operation has completed. @@ -69,8 +72,8 @@ export interface IObserver { endUpdate(observable: IObservable): void; } -export interface ISettable { - set(value: T, transaction: ITransaction | undefined): void; +export interface ISettable { + set(value: T, transaction: ITransaction | undefined, change: TChange): void; } export interface ITransaction { @@ -80,12 +83,14 @@ export interface ITransaction { */ updateObserver( observer: IObserver, - observable: IObservable + observable: IObservable ): void; } // === Base === -export abstract class ConvenientObservable implements IObservable { +export abstract class ConvenientObservable implements IObservable { + get _change(): TChange { return null!; } + public abstract get(): T; public abstract subscribe(observer: IObserver): void; public abstract unsubscribe(observer: IObserver): void; @@ -100,7 +105,7 @@ export abstract class ConvenientObservable implements IObservable { } } -export abstract class BaseObservable extends ConvenientObservable { +export abstract class BaseObservable extends ConvenientObservable { protected readonly observers = new Set(); public subscribe(observer: IObserver): void { @@ -151,9 +156,9 @@ class TransactionImpl implements ITransaction { } } -export class ObservableValue - extends BaseObservable - implements ISettable +export class ObservableValue + extends BaseObservable + implements ISettable { private value: T; @@ -166,14 +171,14 @@ export class ObservableValue return this.value; } - public set(value: T, tx: ITransaction | undefined): void { + public set(value: T, tx: ITransaction | undefined, change: TChange): void { if (this.value === value) { return; } if (!tx) { transaction((tx) => { - this.set(value, tx); + this.set(value, tx, change); }); return; } @@ -182,7 +187,7 @@ export class ObservableValue for (const observer of this.observers) { tx.updateObserver(observer, this); - observer.handleChange(this); + observer.handleChange(this, change); } } } @@ -191,7 +196,7 @@ export function constObservable(value: T): IObservable { return new ConstObservable(value); } -class ConstObservable extends ConvenientObservable { +class ConstObservable extends ConvenientObservable { constructor(private readonly value: T) { super(); } @@ -208,11 +213,28 @@ class ConstObservable extends ConvenientObservable { } // == autorun == -export function autorun( - fn: (reader: IReader) => void, - name: string +export function autorun(fn: (reader: IReader) => void, name: string): IDisposable { + return new AutorunObserver(fn, name, undefined); +} + +interface IChangeContext { + readonly changedObservable: IObservable; + readonly change: unknown; + + didChange(observable: IObservable): this is { change: TChange }; +} + +export function autorunHandleChanges( + name: string, + options: { + /** + * Returns if this change should cause a re-run of the autorun. + */ + handleChange: (context: IChangeContext) => boolean; + }, + fn: (reader: IReader) => void ): IDisposable { - return new AutorunObserver(fn, name); + return new AutorunObserver(fn, name, options.handleChange); } export function autorunWithStore( @@ -252,7 +274,8 @@ export class AutorunObserver implements IObserver, IReader, IDisposable { constructor( private readonly runFn: (reader: IReader) => void, - public readonly name: string + public readonly name: string, + private readonly _handleChange: ((context: IChangeContext) => boolean) | undefined ) { this.runIfNeeded(); } @@ -264,8 +287,13 @@ export class AutorunObserver implements IObserver, IReader, IDisposable { } } - public handleChange() { - this.needsToRun = true; + public handleChange(observable: IObservable, change: TChange): void { + const shouldReact = this._handleChange ? this._handleChange({ + changedObservable: observable, + change, + didChange: o => o === observable as any, + }) : true; + this.needsToRun = this.needsToRun || shouldReact; if (this.updateCount === 0) { this.runIfNeeded(); @@ -337,7 +365,7 @@ export function autorunDelta( export function derivedObservable(name: string, computeFn: (reader: IReader) => T): IObservable { return new LazyDerived(computeFn, name); } -export class LazyDerived extends ConvenientObservable { +export class LazyDerived extends ConvenientObservable { private readonly observer: LazyDerivedObserver; constructor(computeFn: (reader: IReader) => T, name: string) { @@ -366,7 +394,7 @@ export class LazyDerived extends ConvenientObservable { * @internal */ class LazyDerivedObserver - extends BaseObservable + extends BaseObservable implements IReader, IObserver { private hadValue = false; private hasValue = false; @@ -486,9 +514,8 @@ class LazyDerivedObserver this.hasValue = true; if (this.hadValue && oldValue !== this.value) { - // for (const r of this.observers) { - r.handleChange(this); + r.handleChange(this, undefined); } } } @@ -508,6 +535,20 @@ export function observableFromPromise(promise: Promise): IObservable<{ val return observable; } +export function waitForState(observable: IObservable, predicate: (state: T) => state is TState): Promise; +export function waitForState(observable: IObservable, predicate: (state: T) => boolean): Promise; +export function waitForState(observable: IObservable, predicate: (state: T) => boolean): Promise { + return new Promise(resolve => { + const d = autorun(reader => { + const currentState = observable.read(reader); + if (predicate(currentState)) { + d.dispose(); + resolve(currentState); + } + }, 'waitForState'); + }); +} + export function observableFromEvent( event: Event, getValue: (args: TArgs | undefined) => T @@ -540,7 +581,7 @@ class FromEventObservable extends BaseObservable { transaction(tx => { for (const o of this.observers) { tx.updateObserver(o, this); - o.handleChange(this); + o.handleChange(this, undefined); } }); } @@ -622,3 +663,12 @@ export function keepAlive(observable: IObservable): IDisposable { observable.read(reader); }, 'keep-alive'); } + +export function derivedObservableWithCache(name: string, computeFn: (reader: IReader, lastValue: T | undefined) => T): IObservable { + let lastValue: T | undefined = undefined; + const observable = derivedObservable(name, reader => { + lastValue = computeFn(reader, lastValue); + return lastValue; + }); + return observable; +} diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.ts index d90564b396a..992bae6cda7 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.ts @@ -30,6 +30,7 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/tex import { localize } from 'vs/nls'; import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -41,7 +42,7 @@ import { FloatingClickWidget } from 'vs/workbench/browser/codeeditor'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { IEditorControl, IEditorOpenContext } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; -import { autorun, derivedObservable, IObservable, ITransaction, keepAlive, ObservableValue } from 'vs/workbench/contrib/audioCues/browser/observable'; +import { autorun, autorunWithStore, derivedObservable, IObservable, ITransaction, keepAlive, ObservableValue, transaction } from 'vs/workbench/contrib/audioCues/browser/observable'; import { MergeEditorInput } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { MergeEditorModel } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorModel'; import { LineRange, ModifiedBaseRange } from 'vs/workbench/contrib/mergeEditor/browser/model'; @@ -60,8 +61,8 @@ export class MergeEditor extends EditorPane { private _grid!: Grid; - private readonly input1View = this.instantiation.createInstance(InputCodeEditorView, 1, { readonly: true }); - private readonly input2View = this.instantiation.createInstance(InputCodeEditorView, 2, { readonly: true }); + private readonly input1View = this.instantiation.createInstance(InputCodeEditorView, 1, { readonly: !this.inputsWritable }); + private readonly input2View = this.instantiation.createInstance(InputCodeEditorView, 2, { readonly: !this.inputsWritable }); private readonly inputResultView = this.instantiation.createInstance(ResultCodeEditorView, { readonly: false }); private readonly _ctxIsMergeEditor: IContextKey; @@ -70,6 +71,10 @@ export class MergeEditor extends EditorPane { private _model: MergeEditorModel | undefined; public get model(): MergeEditorModel | undefined { return this._model; } + private get inputsWritable(): boolean { + return !!this._configurationService.getValue('mergeEditor.writableInputs'); + } + constructor( @IInstantiationService private readonly instantiation: IInstantiationService, @ILabelService private readonly _labelService: ILabelService, @@ -79,6 +84,7 @@ export class MergeEditor extends EditorPane { @IStorageService storageService: IStorageService, @IThemeService themeService: IThemeService, @ITextResourceConfigurationService private readonly textResourceConfigurationService: ITextResourceConfigurationService, + @IConfigurationService private readonly _configurationService: IConfigurationService, ) { super(MergeEditor.ID, telemetryService, themeService, storageService); @@ -93,7 +99,7 @@ export class MergeEditor extends EditorPane { return undefined; } const resultDiffs = model.resultDiffs.read(reader); - const modifiedBaseRanges = ModifiedBaseRange.fromDiffs(model.base, model.input1, model.input1LinesDiffs, model.result, resultDiffs); + const modifiedBaseRanges = ModifiedBaseRange.fromDiffs(model.base, model.input1, model.input1LinesDiffs.read(reader), model.result, resultDiffs); return modifiedBaseRanges; }); const input2ResultMapping = derivedObservable('input2ResultMapping', reader => { @@ -102,7 +108,7 @@ export class MergeEditor extends EditorPane { return undefined; } const resultDiffs = model.resultDiffs.read(reader); - const modifiedBaseRanges = ModifiedBaseRange.fromDiffs(model.base, model.input2, model.input2LinesDiffs, model.result, resultDiffs); + const modifiedBaseRanges = ModifiedBaseRange.fromDiffs(model.base, model.input2, model.input2LinesDiffs.read(reader), model.result, resultDiffs); return modifiedBaseRanges; }); @@ -227,42 +233,44 @@ export class MergeEditor extends EditorPane { // TODO: Update editor options! - const input1ViewZoneIds: string[] = []; - const input2ViewZoneIds: string[] = []; - for (const m of model.modifiedBaseRanges) { - const max = Math.max(m.input1Range.lineCount, m.input2Range.lineCount, 1); + this._sessionDisposables.add(autorunWithStore((reader, store) => { + const input1ViewZoneIds: string[] = []; + const input2ViewZoneIds: string[] = []; + for (const m of model.modifiedBaseRanges.read(reader)) { + const max = Math.max(m.input1Range.lineCount, m.input2Range.lineCount, 1); - this.input1View.editor.changeViewZones(a => { - input1ViewZoneIds.push(a.addZone({ - afterLineNumber: m.input1Range.endLineNumberExclusive - 1, - heightInLines: max - m.input1Range.lineCount, - domNode: $('div.diagonal-fill'), - })); - }); - - this.input2View.editor.changeViewZones(a => { - input2ViewZoneIds.push(a.addZone({ - afterLineNumber: m.input2Range.endLineNumberExclusive - 1, - heightInLines: max - m.input2Range.lineCount, - domNode: $('div.diagonal-fill'), - })); - }); - } - - this._sessionDisposables.add({ - dispose: () => { this.input1View.editor.changeViewZones(a => { - for (const zone of input1ViewZoneIds) { - a.removeZone(zone); - } + input1ViewZoneIds.push(a.addZone({ + afterLineNumber: m.input1Range.endLineNumberExclusive - 1, + heightInLines: max - m.input1Range.lineCount, + domNode: $('div.diagonal-fill'), + })); }); + this.input2View.editor.changeViewZones(a => { - for (const zone of input2ViewZoneIds) { - a.removeZone(zone); - } + input2ViewZoneIds.push(a.addZone({ + afterLineNumber: m.input2Range.endLineNumberExclusive - 1, + heightInLines: max - m.input2Range.lineCount, + domNode: $('div.diagonal-fill'), + })); }); } - }); + + store.add({ + dispose: () => { + this.input1View.editor.changeViewZones(a => { + for (const zone of input1ViewZoneIds) { + a.removeZone(zone); + } + }); + this.input2View.editor.changeViewZones(a => { + for (const zone of input2ViewZoneIds) { + a.removeZone(zone); + } + }); + } + }); + }, 'update alignment view zones')); } protected override setEditorVisible(visible: boolean): void { @@ -448,7 +456,7 @@ class InputCodeEditorView extends CodeEditorView { return []; } const result = new Array(); - for (const m of model.modifiedBaseRanges) { + for (const m of model.modifiedBaseRanges.read(reader)) { const range = m.getInputRange(this.inputNumber); if (!range.isEmpty) { result.push({ @@ -478,13 +486,14 @@ class InputCodeEditorView extends CodeEditorView { getIntersectingGutterItems: (range, reader) => { const model = this.model.read(reader); if (!model) { return []; } - return model.modifiedBaseRanges + return model.modifiedBaseRanges.read(reader) .filter((r) => r.getInputDiffs(this.inputNumber).length > 0) .map((baseRange, idx) => ({ id: idx.toString(), additionalHeightInPx: 0, offsetInPx: 0, range: baseRange.getInputRange(this.inputNumber), + enabled: model.isUpToDate, toggleState: derivedObservable('toggle', (reader) => model .getState(baseRange) @@ -510,14 +519,19 @@ class InputCodeEditorView extends CodeEditorView { } interface ModifiedBaseRangeGutterItemInfo extends IGutterItemInfo { + enabled: IObservable; toggleState: IObservable; - setState(value: boolean, tx: ITransaction | undefined): void; + setState(value: boolean, tx: ITransaction): void; } class MergeConflictGutterItemView extends Disposable implements IGutterItemView { - constructor(private item: ModifiedBaseRangeGutterItemInfo, private readonly target: HTMLElement) { + private readonly item = new ObservableValue(undefined, 'item'); + + constructor(item: ModifiedBaseRangeGutterItemInfo, private readonly target: HTMLElement) { super(); + this.item.set(item, undefined); + target.classList.add('merge-accept-gutter-marker'); // TODO: localized title @@ -526,7 +540,8 @@ class MergeConflictGutterItemView extends Disposable implements IGutterItemView< this._register( autorun((reader) => { - const value = this.item.toggleState.read(reader); + const item = this.item.read(reader)!; + const value = item.toggleState.read(reader); checkBox.setIcon( value === true ? Codicon.check @@ -535,11 +550,19 @@ class MergeConflictGutterItemView extends Disposable implements IGutterItemView< : Codicon.circleFilled ); checkBox.checked = value === true; + + if (!item.enabled.read(reader)) { + checkBox.disable(); + } else { + checkBox.enable(); + } }, 'Update Toggle State') ); this._register(checkBox.onChange(() => { - this.item.setState(checkBox.checked, undefined); + transaction(tx => { + this.item.get()!.setState(checkBox.checked, tx); + }); })); target.appendChild(n('div.background', [noBreakWhitespace]).root); @@ -555,7 +578,7 @@ class MergeConflictGutterItemView extends Disposable implements IGutterItemView< } update(baseRange: ModifiedBaseRangeGutterItemInfo): void { - this.item = baseRange; + this.item.set(baseRange, undefined); } } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts index f6b69488351..efa8b0360e0 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts @@ -14,7 +14,7 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { IUntypedEditorInput, EditorInputCapabilities } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { AbstractTextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput'; -import { MergeEditorModel, MergeEditorModelFactory } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorModel'; +import { MergeEditorModel } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorModel'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITextFileEditorModel, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -39,10 +39,9 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput { private _model?: MergeEditorModel; private _outTextModel?: ITextFileEditorModel; - private readonly mergeEditorModelFactory = this._instaService.createInstance(MergeEditorModelFactory); constructor( - private readonly _anchestor: URI, + private readonly _base: URI, private readonly _input1: MergeEditorInputData, private readonly _input2: MergeEditorInputData, private readonly _result: URI, @@ -101,13 +100,14 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput { if (!this._model) { - const anchestor = await this._textModelService.createModelReference(this._anchestor); + const base = await this._textModelService.createModelReference(this._base); const input1 = await this._textModelService.createModelReference(this._input1.uri); const input2 = await this._textModelService.createModelReference(this._input2.uri); const result = await this._textModelService.createModelReference(this._result); - this._model = await this.mergeEditorModelFactory.create( - anchestor.object.textEditorModel, + this._model = this._instaService.createInstance( + MergeEditorModel, + base.object.textEditorModel, input1.object.textEditorModel, this._input1.detail, this._input1.description, @@ -117,13 +117,13 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput { result.object.textEditorModel ); + await this._model.onInitialized; + this._store.add(this._model); - this._store.add(anchestor); + this._store.add(base); this._store.add(input1); this._store.add(input2); this._store.add(result); - - // result.object. } return this._model; } @@ -132,7 +132,7 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput { if (!(otherInput instanceof MergeEditorInput)) { return false; } - return isEqual(this._anchestor, otherInput._anchestor) + return isEqual(this._base, otherInput._base) && isEqual(this._input1.uri, otherInput._input1.uri) && isEqual(this._input2.uri, otherInput._input2.uri) && isEqual(this._result, otherInput._result); @@ -140,7 +140,7 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput { toJSON(): MergeEditorInputJSON { return { - anchestor: this._anchestor, + anchestor: this._base, inputOne: this._input1, inputTwo: this._input2, result: this._result, diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorModel.ts index 9e32d53e6cc..0d1907a4eb9 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorModel.ts @@ -3,96 +3,72 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Emitter } from 'vs/base/common/event'; -import { compareBy, CompareResult, equals, numberComparator } from 'vs/base/common/arrays'; +import { compareBy, CompareResult, equals } from 'vs/base/common/arrays'; import { BugIndicatingError } from 'vs/base/common/errors'; import { ITextModel } from 'vs/editor/common/model'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; import { EditorModel } from 'vs/workbench/common/editor/editorModel'; -import { IObservable, ITransaction, ObservableValue, transaction } from 'vs/workbench/contrib/audioCues/browser/observable'; -import { ModifiedBaseRange, LineEdit, LineDiff, ModifiedBaseRangeState, LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model'; -import { leftJoin, ReentrancyBarrier } from 'vs/workbench/contrib/mergeEditor/browser/utils'; +import { autorunHandleChanges, derivedObservable, derivedObservableWithCache, IObservable, ITransaction, keepAlive, ObservableValue, transaction, waitForState } from 'vs/workbench/contrib/audioCues/browser/observable'; +import { LineDiff, LineEdit, LineRange, ModifiedBaseRange, ModifiedBaseRangeState } from 'vs/workbench/contrib/mergeEditor/browser/model'; +import { EditorWorkerServiceDiffComputer, TextModelDiffChangeReason, TextModelDiffs, TextModelDiffState } from 'vs/workbench/contrib/mergeEditor/browser/textModelDiffs'; +import { leftJoin } from 'vs/workbench/contrib/mergeEditor/browser/utils'; -export class MergeEditorModelFactory { - constructor( - @IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService - ) { - } - - public async create( - base: ITextModel, - input1: ITextModel, - input1Detail: string | undefined, - input1Description: string | undefined, - input2: ITextModel, - input2Detail: string | undefined, - input2Description: string | undefined, - result: ITextModel, - ): Promise { - - const baseToInput1DiffPromise = this._editorWorkerService.computeDiff( - base.uri, - input1.uri, - false, - 1000 - ); - const baseToInput2DiffPromise = this._editorWorkerService.computeDiff( - base.uri, - input2.uri, - false, - 1000 - ); - const baseToResultDiffPromise = this._editorWorkerService.computeDiff( - base.uri, - result.uri, - false, - 1000 - ); - - const [baseToInput1Diff, baseToInput2Diff, baseToResultDiff] = await Promise.all([ - baseToInput1DiffPromise, - baseToInput2DiffPromise, - baseToResultDiffPromise - ]); - - const changesInput1 = - baseToInput1Diff?.changes.map((c) => - LineDiff.fromLineChange(c, base, input1) - ) || []; - const changesInput2 = - baseToInput2Diff?.changes.map((c) => - LineDiff.fromLineChange(c, base, input2) - ) || []; - const changesResult = - baseToResultDiff?.changes.map((c) => - LineDiff.fromLineChange(c, base, result) - ) || []; - - return new MergeEditorModel( - InternalSymbol, - base, - input1, - input1Detail, - input1Description, - input2, - input2Detail, - input2Description, - result, - changesInput1, - changesInput2, - changesResult, - this._editorWorkerService, - ); - } +export const enum MergeEditorModelState { + initializing = 1, + upToDate = 2, + updating = 3, } -const InternalSymbol: unique symbol = null!; - export class MergeEditorModel extends EditorModel { - private resultEdits: ResultEdits; + private readonly diffComputer = new EditorWorkerServiceDiffComputer(this.editorWorkerService); + private readonly input1TextModelDiffs = new TextModelDiffs(this.base, this.input1, this.diffComputer); + private readonly input2TextModelDiffs = new TextModelDiffs(this.base, this.input2, this.diffComputer); + private readonly resultTextModelDiffs = new TextModelDiffs(this.base, this.result, this.diffComputer); + + public readonly state = derivedObservable('state', reader => { + const states = [ + this.input1TextModelDiffs, + this.input2TextModelDiffs, + this.resultTextModelDiffs, + ].map((s) => s.state.read(reader)); + + if (states.some((s) => s === TextModelDiffState.initializing)) { + return MergeEditorModelState.initializing; + } + if (states.some((s) => s === TextModelDiffState.updating)) { + return MergeEditorModelState.updating; + } + return MergeEditorModelState.upToDate; + }); + + public readonly isUpToDate = derivedObservable('isUpdating', reader => this.state.read(reader) === MergeEditorModelState.upToDate); + + public readonly onInitialized = waitForState(this.state, state => state === MergeEditorModelState.upToDate); + + public readonly modifiedBaseRanges = derivedObservableWithCache('modifiedBaseRanges', (reader, lastValue) => { + if (this.state.read(reader) !== MergeEditorModelState.upToDate) { + return lastValue || []; + } + + const input1Diffs = this.input1TextModelDiffs.diffs.read(reader); + const input2Diffs = this.input2TextModelDiffs.diffs.read(reader); + + return ModifiedBaseRange.fromDiffs(this.base, this.input1, input1Diffs, this.input2, input2Diffs); + }); + + public readonly input1LinesDiffs = this.input1TextModelDiffs.diffs; + public readonly input2LinesDiffs = this.input2TextModelDiffs.diffs; + public readonly resultDiffs = this.resultTextModelDiffs.diffs; + + private readonly modifiedBaseRangeStateStores = + derivedObservable('modifiedBaseRangeStateStores', reader => { + const map = new Map( + this.modifiedBaseRanges.read(reader).map(s => ([s, new ObservableValue(ModifiedBaseRangeState.default, 'State')])) + ); + return map; + }); constructor( - _symbol: typeof InternalSymbol, readonly base: ITextModel, readonly input1: ITextModel, readonly input1Detail: string | undefined, @@ -101,27 +77,43 @@ export class MergeEditorModel extends EditorModel { readonly input2Detail: string | undefined, readonly input2Description: string | undefined, readonly result: ITextModel, - public readonly input1LinesDiffs: readonly LineDiff[], - public readonly input2LinesDiffs: readonly LineDiff[], - resultDiffs: LineDiff[], - private readonly editorWorkerService: IEditorWorkerService + @IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService ) { super(); - this.resultEdits = new ResultEdits(resultDiffs, this.base, this.result, this.editorWorkerService); - this.resultEdits.onDidChange(() => { - this.recomputeState(); - }); - this.recomputeState(); + this._register(keepAlive(this.modifiedBaseRangeStateStores)); - this.resetUnknown(); + this._register( + autorunHandleChanges( + 'Recompute State', + { + handleChange: (ctx) => + ctx.didChange(this.resultTextModelDiffs.diffs) + // Ignore non-text changes as we update the state directly + ? ctx.change === TextModelDiffChangeReason.textChange + : true, + }, + (reader) => { + if (!this.isUpToDate.read(reader)) { + return; + } + const resultDiffs = this.resultTextModelDiffs.diffs.read(reader); + const stores = this.modifiedBaseRangeStateStores.read(reader); + this.recomputeState(resultDiffs, stores); + } + ) + ); + + this.onInitialized.then(() => { + this.resetUnknown(); + }); } - private recomputeState(): void { + private recomputeState(resultDiffs: LineDiff[], stores: Map>): void { transaction(tx => { const baseRangeWithStoreAndTouchingDiffs = leftJoin( - this.modifiedBaseRangeStateStores, - this.resultEdits.diffs.get(), + stores, + resultDiffs, (baseRange, diff) => baseRange[0].baseRange.touches(diff.originalRange) ? CompareResult.neitherLessOrGreaterThan @@ -132,14 +124,14 @@ export class MergeEditorModel extends EditorModel { ); for (const row of baseRangeWithStoreAndTouchingDiffs) { - row.left[1].set(this.computeState(row.left[0], row.rights), tx); + row.left[1].set(computeState(row.left[0], row.rights), tx); } }); } public resetUnknown(): void { transaction(tx => { - for (const range of this.modifiedBaseRanges) { + for (const range of this.modifiedBaseRanges.get()) { if (this.getState(range).get().conflicting) { this.setState(range, ModifiedBaseRangeState.default, tx); } @@ -149,7 +141,7 @@ export class MergeEditorModel extends EditorModel { public mergeNonConflictingDiffs(): void { transaction((tx) => { - for (const m of this.modifiedBaseRanges) { + for (const m of this.modifiedBaseRanges.get()) { if (m.isConflicting) { continue; } @@ -164,54 +156,8 @@ export class MergeEditorModel extends EditorModel { }); } - public get resultDiffs(): IObservable { - return this.resultEdits.diffs; - } - - public readonly modifiedBaseRanges = ModifiedBaseRange.fromDiffs( - this.base, - this.input1, - this.input1LinesDiffs, - this.input2, - this.input2LinesDiffs - ); - - private readonly modifiedBaseRangeStateStores: ReadonlyMap> = new Map( - this.modifiedBaseRanges.map(s => ([s, new ObservableValue(ModifiedBaseRangeState.default, 'State')])) - ); - - private computeState(baseRange: ModifiedBaseRange, conflictingDiffs?: LineDiff[]): ModifiedBaseRangeState { - if (!conflictingDiffs) { - conflictingDiffs = this.resultEdits.findTouchingDiffs( - baseRange.baseRange - ); - } - - if (conflictingDiffs.length === 0) { - return ModifiedBaseRangeState.default; - } - const conflictingEdits = conflictingDiffs.map((d) => d.getLineEdit()); - - function editsAgreeWithDiffs(diffs: readonly LineDiff[]): boolean { - return equals( - conflictingEdits, - diffs.map((d) => d.getLineEdit()), - (a, b) => a.equals(b) - ); - } - - if (editsAgreeWithDiffs(baseRange.input1Diffs)) { - return ModifiedBaseRangeState.default.withInput1(true); - } - if (editsAgreeWithDiffs(baseRange.input2Diffs)) { - return ModifiedBaseRangeState.default.withInput2(true); - } - - return ModifiedBaseRangeState.conflicting; - } - public getState(baseRange: ModifiedBaseRange): IObservable { - const existingState = this.modifiedBaseRangeStateStores.get(baseRange); + const existingState = this.modifiedBaseRangeStateStores.get().get(baseRange); if (!existingState) { throw new BugIndicatingError('object must be from this instance'); } @@ -221,240 +167,122 @@ export class MergeEditorModel extends EditorModel { public setState( baseRange: ModifiedBaseRange, state: ModifiedBaseRangeState, - transaction: ITransaction | undefined + transaction: ITransaction ): void { - const existingState = this.modifiedBaseRangeStateStores.get(baseRange); + if (!this.isUpToDate.get()) { + throw new BugIndicatingError('Cannot set state while updating'); + } + + const existingState = this.modifiedBaseRangeStateStores.get().get(baseRange); if (!existingState) { throw new BugIndicatingError('object must be from this instance'); } - - const conflictingDiffs = this.resultEdits.findTouchingDiffs( + const conflictingDiffs = this.resultTextModelDiffs.findTouchingDiffs( baseRange.baseRange ); if (conflictingDiffs) { - this.resultEdits.removeDiffs(conflictingDiffs, transaction); + this.resultTextModelDiffs.removeDiffs(conflictingDiffs, transaction); } - function getEdit(baseRange: ModifiedBaseRange, state: ModifiedBaseRangeState): { edit: LineEdit | undefined; effectiveState: ModifiedBaseRangeState } { - interface LineDiffWithInputNumber { - diff: LineDiff; - inputNumber: 1 | 2; - } - - const diffs = new Array(); - if (state.input1) { - if (baseRange.input1CombinedDiff) { - diffs.push({ diff: baseRange.input1CombinedDiff, inputNumber: 1 }); - } - } - if (state.input2) { - if (baseRange.input2CombinedDiff) { - diffs.push({ diff: baseRange.input2CombinedDiff, inputNumber: 2 }); - } - } - if (state.input2First) { - diffs.reverse(); - } - const firstDiff: LineDiffWithInputNumber | undefined = diffs[0]; - const secondDiff: LineDiffWithInputNumber | undefined = diffs[1]; - diffs.sort(compareBy(d => d.diff.originalRange, LineRange.compareByStart)); - - if (!firstDiff) { - return { edit: undefined, effectiveState: state }; - } - - if (!secondDiff) { - return { edit: firstDiff.diff.getLineEdit(), effectiveState: state }; - } - - // Two inserts - if ( - firstDiff.diff.originalRange.lineCount === 0 && - firstDiff.diff.originalRange.equals(secondDiff.diff.originalRange) - ) { - return { - edit: new LineEdit( - firstDiff.diff.originalRange, - firstDiff.diff - .getLineEdit() - .newLines.concat(secondDiff.diff.getLineEdit().newLines) - ), - effectiveState: state, - }; - } - - // Technically non-conflicting diffs - if (diffs.length === 2 && diffs[0].diff.originalRange.endLineNumberExclusive === diffs[1].diff.originalRange.startLineNumber) { - return { - edit: new LineEdit( - LineRange.join(diffs.map(d => d.diff.originalRange))!, - diffs.flatMap(d => d.diff.getLineEdit().newLines) - ), - effectiveState: state, - }; - } - - return { edit: firstDiff.diff.getLineEdit(), effectiveState: state }; - } - const { edit, effectiveState } = getEdit(baseRange, state); + const { edit, effectiveState } = getEditForBase(baseRange, state); existingState.set(effectiveState, transaction); if (edit) { - this.resultEdits.applyEditRelativeToOriginal(edit, transaction); + this.resultTextModelDiffs.applyEditRelativeToOriginal(edit, transaction); } } - - public getResultRange(baseRange: LineRange): LineRange { - return this.resultEdits.getResultRange(baseRange); - } } -class ResultEdits { - private readonly barrier = new ReentrancyBarrier(); - private readonly onDidChangeEmitter = new Emitter(); - public readonly onDidChange = this.onDidChangeEmitter.event; +function getEditForBase(baseRange: ModifiedBaseRange, state: ModifiedBaseRangeState): { edit: LineEdit | undefined; effectiveState: ModifiedBaseRangeState } { + interface LineDiffWithInputNumber { + diff: LineDiff; + inputNumber: 1 | 2; + } - constructor( - diffs: LineDiff[], - private readonly baseTextModel: ITextModel, - private readonly resultTextModel: ITextModel, - private readonly _editorWorkerService: IEditorWorkerService + const diffs = new Array(); + if (state.input1) { + if (baseRange.input1CombinedDiff) { + diffs.push({ diff: baseRange.input1CombinedDiff, inputNumber: 1 }); + } + } + if (state.input2) { + if (baseRange.input2CombinedDiff) { + diffs.push({ diff: baseRange.input2CombinedDiff, inputNumber: 2 }); + } + } + if (state.input2First) { + diffs.reverse(); + } + const firstDiff: LineDiffWithInputNumber | undefined = diffs[0]; + const secondDiff: LineDiffWithInputNumber | undefined = diffs[1]; + diffs.sort(compareBy(d => d.diff.originalRange, LineRange.compareByStart)); + + if (!firstDiff) { + return { edit: undefined, effectiveState: ModifiedBaseRangeState.default }; + } + + if (!secondDiff) { + return { edit: firstDiff.diff.getLineEdit(), effectiveState: ModifiedBaseRangeState.default.withInputValue(firstDiff.inputNumber, true) }; + } + + // Two inserts + if ( + firstDiff.diff.originalRange.lineCount === 0 && + firstDiff.diff.originalRange.equals(secondDiff.diff.originalRange) ) { - diffs.sort(compareBy((d) => d.originalRange.startLineNumber, numberComparator)); - this._diffs.set(diffs, undefined); - - resultTextModel.onDidChangeContent(e => { - this.barrier.runExclusively(() => { - this._editorWorkerService.computeDiff( - baseTextModel.uri, - resultTextModel.uri, - false, - 1000 - ).then(e => { - const diffs = - e?.changes.map((c) => - LineDiff.fromLineChange(c, baseTextModel, resultTextModel) - ) || []; - this._diffs.set(diffs, undefined); - - this.onDidChangeEmitter.fire(undefined); - }); - }); - }); + return { + edit: new LineEdit( + firstDiff.diff.originalRange, + firstDiff.diff + .getLineEdit() + .newLines.concat(secondDiff.diff.getLineEdit().newLines) + ), + effectiveState: state, + }; } - private readonly _diffs = new ObservableValue([], 'diffs'); - - public readonly diffs: IObservable = this._diffs; - - public removeDiffs(diffToRemoves: LineDiff[], transaction: ITransaction | undefined): void { - diffToRemoves.sort(compareBy((d) => d.originalRange.startLineNumber, numberComparator)); - diffToRemoves.reverse(); - - let diffs = this._diffs.get(); - - for (const diffToRemove of diffToRemoves) { - // TODO improve performance - const len = diffs.length; - diffs = diffs.filter((d) => d !== diffToRemove); - if (len === diffs.length) { - throw new BugIndicatingError(); - } - - this.barrier.runExclusivelyOrThrow(() => { - diffToRemove.getReverseLineEdit().apply(this.resultTextModel); - }); - - diffs = diffs.map((d) => - d.modifiedRange.isAfter(diffToRemove.modifiedRange) - ? new LineDiff( - d.originalTextModel, - d.originalRange, - d.modifiedTextModel, - d.modifiedRange.delta( - diffToRemove.originalRange.lineCount - diffToRemove.modifiedRange.lineCount - ) - ) - : d - ); - } - - this._diffs.set(diffs, transaction); + // Technically non-conflicting diffs + if (diffs.length === 2 && diffs[0].diff.originalRange.endLineNumberExclusive === diffs[1].diff.originalRange.startLineNumber) { + return { + edit: new LineEdit( + LineRange.join(diffs.map(d => d.diff.originalRange))!, + diffs.flatMap(d => d.diff.getLineEdit().newLines) + ), + effectiveState: state, + }; } - /** - * Edit must be conflict free. - */ - public applyEditRelativeToOriginal(edit: LineEdit, transaction: ITransaction | undefined): void { - let firstAfter = false; - let delta = 0; - const newDiffs = new Array(); - for (const diff of this._diffs.get()) { - if (diff.originalRange.touches(edit.range)) { - throw new BugIndicatingError('Edit must be conflict free.'); - } else if (diff.originalRange.isAfter(edit.range)) { - if (!firstAfter) { - firstAfter = true; - - newDiffs.push(new LineDiff( - this.baseTextModel, - edit.range, - this.resultTextModel, - new LineRange(edit.range.startLineNumber + delta, edit.newLines.length) - )); - } - - newDiffs.push(new LineDiff( - diff.originalTextModel, - diff.originalRange, - diff.modifiedTextModel, - diff.modifiedRange.delta(edit.newLines.length - edit.range.lineCount) - )); - } else { - newDiffs.push(diff); - } - - if (!firstAfter) { - delta += diff.modifiedRange.lineCount - diff.originalRange.lineCount; - } - } - - if (!firstAfter) { - firstAfter = true; - - newDiffs.push(new LineDiff( - this.baseTextModel, - edit.range, - this.resultTextModel, - new LineRange(edit.range.startLineNumber + delta, edit.newLines.length) - )); - } - - this.barrier.runExclusivelyOrThrow(() => { - new LineEdit(edit.range.delta(delta), edit.newLines).apply(this.resultTextModel); - }); - this._diffs.set(newDiffs, transaction); - } - - public findTouchingDiffs(baseRange: LineRange): LineDiff[] { - return this.diffs.get().filter(d => d.originalRange.touches(baseRange)); - } - - public getResultRange(baseRange: LineRange): LineRange { - let startOffset = 0; - let lengthOffset = 0; - for (const diff of this.diffs.get()) { - if (diff.originalRange.endLineNumberExclusive <= baseRange.startLineNumber) { - startOffset += diff.resultingDeltaFromOriginalToModified; - } else if (diff.originalRange.startLineNumber <= baseRange.endLineNumberExclusive) { - lengthOffset += diff.resultingDeltaFromOriginalToModified; - } else { - break; - } - } - - return new LineRange(baseRange.startLineNumber + startOffset, baseRange.lineCount + lengthOffset); - } + return { + edit: secondDiff.diff.getLineEdit(), + effectiveState: ModifiedBaseRangeState.default.withInputValue( + secondDiff.inputNumber, + true + ), + }; +} + +function computeState(baseRange: ModifiedBaseRange, conflictingDiffs: LineDiff[]): ModifiedBaseRangeState { + if (conflictingDiffs.length === 0) { + return ModifiedBaseRangeState.default; + } + const conflictingEdits = conflictingDiffs.map((d) => d.getLineEdit()); + + function editsAgreeWithDiffs(diffs: readonly LineDiff[]): boolean { + return equals( + conflictingEdits, + diffs.map((d) => d.getLineEdit()), + (a, b) => a.equals(b) + ); + } + + if (editsAgreeWithDiffs(baseRange.input1Diffs)) { + return ModifiedBaseRangeState.default.withInput1(true); + } + if (editsAgreeWithDiffs(baseRange.input2Diffs)) { + return ModifiedBaseRangeState.default.withInput2(true); + } + + return ModifiedBaseRangeState.conflicting; } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/textModelDiffs.ts b/src/vs/workbench/contrib/mergeEditor/browser/textModelDiffs.ts new file mode 100644 index 00000000000..348aabaef38 --- /dev/null +++ b/src/vs/workbench/contrib/mergeEditor/browser/textModelDiffs.ts @@ -0,0 +1,233 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { compareBy, numberComparator } from 'vs/base/common/arrays'; +import { BugIndicatingError } from 'vs/base/common/errors'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { ITextModel } from 'vs/editor/common/model'; +import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; +import { IObservable, ITransaction, ObservableValue, transaction } from 'vs/workbench/contrib/audioCues/browser/observable'; +import { LineDiff, LineEdit, LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model'; +import { ReentrancyBarrier } from 'vs/workbench/contrib/mergeEditor/browser/utils'; + +export class TextModelDiffs extends Disposable { + private updateCount = 0; + private readonly _state = new ObservableValue(TextModelDiffState.initializing, 'LiveDiffState'); + private readonly _diffs = new ObservableValue([], 'LiveDiffs'); + + private readonly barrier = new ReentrancyBarrier(); + + constructor( + private readonly baseTextModel: ITextModel, + private readonly textModel: ITextModel, + private readonly diffComputer: IDiffComputer, + ) { + super(); + + this.update(true); + this._register(baseTextModel.onDidChangeContent(this.barrier.makeExclusive(() => this.update()))); + this._register(textModel.onDidChangeContent(this.barrier.makeExclusive(() => this.update()))); + } + + public get state(): IObservable { + return this._state; + } + + public get diffs(): IObservable { + return this._diffs; + } + + private async update(initializing: boolean = false): Promise { + this.updateCount++; + const currentUpdateCount = this.updateCount; + + if (this._state.get() === TextModelDiffState.initializing) { + initializing = true; + } + + transaction(tx => { + this._state.set( + initializing ? TextModelDiffState.initializing : TextModelDiffState.updating, + tx, + TextModelDiffChangeReason.other + ); + }); + + const result = await this.diffComputer.computeDiff(this.baseTextModel, this.textModel); + + if (currentUpdateCount !== this.updateCount) { + // There is a newer update call + return; + } + + transaction(tx => { + if (result) { + this._state.set(TextModelDiffState.upToDate, tx, TextModelDiffChangeReason.textChange); + this._diffs.set(result, tx, TextModelDiffChangeReason.textChange); + } else { + this._state.set(TextModelDiffState.error, tx, TextModelDiffChangeReason.textChange); + } + }); + } + + private ensureUpToDate(): void { + if (this.state.get() !== TextModelDiffState.upToDate) { + throw new BugIndicatingError('Cannot remove diffs when the model is not up to date'); + } + } + + public removeDiffs(diffToRemoves: LineDiff[], transaction: ITransaction | undefined): void { + this.ensureUpToDate(); + + diffToRemoves.sort(compareBy((d) => d.originalRange.startLineNumber, numberComparator)); + diffToRemoves.reverse(); + + let diffs = this._diffs.get(); + + for (const diffToRemove of diffToRemoves) { + // TODO improve performance + const len = diffs.length; + diffs = diffs.filter((d) => d !== diffToRemove); + if (len === diffs.length) { + throw new BugIndicatingError(); + } + + this.barrier.runExclusivelyOrThrow(() => { + diffToRemove.getReverseLineEdit().apply(this.textModel); + }); + + diffs = diffs.map((d) => + d.modifiedRange.isAfter(diffToRemove.modifiedRange) + ? new LineDiff( + d.originalTextModel, + d.originalRange, + d.modifiedTextModel, + d.modifiedRange.delta( + diffToRemove.originalRange.lineCount - diffToRemove.modifiedRange.lineCount + ) + ) + : d + ); + } + + this._diffs.set(diffs, transaction, TextModelDiffChangeReason.other); + } + + /** + * Edit must be conflict free. + */ + public applyEditRelativeToOriginal(edit: LineEdit, transaction: ITransaction | undefined): void { + this.ensureUpToDate(); + + let firstAfter = false; + let delta = 0; + const newDiffs = new Array(); + for (const diff of this.diffs.get()) { + if (diff.originalRange.touches(edit.range)) { + throw new BugIndicatingError('Edit must be conflict free.'); + } else if (diff.originalRange.isAfter(edit.range)) { + if (!firstAfter) { + firstAfter = true; + + newDiffs.push(new LineDiff( + this.baseTextModel, + edit.range, + this.textModel, + new LineRange(edit.range.startLineNumber + delta, edit.newLines.length) + )); + } + + newDiffs.push(new LineDiff( + diff.originalTextModel, + diff.originalRange, + diff.modifiedTextModel, + diff.modifiedRange.delta(edit.newLines.length - edit.range.lineCount) + )); + } else { + newDiffs.push(diff); + } + + if (!firstAfter) { + delta += diff.modifiedRange.lineCount - diff.originalRange.lineCount; + } + } + + if (!firstAfter) { + firstAfter = true; + + newDiffs.push(new LineDiff( + this.baseTextModel, + edit.range, + this.textModel, + new LineRange(edit.range.startLineNumber + delta, edit.newLines.length) + )); + } + + this.barrier.runExclusivelyOrThrow(() => { + new LineEdit(edit.range.delta(delta), edit.newLines).apply(this.textModel); + }); + this._diffs.set(newDiffs, transaction, TextModelDiffChangeReason.other); + } + + public findTouchingDiffs(baseRange: LineRange): LineDiff[] { + return this.diffs.get().filter(d => d.originalRange.touches(baseRange)); + } + + /* + public getResultRange(baseRange: LineRange): LineRange { + let startOffset = 0; + let lengthOffset = 0; + for (const diff of this.diffs.get()) { + if (diff.originalRange.endLineNumberExclusive <= baseRange.startLineNumber) { + startOffset += diff.resultingDeltaFromOriginalToModified; + } else if (diff.originalRange.startLineNumber <= baseRange.endLineNumberExclusive) { + lengthOffset += diff.resultingDeltaFromOriginalToModified; + } else { + break; + } + } + + return new LineRange(baseRange.startLineNumber + startOffset, baseRange.lineCount + lengthOffset); + } + */ +} + +export const enum TextModelDiffChangeReason { + other = 0, + textChange = 1, +} + +export const enum TextModelDiffState { + initializing = 1, + upToDate = 2, + updating = 3, + error = 4, +} + +export interface ITextModelDiffsState { + state: TextModelDiffState; + diffs: LineDiff[]; +} + +export interface IDiffComputer { + computeDiff(textModel1: ITextModel, textModel2: ITextModel): Promise; +} + +export class EditorWorkerServiceDiffComputer implements IDiffComputer { + constructor(@IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService) { } + + async computeDiff(textModel1: ITextModel, textModel2: ITextModel): Promise { + //await wait(1000); + const diffs = await this.editorWorkerService.computeDiff(textModel1.uri, textModel2.uri, false, 1000); + if (!diffs || diffs.quitEarly) { + return null; + } + return diffs.changes.map((c) => LineDiff.fromLineChange(c, textModel1, textModel2)); + } +} + +function wait(ms: number): Promise { + return new Promise(r => setTimeout(r, ms)); +} From e43875b2ade2b9e4edfb378875d5bb72a01bb592 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 8 Jun 2022 10:31:06 -0700 Subject: [PATCH 02/32] added refactor preview in command palette, refactor works as usual, refactor preview will pop up a preview --- .../codeAction/browser/codeActionCommands.ts | 59 +++++++++++++++---- .../browser/codeActionContributions.ts | 3 +- .../codeAction/browser/codeActionMenu.ts | 4 +- .../codeAction/browser/codeActionUi.ts | 17 ++++-- .../contrib/codeAction/browser/types.ts | 2 + 5 files changed, 68 insertions(+), 17 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts index 6e4c7a0b42e..37dd8e4727f 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts @@ -27,8 +27,8 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IMarkerService } from 'vs/platform/markers/common/markers'; -import { INotificationService } from 'vs/platform/notification/common/notification'; import { IEditorProgressService } from 'vs/platform/progress/common/progress'; +import { INotificationService } from 'vs/platform/notification/common/notification'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { CodeActionModel, CodeActionsState, SUPPORTED_CODE_ACTIONS } from './codeActionModel'; import { CodeActionAutoApply, CodeActionCommandArgs, CodeActionFilter, CodeActionKind, CodeActionTrigger } from './types'; @@ -92,11 +92,12 @@ export class QuickFixController extends Disposable implements IEditorContributio this._model = this._register(new CodeActionModel(this._editor, languageFeaturesService.codeActionProvider, markerService, contextKeyService, progressService)); this._register(this._model.onDidChangeState(newState => this.update(newState))); + this._ui = new Lazy(() => this._register(new CodeActionUi(editor, QuickFixAction.Id, AutoFixAction.Id, { - applyCodeAction: async (action, retrigger) => { + applyCodeAction: async (action, retrigger, showPreview) => { try { - await this._applyCodeAction(action); + await this._applyCodeAction(action, showPreview); } finally { if (retrigger) { this._trigger({ type: CodeActionTriggerType.Auto, filter: {} }); @@ -133,15 +134,15 @@ export class QuickFixController extends Disposable implements IEditorContributio return this._model.trigger(trigger); } - private _applyCodeAction(action: CodeActionItem): Promise { - return this._instantiationService.invokeFunction(applyCodeAction, action, this._editor); + private _applyCodeAction(action: CodeActionItem, showPreview: boolean): Promise { + return this._instantiationService.invokeFunction(applyCodeAction, action, { showPreviewPane: showPreview, editor: this._editor }); } } export async function applyCodeAction( accessor: ServicesAccessor, item: CodeActionItem, - editor?: ICodeEditor, + options?: { showPreviewPane?: boolean; editor?: ICodeEditor } ): Promise { const bulkEditService = accessor.get(IBulkEditService); const commandService = accessor.get(ICommandService); @@ -170,12 +171,14 @@ export async function applyCodeAction( await item.resolve(CancellationToken.None); if (item.action.edit) { + // let temp = CodeActionItem.RefactorAction; await bulkEditService.apply(ResourceEdit.convert(item.action.edit), { - editor, + editor: options?.editor, label: item.action.title, quotableLabel: item.action.title, code: 'undoredo.codeAction', - respectAutoSaveConfig: true + respectAutoSaveConfig: true, + showPreview: options?.showPreviewPane, }); } @@ -280,7 +283,7 @@ export class RefactorAction extends EditorAction { constructor() { super({ id: refactorCommandId, - label: nls.localize('refactor.label', "Refactor..."), + label: nls.localize('refactor.label2', "Refactor..."), alias: 'Refactor...', precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider), kbOpts: { @@ -320,7 +323,43 @@ export class RefactorAction extends EditorAction { : nls.localize('editor.action.refactor.noneMessage', "No refactorings available"), { include: CodeActionKind.Refactor.contains(args.kind) ? args.kind : CodeActionKind.None, - onlyIncludePreferredActions: args.preferred, + onlyIncludePreferredActions: args.preferred + }, + args.apply); + } +} + +export class RefactorPreview extends EditorAction { + + constructor() { + super({ + id: refactorCommandId + 1, + label: nls.localize('refactor.label1', "Refactor Preview..."), + alias: 'Refactor Preview...', + precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider), + description: { + description: 'Refactor Preview...', + args: [{ name: 'args', schema: argsSchema }] + } + }); + } + + public run(_accessor: ServicesAccessor, editor: ICodeEditor, userArgs: any): void { + const args = CodeActionCommandArgs.fromUser(userArgs, { + kind: CodeActionKind.Refactor, + apply: CodeActionAutoApply.Never + }); + return triggerCodeActionsForEditorSelection(editor, + typeof userArgs?.kind === 'string' + ? args.preferred + ? nls.localize('editor.action.refactor.noneMessage.preferred.kind', "No preferred refactorings for '{0}' available", userArgs.kind) + : nls.localize('editor.action.refactor.noneMessage.kind', "No refactorings for '{0}' available", userArgs.kind) + : args.preferred + ? nls.localize('editor.action.refactor.noneMessage.preferred', "No preferred refactorings available") + : nls.localize('editor.action.refactor.noneMessage', "No refactorings available"), + { + include: CodeActionKind.Refactor.contains(args.kind) ? args.kind : CodeActionKind.None, + onlyIncludePreferredActions: args.preferred, preview: true }, args.apply); } diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionContributions.ts b/src/vs/editor/contrib/codeAction/browser/codeActionContributions.ts index ddbe57e0e31..359bbf7941f 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionContributions.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionContributions.ts @@ -4,12 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { registerEditorAction, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import { AutoFixAction, CodeActionCommand, FixAllAction, OrganizeImportsAction, QuickFixAction, QuickFixController, RefactorAction, SourceAction } from 'vs/editor/contrib/codeAction/browser/codeActionCommands'; +import { AutoFixAction, CodeActionCommand, FixAllAction, OrganizeImportsAction, QuickFixAction, QuickFixController, RefactorAction, RefactorPreview, SourceAction } from 'vs/editor/contrib/codeAction/browser/codeActionCommands'; registerEditorContribution(QuickFixController.ID, QuickFixController); registerEditorAction(QuickFixAction); registerEditorAction(RefactorAction); +registerEditorAction(RefactorPreview); registerEditorAction(SourceAction); registerEditorAction(OrganizeImportsAction); registerEditorAction(AutoFixAction); diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts index 9978c8a442c..56da9f50fb3 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts @@ -23,7 +23,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; interface CodeActionWidgetDelegate { - onSelectCodeAction: (action: CodeActionItem) => Promise; + onSelectCodeAction: (action: CodeActionItem, trigger: CodeActionTrigger) => Promise; } interface ResolveCodeActionKeybinding { @@ -115,7 +115,7 @@ export class CodeActionMenu extends Disposable { actionsToShow: readonly CodeActionItem[], documentation: readonly Command[] ): IAction[] { - const toCodeActionAction = (item: CodeActionItem): CodeActionAction => new CodeActionAction(item.action, () => this._delegate.onSelectCodeAction(item)); + const toCodeActionAction = (item: CodeActionItem): CodeActionAction => new CodeActionAction(item.action, () => this._delegate.onSelectCodeAction(item, trigger)); const result: IAction[] = actionsToShow .map(toCodeActionAction); diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts b/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts index e191d6ba9f5..47715bedcae 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts @@ -31,7 +31,7 @@ export class CodeActionUi extends Disposable { quickFixActionId: string, preferredFixActionId: string, private readonly delegate: { - applyCodeAction: (action: CodeActionItem, regtriggerAfterApply: boolean) => Promise; + applyCodeAction: (action: CodeActionItem, regtriggerAfterApply: boolean, preview: boolean) => Promise; }, @IInstantiationService instantiationService: IInstantiationService, ) { @@ -39,8 +39,17 @@ export class CodeActionUi extends Disposable { this._codeActionWidget = new Lazy(() => { return this._register(instantiationService.createInstance(CodeActionMenu, this._editor, { - onSelectCodeAction: async (action) => { - this.delegate.applyCodeAction(action, /* retrigger */ true); + onSelectCodeAction: async (action, trigger) => { + if (trigger.filter === undefined) { + return; + } + + if (trigger.filter.preview) { + this.delegate.applyCodeAction(action, /* retrigger */ true, true); + } else { + this.delegate.applyCodeAction(action, /* retrigger */ true, false); + } + } })); }); @@ -85,7 +94,7 @@ export class CodeActionUi extends Disposable { if (validActionToApply) { try { this._lightBulbWidget.getValue().hide(); - await this.delegate.applyCodeAction(validActionToApply, false); + await this.delegate.applyCodeAction(validActionToApply, false, false); } finally { actions.dispose(); } diff --git a/src/vs/editor/contrib/codeAction/browser/types.ts b/src/vs/editor/contrib/codeAction/browser/types.ts index ae406530c68..3b0ad95f175 100644 --- a/src/vs/editor/contrib/codeAction/browser/types.ts +++ b/src/vs/editor/contrib/codeAction/browser/types.ts @@ -13,6 +13,7 @@ export class CodeActionKind { public static readonly Empty = new CodeActionKind(''); public static readonly QuickFix = new CodeActionKind('quickfix'); public static readonly Refactor = new CodeActionKind('refactor'); + public static readonly Preview = new CodeActionKind('preview'); public static readonly Source = new CodeActionKind('source'); public static readonly SourceOrganizeImports = CodeActionKind.Source.append('organizeImports'); public static readonly SourceFixAll = CodeActionKind.Source.append('fixAll'); @@ -49,6 +50,7 @@ export interface CodeActionFilter { readonly excludes?: readonly CodeActionKind[]; readonly includeSourceActions?: boolean; readonly onlyIncludePreferredActions?: boolean; + readonly preview?: boolean; } export function mayIncludeActionsOfKind(filter: CodeActionFilter, providedKind: CodeActionKind): boolean { From 578cf6b24851657b38927aea32c7139c630c46f1 Mon Sep 17 00:00:00 2001 From: Justin Chen <54879025+justschen@users.noreply.github.com> Date: Wed, 8 Jun 2022 14:54:59 -0700 Subject: [PATCH 03/32] fixed CodeActionTrigger preview variable and code cleanup --- .../contrib/codeAction/browser/codeAction.ts | 1 + .../codeAction/browser/codeActionCommands.ts | 23 ++++++++++--------- .../codeAction/browser/codeActionUi.ts | 6 +---- .../contrib/codeAction/browser/types.ts | 3 +-- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeAction.ts b/src/vs/editor/contrib/codeAction/browser/codeAction.ts index 75f7f392e2e..72d71d496f0 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeAction.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeAction.ts @@ -22,6 +22,7 @@ import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeat export const codeActionCommandId = 'editor.action.codeAction'; export const refactorCommandId = 'editor.action.refactor'; +export const refactorPreviewCommandId = 'editor.action.refactor.preview'; export const sourceActionCommandId = 'editor.action.sourceAction'; export const organizeImportsCommandId = 'editor.action.organizeImports'; export const fixAllCommandId = 'editor.action.fixAll'; diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts index 37dd8e4727f..8deeea4c4af 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts @@ -18,7 +18,7 @@ import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { CodeActionTriggerType } from 'vs/editor/common/languages'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; -import { codeActionCommandId, CodeActionItem, CodeActionSet, fixAllCommandId, organizeImportsCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/browser/codeAction'; +import { codeActionCommandId, CodeActionItem, CodeActionSet, fixAllCommandId, organizeImportsCommandId, refactorCommandId, refactorPreviewCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/browser/codeAction'; import { CodeActionUi } from 'vs/editor/contrib/codeAction/browser/codeActionUi'; import { MessageController } from 'vs/editor/contrib/message/browser/messageController'; import * as nls from 'vs/nls'; @@ -119,7 +119,8 @@ export class QuickFixController extends Disposable implements IEditorContributio public manualTriggerAtCurrentPosition( notAvailableMessage: string, filter?: CodeActionFilter, - autoApply?: CodeActionAutoApply + autoApply?: CodeActionAutoApply, + preview?: boolean ): void { if (!this._editor.hasModel()) { return; @@ -127,7 +128,7 @@ export class QuickFixController extends Disposable implements IEditorContributio MessageController.get(this._editor)?.closeMessage(); const triggerPosition = this._editor.getPosition(); - this._trigger({ type: CodeActionTriggerType.Invoke, filter, autoApply, context: { notAvailableMessage, position: triggerPosition } }); + this._trigger({ type: CodeActionTriggerType.Invoke, filter, autoApply, context: { notAvailableMessage, position: triggerPosition }, preview }); } private _trigger(trigger: CodeActionTrigger) { @@ -171,7 +172,6 @@ export async function applyCodeAction( await item.resolve(CancellationToken.None); if (item.action.edit) { - // let temp = CodeActionItem.RefactorAction; await bulkEditService.apply(ResourceEdit.convert(item.action.edit), { editor: options?.editor, label: item.action.title, @@ -209,12 +209,13 @@ function triggerCodeActionsForEditorSelection( editor: ICodeEditor, notAvailableMessage: string, filter: CodeActionFilter | undefined, - autoApply: CodeActionAutoApply | undefined + autoApply: CodeActionAutoApply | undefined, + preview: boolean = false ): void { if (editor.hasModel()) { const controller = QuickFixController.get(editor); if (controller) { - controller.manualTriggerAtCurrentPosition(notAvailableMessage, filter, autoApply); + controller.manualTriggerAtCurrentPosition(notAvailableMessage, filter, autoApply, preview); } } } @@ -283,7 +284,7 @@ export class RefactorAction extends EditorAction { constructor() { super({ id: refactorCommandId, - label: nls.localize('refactor.label2', "Refactor..."), + label: nls.localize('refactor.label', "Refactor..."), alias: 'Refactor...', precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider), kbOpts: { @@ -333,8 +334,8 @@ export class RefactorPreview extends EditorAction { constructor() { super({ - id: refactorCommandId + 1, - label: nls.localize('refactor.label1', "Refactor Preview..."), + id: refactorPreviewCommandId, + label: nls.localize('refactor.preview.label', "Refactor Preview..."), alias: 'Refactor Preview...', precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider), description: { @@ -359,9 +360,9 @@ export class RefactorPreview extends EditorAction { : nls.localize('editor.action.refactor.noneMessage', "No refactorings available"), { include: CodeActionKind.Refactor.contains(args.kind) ? args.kind : CodeActionKind.None, - onlyIncludePreferredActions: args.preferred, preview: true + onlyIncludePreferredActions: args.preferred, }, - args.apply); + args.apply, true); } } diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts b/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts index 47715bedcae..b02d185387a 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts @@ -40,11 +40,7 @@ export class CodeActionUi extends Disposable { this._codeActionWidget = new Lazy(() => { return this._register(instantiationService.createInstance(CodeActionMenu, this._editor, { onSelectCodeAction: async (action, trigger) => { - if (trigger.filter === undefined) { - return; - } - - if (trigger.filter.preview) { + if (trigger.preview) { this.delegate.applyCodeAction(action, /* retrigger */ true, true); } else { this.delegate.applyCodeAction(action, /* retrigger */ true, false); diff --git a/src/vs/editor/contrib/codeAction/browser/types.ts b/src/vs/editor/contrib/codeAction/browser/types.ts index 3b0ad95f175..cfc6d344980 100644 --- a/src/vs/editor/contrib/codeAction/browser/types.ts +++ b/src/vs/editor/contrib/codeAction/browser/types.ts @@ -13,7 +13,6 @@ export class CodeActionKind { public static readonly Empty = new CodeActionKind(''); public static readonly QuickFix = new CodeActionKind('quickfix'); public static readonly Refactor = new CodeActionKind('refactor'); - public static readonly Preview = new CodeActionKind('preview'); public static readonly Source = new CodeActionKind('source'); public static readonly SourceOrganizeImports = CodeActionKind.Source.append('organizeImports'); public static readonly SourceFixAll = CodeActionKind.Source.append('fixAll'); @@ -50,7 +49,6 @@ export interface CodeActionFilter { readonly excludes?: readonly CodeActionKind[]; readonly includeSourceActions?: boolean; readonly onlyIncludePreferredActions?: boolean; - readonly preview?: boolean; } export function mayIncludeActionsOfKind(filter: CodeActionFilter, providedKind: CodeActionKind): boolean { @@ -124,6 +122,7 @@ export interface CodeActionTrigger { readonly notAvailableMessage: string; readonly position: Position; }; + readonly preview?: boolean; } export class CodeActionCommandArgs { From 3aebd4c85c185e3b953557461d5be1dc10d173ad Mon Sep 17 00:00:00 2001 From: Justin Chen <54879025+justschen@users.noreply.github.com> Date: Wed, 8 Jun 2022 15:23:39 -0700 Subject: [PATCH 04/32] fix on label and verification --- src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts index 8deeea4c4af..ce8958dd438 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts @@ -335,7 +335,7 @@ export class RefactorPreview extends EditorAction { constructor() { super({ id: refactorPreviewCommandId, - label: nls.localize('refactor.preview.label', "Refactor Preview..."), + label: nls.localize('refactorPreview.label', "Refactor Preview..."), alias: 'Refactor Preview...', precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider), description: { From ec30b14cfbc608fb0a690b3463883013e231efbb Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 8 Jun 2022 15:31:19 -0700 Subject: [PATCH 05/32] revert and fix on verification --- src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts index ce8958dd438..8deeea4c4af 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts @@ -335,7 +335,7 @@ export class RefactorPreview extends EditorAction { constructor() { super({ id: refactorPreviewCommandId, - label: nls.localize('refactorPreview.label', "Refactor Preview..."), + label: nls.localize('refactor.preview.label', "Refactor Preview..."), alias: 'Refactor Preview...', precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider), description: { From 40d4a40f30bbab7704b5831286b106478db8dfa9 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 8 Jun 2022 16:06:11 -0700 Subject: [PATCH 06/32] code cleanup, helper function on trigger --- .../codeAction/browser/codeActionCommands.ts | 66 ++++++++----------- .../codeAction/browser/codeActionUi.ts | 7 +- 2 files changed, 29 insertions(+), 44 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts index 8deeea4c4af..3eab7d6704e 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts @@ -39,6 +39,26 @@ function contextKeyForSupportedActions(kind: CodeActionKind) { new RegExp('(\\s|^)' + escapeRegExpCharacters(kind.value) + '\\b')); } +function RefactorTrigger(editor: ICodeEditor, userArgs: any, preview: boolean) { + const args = CodeActionCommandArgs.fromUser(userArgs, { + kind: CodeActionKind.Refactor, + apply: CodeActionAutoApply.Never + }); + return triggerCodeActionsForEditorSelection(editor, + typeof userArgs?.kind === 'string' + ? args.preferred + ? nls.localize('editor.action.refactor.noneMessage.preferred.kind', "No preferred refactorings for '{0}' available", userArgs.kind) + : nls.localize('editor.action.refactor.noneMessage.kind', "No refactorings for '{0}' available", userArgs.kind) + : args.preferred + ? nls.localize('editor.action.refactor.noneMessage.preferred', "No preferred refactorings available") + : nls.localize('editor.action.refactor.noneMessage', "No refactorings available"), + { + include: CodeActionKind.Refactor.contains(args.kind) ? args.kind : CodeActionKind.None, + onlyIncludePreferredActions: args.preferred + }, + args.apply, preview); +} + const argsSchema: IJSONSchema = { type: 'object', defaultSnippets: [{ body: { kind: '' } }], @@ -95,9 +115,9 @@ export class QuickFixController extends Disposable implements IEditorContributio this._ui = new Lazy(() => this._register(new CodeActionUi(editor, QuickFixAction.Id, AutoFixAction.Id, { - applyCodeAction: async (action, retrigger, showPreview) => { + applyCodeAction: async (action, retrigger, preview) => { try { - await this._applyCodeAction(action, showPreview); + await this._applyCodeAction(action, preview); } finally { if (retrigger) { this._trigger({ type: CodeActionTriggerType.Auto, filter: {} }); @@ -135,8 +155,8 @@ export class QuickFixController extends Disposable implements IEditorContributio return this._model.trigger(trigger); } - private _applyCodeAction(action: CodeActionItem, showPreview: boolean): Promise { - return this._instantiationService.invokeFunction(applyCodeAction, action, { showPreviewPane: showPreview, editor: this._editor }); + private _applyCodeAction(action: CodeActionItem, preview: boolean): Promise { + return this._instantiationService.invokeFunction(applyCodeAction, action, { showPreviewPane: preview, editor: this._editor }); } } @@ -310,23 +330,7 @@ export class RefactorAction extends EditorAction { } public run(_accessor: ServicesAccessor, editor: ICodeEditor, userArgs: any): void { - const args = CodeActionCommandArgs.fromUser(userArgs, { - kind: CodeActionKind.Refactor, - apply: CodeActionAutoApply.Never - }); - return triggerCodeActionsForEditorSelection(editor, - typeof userArgs?.kind === 'string' - ? args.preferred - ? nls.localize('editor.action.refactor.noneMessage.preferred.kind', "No preferred refactorings for '{0}' available", userArgs.kind) - : nls.localize('editor.action.refactor.noneMessage.kind', "No refactorings for '{0}' available", userArgs.kind) - : args.preferred - ? nls.localize('editor.action.refactor.noneMessage.preferred', "No preferred refactorings available") - : nls.localize('editor.action.refactor.noneMessage', "No refactorings available"), - { - include: CodeActionKind.Refactor.contains(args.kind) ? args.kind : CodeActionKind.None, - onlyIncludePreferredActions: args.preferred - }, - args.apply); + return RefactorTrigger(editor, userArgs, false); } } @@ -335,7 +339,7 @@ export class RefactorPreview extends EditorAction { constructor() { super({ id: refactorPreviewCommandId, - label: nls.localize('refactor.preview.label', "Refactor Preview..."), + label: nls.localize('refactor.preview.label', "Refactor with Preview..."), alias: 'Refactor Preview...', precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider), description: { @@ -346,23 +350,7 @@ export class RefactorPreview extends EditorAction { } public run(_accessor: ServicesAccessor, editor: ICodeEditor, userArgs: any): void { - const args = CodeActionCommandArgs.fromUser(userArgs, { - kind: CodeActionKind.Refactor, - apply: CodeActionAutoApply.Never - }); - return triggerCodeActionsForEditorSelection(editor, - typeof userArgs?.kind === 'string' - ? args.preferred - ? nls.localize('editor.action.refactor.noneMessage.preferred.kind', "No preferred refactorings for '{0}' available", userArgs.kind) - : nls.localize('editor.action.refactor.noneMessage.kind', "No refactorings for '{0}' available", userArgs.kind) - : args.preferred - ? nls.localize('editor.action.refactor.noneMessage.preferred', "No preferred refactorings available") - : nls.localize('editor.action.refactor.noneMessage', "No refactorings available"), - { - include: CodeActionKind.Refactor.contains(args.kind) ? args.kind : CodeActionKind.None, - onlyIncludePreferredActions: args.preferred, - }, - args.apply, true); + return RefactorTrigger(editor, userArgs, true); } } diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts b/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts index b02d185387a..c1e5a2f2789 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts @@ -40,12 +40,9 @@ export class CodeActionUi extends Disposable { this._codeActionWidget = new Lazy(() => { return this._register(instantiationService.createInstance(CodeActionMenu, this._editor, { onSelectCodeAction: async (action, trigger) => { - if (trigger.preview) { - this.delegate.applyCodeAction(action, /* retrigger */ true, true); - } else { - this.delegate.applyCodeAction(action, /* retrigger */ true, false); + if (trigger.preview !== undefined) { + this.delegate.applyCodeAction(action, /* retrigger */ true, trigger.preview); } - } })); }); From 86ea71dff2dfbdafb510c0f8dda14a093372d492 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 8 Jun 2022 21:57:45 -0700 Subject: [PATCH 07/32] matched naming convention and fixed issue with trigger.preview boolean: --- .../editor/contrib/codeAction/browser/codeActionCommands.ts | 6 +++--- src/vs/editor/contrib/codeAction/browser/codeActionUi.ts | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts index 3eab7d6704e..6043a70dedf 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts @@ -156,14 +156,14 @@ export class QuickFixController extends Disposable implements IEditorContributio } private _applyCodeAction(action: CodeActionItem, preview: boolean): Promise { - return this._instantiationService.invokeFunction(applyCodeAction, action, { showPreviewPane: preview, editor: this._editor }); + return this._instantiationService.invokeFunction(applyCodeAction, action, { preview, editor: this._editor }); } } export async function applyCodeAction( accessor: ServicesAccessor, item: CodeActionItem, - options?: { showPreviewPane?: boolean; editor?: ICodeEditor } + options?: { preview?: boolean; editor?: ICodeEditor } ): Promise { const bulkEditService = accessor.get(IBulkEditService); const commandService = accessor.get(ICommandService); @@ -198,7 +198,7 @@ export async function applyCodeAction( quotableLabel: item.action.title, code: 'undoredo.codeAction', respectAutoSaveConfig: true, - showPreview: options?.showPreviewPane, + showPreview: options?.preview, }); } diff --git a/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts b/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts index c1e5a2f2789..09c82ccd2ea 100644 --- a/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts +++ b/src/vs/editor/contrib/codeAction/browser/codeActionUi.ts @@ -40,9 +40,7 @@ export class CodeActionUi extends Disposable { this._codeActionWidget = new Lazy(() => { return this._register(instantiationService.createInstance(CodeActionMenu, this._editor, { onSelectCodeAction: async (action, trigger) => { - if (trigger.preview !== undefined) { - this.delegate.applyCodeAction(action, /* retrigger */ true, trigger.preview); - } + this.delegate.applyCodeAction(action, /* retrigger */ true, Boolean(trigger.preview)); } })); }); From 670c3fd002b0d85c5b07bac77b30d197bcba44a1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 9 Jun 2022 16:55:46 +0200 Subject: [PATCH 08/32] fix https://github.com/microsoft/vscode/issues/150293 (#151616) --- .../api/browser/mainThreadCommands.ts | 11 ++--- .../workbench/api/common/extHost.protocol.ts | 3 +- .../workbench/api/common/extHostCommands.ts | 20 ++++----- .../api/test/browser/extHostCommands.test.ts | 24 +++++----- .../test/browser/mainThreadCommands.test.ts | 44 +------------------ 5 files changed, 28 insertions(+), 74 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadCommands.ts b/src/vs/workbench/api/browser/mainThreadCommands.ts index dc5df7b422e..98d2046f54f 100644 --- a/src/vs/workbench/api/browser/mainThreadCommands.ts +++ b/src/vs/workbench/api/browser/mainThreadCommands.ts @@ -74,17 +74,18 @@ export class MainThreadCommands implements MainThreadCommandsShape { } } - async $executeCommand(id: string, args: any[] | SerializableObjectWithBuffers, retry: boolean): Promise { + async $activateByCommandEvent(id: string): Promise { + const activationEvent = `onCommand:${id}`; + await this._extensionService.activateByEvent(activationEvent); + } + + async $executeCommand(id: string, args: any[] | SerializableObjectWithBuffers): Promise { if (args instanceof SerializableObjectWithBuffers) { args = args.value; } for (let i = 0; i < args.length; i++) { args[i] = revive(args[i]); } - if (retry && args.length > 0 && !CommandsRegistry.getCommand(id)) { - await this._extensionService.activateByEvent(`onCommand:${id}`); - throw new Error('$executeCommand:retry'); - } return this._commandService.executeCommand(id, ...args); } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 60478d4a194..b2205cc31cb 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -92,7 +92,8 @@ export interface MainThreadClipboardShape extends IDisposable { export interface MainThreadCommandsShape extends IDisposable { $registerCommand(id: string): void; $unregisterCommand(id: string): void; - $executeCommand(id: string, args: any[] | SerializableObjectWithBuffers, retry: boolean): Promise; + $activateByCommandEvent(id: string): Promise; + $executeCommand(id: string, args: any[] | SerializableObjectWithBuffers): Promise; $getCommands(): Promise; } diff --git a/src/vs/workbench/api/common/extHostCommands.ts b/src/vs/workbench/api/common/extHostCommands.ts index d0ae8f53ff4..4ff7b0e4911 100644 --- a/src/vs/workbench/api/common/extHostCommands.ts +++ b/src/vs/workbench/api/common/extHostCommands.ts @@ -163,10 +163,15 @@ export class ExtHostCommands implements ExtHostCommandsShape { executeCommand(id: string, ...args: any[]): Promise { this._logService.trace('ExtHostCommands#executeCommand', id); - return this._doExecuteCommand(id, args, true); + return this._doExecuteCommand(id, args); } - private async _doExecuteCommand(id: string, args: any[], retry: boolean): Promise { + private async _doExecuteCommand(id: string, args: any[]): Promise { + + // make sure to emit an onCommand-activation event in ALL cases + // (1) locally known command -> activation notificed bystander + // (2) unknown command -> can activate future local extension + await this.#proxy.$activateByCommandEvent(id); if (this._commands.has(id)) { // we stay inside the extension host and support @@ -201,17 +206,10 @@ export class ExtHostCommands implements ExtHostCommandsShape { }); try { - const result = await this.#proxy.$executeCommand(id, hasBuffers ? new SerializableObjectWithBuffers(toArgs) : toArgs, retry); + const result = await this.#proxy.$executeCommand(id, hasBuffers ? new SerializableObjectWithBuffers(toArgs) : toArgs); return revive(result); } catch (e) { - // Rerun the command when it wasn't known, had arguments, and when retry - // is enabled. We do this because the command might be registered inside - // the extension host now and can therfore accept the arguments as-is. - if (e instanceof Error && e.message === '$executeCommand:retry') { - return this._doExecuteCommand(id, args, false); - } else { - throw e; - } + throw e; } } } diff --git a/src/vs/workbench/api/test/browser/extHostCommands.test.ts b/src/vs/workbench/api/test/browser/extHostCommands.test.ts index da9b47ccda9..7426d5d530e 100644 --- a/src/vs/workbench/api/test/browser/extHostCommands.test.ts +++ b/src/vs/workbench/api/test/browser/extHostCommands.test.ts @@ -60,7 +60,7 @@ suite('ExtHostCommands', function () { assert.strictEqual(unregisterCounter, 1); }); - test('execute with retry', async function () { + test('execute triggers activate', async function () { let count = 0; @@ -68,16 +68,13 @@ suite('ExtHostCommands', function () { override $registerCommand(id: string): void { // } - override async $executeCommand(id: string, args: any[], retry: boolean): Promise { - count++; - assert.strictEqual(retry, count === 1); - if (count === 1) { - assert.strictEqual(retry, true); - throw new Error('$executeCommand:retry'); - } else { - assert.strictEqual(retry, false); - return 17; - } + + override async $activateByCommandEvent(id: string): Promise { + count += 1; + } + + override async $executeCommand(id: string, args: any[]): Promise { + return undefined; } }; @@ -86,8 +83,7 @@ suite('ExtHostCommands', function () { new NullLogService() ); - const result = await commands.executeCommand('fooo', [this, true]); - assert.strictEqual(result, 17); - assert.strictEqual(count, 2); + await commands.executeCommand('fooo', [this, true]); + assert.strictEqual(count, 1); }); }); diff --git a/src/vs/workbench/api/test/browser/mainThreadCommands.test.ts b/src/vs/workbench/api/test/browser/mainThreadCommands.test.ts index fe6133d11ad..e91553dc9b5 100644 --- a/src/vs/workbench/api/test/browser/mainThreadCommands.test.ts +++ b/src/vs/workbench/api/test/browser/mainThreadCommands.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { MainThreadCommands } from 'vs/workbench/api/browser/mainThreadCommands'; -import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { SingleProxyRPCProtocol } from 'vs/workbench/api/test/common/testRPCProtocol'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { mock } from 'vs/base/test/common/mock'; @@ -42,46 +42,4 @@ suite('MainThreadCommands', function () { assert.strictEqual(CommandsRegistry.getCommand('foo'), undefined); assert.strictEqual(CommandsRegistry.getCommand('bar'), undefined); }); - - test('activate and throw when needed', async function () { - - const activations: string[] = []; - const runs: string[] = []; - - const commands = new MainThreadCommands( - SingleProxyRPCProtocol(null), - new class extends mock() { - override executeCommand(id: string): Promise { - runs.push(id); - return Promise.resolve(undefined); - } - }, - new class extends mock() { - override activateByEvent(id: string) { - activations.push(id); - return Promise.resolve(); - } - } - ); - - // case 1: arguments and retry - try { - activations.length = 0; - await commands.$executeCommand('bazz', [1, 2, { n: 3 }], true); - assert.ok(false); - } catch (e) { - assert.deepStrictEqual(activations, ['onCommand:bazz']); - assert.strictEqual((e).message, '$executeCommand:retry'); - } - - // case 2: no arguments and retry - runs.length = 0; - await commands.$executeCommand('bazz', [], true); - assert.deepStrictEqual(runs, ['bazz']); - - // case 3: arguments and no retry - runs.length = 0; - await commands.$executeCommand('bazz', [1, 2, true], false); - assert.deepStrictEqual(runs, ['bazz']); - }); }); From 03e43d3bd5a803c130226f9f960e1d872f186472 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 9 Jun 2022 08:09:43 -0700 Subject: [PATCH 09/32] Fix unit test DI warnings Fixes #151526 --- .../test/browser/xterm/shellIntegrationAddon.test.ts | 2 +- .../terminal/test/browser/xterm/xtermTerminal.test.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/shellIntegrationAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/shellIntegrationAddon.test.ts index 8e8740ea388..bafbd5e65a8 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/shellIntegrationAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/shellIntegrationAddon.test.ts @@ -48,7 +48,7 @@ suite('ShellIntegrationAddon', () => { }); const instantiationService = new TestInstantiationService(); instantiationService.stub(ILogService, NullLogService); - shellIntegrationAddon = instantiationService.createInstance(TestShellIntegrationAddon); + shellIntegrationAddon = instantiationService.createInstance(TestShellIntegrationAddon, undefined, undefined); xterm.loadAddon(shellIntegrationAddon); capabilities = shellIntegrationAddon.capabilities; }); diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts index eaec5127e56..a35b293a2a9 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts @@ -113,7 +113,7 @@ suite('XtermTerminal', () => { instantiationService.stub(IContextMenuService, instantiationService.createInstance(ContextMenuService)); configHelper = instantiationService.createInstance(TerminalConfigHelper); - xterm = instantiationService.createInstance(TestXtermTerminal, Terminal, configHelper, 80, 30, TerminalLocation.Panel, new TerminalCapabilityStore()); + xterm = instantiationService.createInstance(TestXtermTerminal, Terminal, configHelper, 80, 30, TerminalLocation.Panel, new TerminalCapabilityStore(), true); TestWebglAddon.shouldThrow = false; TestWebglAddon.isEnabled = false; @@ -130,7 +130,7 @@ suite('XtermTerminal', () => { [PANEL_BACKGROUND]: '#ff0000', [SIDE_BAR_BACKGROUND]: '#00ff00' })); - xterm = instantiationService.createInstance(XtermTerminal, Terminal, configHelper, 80, 30, TerminalLocation.Panel, new TerminalCapabilityStore()); + xterm = instantiationService.createInstance(XtermTerminal, Terminal, configHelper, 80, 30, TerminalLocation.Panel, new TerminalCapabilityStore(), true); strictEqual(xterm.raw.options.theme?.background, '#ff0000'); viewDescriptorService.moveTerminalToLocation(ViewContainerLocation.Sidebar); strictEqual(xterm.raw.options.theme?.background, '#00ff00'); @@ -164,7 +164,7 @@ suite('XtermTerminal', () => { 'terminal.ansiBrightCyan': '#150000', 'terminal.ansiBrightWhite': '#160000', })); - xterm = instantiationService.createInstance(XtermTerminal, Terminal, configHelper, 80, 30, TerminalLocation.Panel, new TerminalCapabilityStore()); + xterm = instantiationService.createInstance(XtermTerminal, Terminal, configHelper, 80, 30, TerminalLocation.Panel, new TerminalCapabilityStore(), true); deepStrictEqual(xterm.raw.options.theme, { background: '#000100', foreground: '#000200', From bc5d6d52c455721b4b5c4202341de43e953f4d48 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 9 Jun 2022 07:15:30 -0800 Subject: [PATCH 10/32] reset terminal focus context key when panel closes or active editor changes and is not a terminal (#151618) --- src/vs/workbench/contrib/terminal/browser/terminal.ts | 6 ++++++ .../contrib/terminal/browser/terminalEditorService.ts | 8 ++++++++ .../contrib/terminal/browser/terminalInstance.ts | 4 ++++ src/vs/workbench/contrib/terminal/browser/terminalView.ts | 3 +++ 4 files changed, 21 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index d47d4fbad5d..65edb12ae16 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -669,6 +669,12 @@ export interface ITerminalInstance { */ clearSelection(): void; + /** + * When the panel is hidden or a terminal in the editor area becomes inactive, reset the focus context key + * to avoid issues like #147180. + */ + resetFocusContextKey(): void; + /** * Select all text in the terminal. */ diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index 77e38655595..aec68ee5d91 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -101,6 +101,14 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor } } })); + this._register(this._editorService.onDidActiveEditorChange(() => { + const instance = this._editorService.activeEditor instanceof TerminalEditorInput ? this._editorService.activeEditor : undefined; + if (!instance) { + for (const instance of this.instances) { + instance.resetFocusContextKey(); + } + } + })); } private _getActiveTerminalEditors(): EditorInput[] { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 2d7ec4682d3..0825cf86165 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1150,6 +1150,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } } + resetFocusContextKey(): void { + this._terminalFocusContextKey.reset(); + } + private _initDragAndDrop(container: HTMLElement) { this._dndObserver?.dispose(); const dndController = this._instantiationService.createInstance(TerminalInstanceDragAndDropController, container); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index d450e1d6609..dabbb9a49b0 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -175,6 +175,9 @@ export class TerminalViewPane extends ViewPane { this._terminalGroupService.activeGroup?.setVisible(visible); } } else { + for (const instance of this._terminalGroupService.instances) { + instance.resetFocusContextKey(); + } this._terminalGroupService.activeGroup?.setVisible(false); } })); From 22609886df9b5172847e0625ace94f034b4ff9c2 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Thu, 9 Jun 2022 11:39:14 -0400 Subject: [PATCH 11/32] Set z-index of watermark (#151623) --- src/vs/workbench/contrib/watermark/browser/media/watermark.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/watermark/browser/media/watermark.css b/src/vs/workbench/contrib/watermark/browser/media/watermark.css index 2c45ebd4b16..29eba5b8a5f 100644 --- a/src/vs/workbench/contrib/watermark/browser/media/watermark.css +++ b/src/vs/workbench/contrib/watermark/browser/media/watermark.css @@ -23,6 +23,8 @@ text-align: center; white-space: nowrap; overflow: hidden; + /* Watermark should show even over opaque backgrounds */ + z-index: 1000; } .monaco-workbench .part.editor > .content.empty > .watermark > .watermark-box { From cbfb128002bfd3812f179811e7dff5f6234c782b Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Thu, 9 Jun 2022 17:46:07 +0200 Subject: [PATCH 12/32] Removes unused symbols. --- src/vs/workbench/contrib/audioCues/browser/observable.ts | 1 - .../workbench/contrib/mergeEditor/browser/textModelDiffs.ts | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/vs/workbench/contrib/audioCues/browser/observable.ts b/src/vs/workbench/contrib/audioCues/browser/observable.ts index 32fe7ccda98..13205de661c 100644 --- a/src/vs/workbench/contrib/audioCues/browser/observable.ts +++ b/src/vs/workbench/contrib/audioCues/browser/observable.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { BugIndicatingError } from 'vs/base/common/errors'; import { Event } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; diff --git a/src/vs/workbench/contrib/mergeEditor/browser/textModelDiffs.ts b/src/vs/workbench/contrib/mergeEditor/browser/textModelDiffs.ts index 348aabaef38..e7c6c9967e5 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/textModelDiffs.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/textModelDiffs.ts @@ -227,7 +227,3 @@ export class EditorWorkerServiceDiffComputer implements IDiffComputer { return diffs.changes.map((c) => LineDiff.fromLineChange(c, textModel1, textModel2)); } } - -function wait(ms: number): Promise { - return new Promise(r => setTimeout(r, ms)); -} From 4c8474a0e50d3f875571dfee240779a20920d5cc Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 9 Jun 2022 17:50:14 +0200 Subject: [PATCH 13/32] speed up the theme browsing from marketplace (#151622) --- .../themes/browser/themes.contribution.ts | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts index 30308a2a8fb..ece11b70b1c 100644 --- a/src/vs/workbench/contrib/themes/browser/themes.contribution.ts +++ b/src/vs/workbench/contrib/themes/browser/themes.contribution.ts @@ -99,16 +99,18 @@ class MarketplaceThemesPicker { try { const installedExtensions = await this._installedExtensions; - const options = { text: `${this.marketplaceQuery} ${value}`, pageSize: 40 }; + const options = { text: `${this.marketplaceQuery} ${value}`, pageSize: 20 }; const pager = await this.extensionGalleryService.query(options, token); - for (let i = 0; i < pager.total && i < 1; i++) { + for (let i = 0; i < pager.total && i < 1; i++) { // loading multiple pages is turned of for now to avoid flickering if (token.isCancellationRequested) { break; } const nThemes = this._marketplaceThemes.length; + const gallery = i === 0 ? pager.firstPage : await pager.getPage(i, token); - const gallery = await pager.getPage(i, token); + const promises: Promise[] = []; + const promisesGalleries = []; for (let i = 0; i < gallery.length; i++) { if (token.isCancellationRequested) { break; @@ -116,12 +118,18 @@ class MarketplaceThemesPicker { const ext = gallery[i]; if (!installedExtensions.has(ext.identifier.id) && !this._marketplaceExtensions.has(ext.identifier.id)) { this._marketplaceExtensions.add(ext.identifier.id); - const themes = await this.getMarketplaceColorThemes(ext.publisher, ext.name, ext.version); - for (const theme of themes) { - this._marketplaceThemes.push({ id: theme.id, theme: theme, label: theme.label, description: `${ext.displayName} · ${ext.publisherDisplayName}`, galleryExtension: ext, buttons: [configureButton] }); - } + promises.push(this.getMarketplaceColorThemes(ext.publisher, ext.name, ext.version)); + promisesGalleries.push(ext); } } + const allThemes = await Promise.all(promises); + for (let i = 0; i < allThemes.length; i++) { + const ext = promisesGalleries[i]; + for (const theme of allThemes[i]) { + this._marketplaceThemes.push({ id: theme.id, theme: theme, label: theme.label, description: `${ext.displayName} · ${ext.publisherDisplayName}`, galleryExtension: ext, buttons: [configureButton] }); + } + } + if (nThemes !== this._marketplaceThemes.length) { this._marketplaceThemes.sort((t1, t2) => t1.label.localeCompare(t2.label)); this._onDidChange.fire(); From f1692ad986e49b19c5d6dfa1d723334d8cbafe30 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 9 Jun 2022 10:11:19 -0700 Subject: [PATCH 14/32] Improve terminal link debug logs --- .../workbench/contrib/terminal/browser/links/links.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/links/links.ts b/src/vs/workbench/contrib/terminal/browser/links/links.ts index a93a42c4b49..ad7f84b6141 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/links.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/links.ts @@ -79,30 +79,30 @@ export const enum TerminalBuiltinLinkType { /** * The link is validated to be a file on the file system and will open an editor. */ - LocalFile, + LocalFile = 'LocalFile', /** * The link is validated to be a folder on the file system and is outside the workspace. It will * reveal the folder within the explorer. */ - LocalFolderOutsideWorkspace, + LocalFolderOutsideWorkspace = 'LocalFolderOutsideWorkspace', /** * The link is validated to be a folder on the file system and is within the workspace and will * reveal the folder within the explorer. */ - LocalFolderInWorkspace, + LocalFolderInWorkspace = 'LocalFolderInWorkspace', /** * A low confidence link which will search for the file in the workspace. If there is a single * match, it will open the file; otherwise, it will present the matches in a quick pick. */ - Search, + Search = 'Search', /** * A link whose text is a valid URI. */ - Url + Url = 'Url' } export interface ITerminalExternalLinkType { From 1cd56dcf05410d0a7fd6d12586cb53d865a45baa Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 9 Jun 2022 10:46:21 -0700 Subject: [PATCH 15/32] Terminal search links: Prefer exact match against initial cwd Fixes #144534 --- .../browser/links/terminalLinkManager.ts | 2 +- .../browser/links/terminalLinkOpeners.ts | 17 ++++++++++++-- .../browser/links/terminalLinkManager.test.ts | 6 ++++- .../browser/links/terminalLinkOpeners.test.ts | 23 +++++++++++++++++-- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts index d56a7fe620e..bc918bc56e1 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts @@ -86,7 +86,7 @@ export class TerminalLinkManager extends DisposableStore { this._openers.set(TerminalBuiltinLinkType.LocalFile, localFileOpener); this._openers.set(TerminalBuiltinLinkType.LocalFolderInWorkspace, localFolderInWorkspaceOpener); this._openers.set(TerminalBuiltinLinkType.LocalFolderOutsideWorkspace, this._instantiationService.createInstance(TerminalLocalFolderOutsideWorkspaceLinkOpener)); - this._openers.set(TerminalBuiltinLinkType.Search, this._instantiationService.createInstance(TerminalSearchLinkOpener, capabilities, localFileOpener, localFolderInWorkspaceOpener, this._processManager.os || OS)); + this._openers.set(TerminalBuiltinLinkType.Search, this._instantiationService.createInstance(TerminalSearchLinkOpener, capabilities, this._processManager.getInitialCwd(), localFileOpener, localFolderInWorkspaceOpener, this._processManager.os || OS)); this._openers.set(TerminalBuiltinLinkType.Url, this._instantiationService.createInstance(TerminalUrlLinkOpener, !!this._processManager.remoteAuthority)); this._registerStandardLinkProviders(); diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts index fed1eb2491b..76c7cb113d3 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts @@ -125,6 +125,7 @@ export class TerminalSearchLinkOpener implements ITerminalLinkOpener { constructor( private readonly _capabilities: ITerminalCapabilityStore, + private readonly _initialCwd: Promise, private readonly _localFileOpener: TerminalLocalFileLinkOpener, private readonly _localFolderInWorkspaceOpener: TerminalLocalFolderInWorkspaceLinkOpener, private readonly _os: OperatingSystem, @@ -182,10 +183,20 @@ export class TerminalSearchLinkOpener implements ITerminalLinkOpener { } private async _getExactMatch(sanitizedLink: string): Promise { + // Make the an absolute link relative to the cwd if it isn't absolute + const pathModule = osPathModule(this._os); + const isAbsolute = pathModule.isAbsolute(sanitizedLink); + let absolutePath: string | undefined = isAbsolute ? sanitizedLink : undefined; + const initialCwd = await this._initialCwd; + if (!isAbsolute && initialCwd.length > 0) { + absolutePath = pathModule.join(initialCwd, sanitizedLink); + } + + // Try open as an absolute link let resourceMatch: IResourceMatch | undefined; - if (osPathModule(this._os).isAbsolute(sanitizedLink)) { + if (absolutePath) { + const slashNormalizedPath = this._os === OperatingSystem.Windows ? absolutePath.replace(/\\/g, '/') : absolutePath; const scheme = this._workbenchEnvironmentService.remoteAuthority ? Schemas.vscodeRemote : Schemas.file; - const slashNormalizedPath = this._os === OperatingSystem.Windows ? sanitizedLink.replace(/\\/g, '/') : sanitizedLink; const uri = URI.from({ scheme, path: slashNormalizedPath }); try { const fileStat = await this._fileService.stat(uri); @@ -194,6 +205,8 @@ export class TerminalSearchLinkOpener implements ITerminalLinkOpener { // File or dir doesn't exist, continue on } } + + // Search the workspace if an exact match based on the absolute path was not found if (!resourceMatch) { const results = await this._searchService.fileSearch( this._fileQueryBuilder.file(this._workspaceContextService.getWorkspace().folders, { diff --git a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkManager.test.ts b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkManager.test.ts index e37c554e6ef..a7559d081f0 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkManager.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkManager.test.ts @@ -81,7 +81,11 @@ suite('TerminalLinkManager', () => { instantiationService.stub(IViewDescriptorService, viewDescriptorService); xterm = new Terminal({ cols: 80, rows: 30 }); - linkManager = instantiationService.createInstance(TestLinkManager, xterm, upcastPartial({}), { + linkManager = instantiationService.createInstance(TestLinkManager, xterm, upcastPartial({ + async getInitialCwd() { + return ''; + } + }), { get(capability: T): ITerminalCapabilityImplMap[T] | undefined { return undefined; } diff --git a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts index a67d0f4b0d2..dcbdef59e2c 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts @@ -97,11 +97,30 @@ suite('Workbench - TerminalLinkOpeners', () => { capabilities.add(TerminalCapability.CommandDetection, commandDetection); }); + test('should open single exact match against cwd when searching if it exists', async () => { + localFileOpener = instantiationService.createInstance(TerminalLocalFileLinkOpener, OperatingSystem.Linux); + const localFolderOpener = instantiationService.createInstance(TerminalLocalFolderInWorkspaceLinkOpener); + opener = instantiationService.createInstance(TerminalSearchLinkOpener, capabilities, Promise.resolve('/initial/cwd'), localFileOpener, localFolderOpener, OperatingSystem.Linux); + fileService.setFiles([ + URI.from({ scheme: Schemas.file, path: '/initial/cwd/foo/bar.txt' }), + URI.from({ scheme: Schemas.file, path: '/initial/cwd/foo2/bar.txt' }) + ]); + await opener.open({ + text: 'foo/bar.txt', + bufferRange: { start: { x: 1, y: 1 }, end: { x: 8, y: 1 } }, + type: TerminalBuiltinLinkType.Search + }); + deepStrictEqual(activationResult, { + link: 'file:///initial/cwd/foo/bar.txt', + source: 'editor' + }); + }); + suite('macOS/Linux', () => { setup(() => { localFileOpener = instantiationService.createInstance(TerminalLocalFileLinkOpener, OperatingSystem.Linux); const localFolderOpener = instantiationService.createInstance(TerminalLocalFolderInWorkspaceLinkOpener); - opener = instantiationService.createInstance(TerminalSearchLinkOpener, capabilities, localFileOpener, localFolderOpener, OperatingSystem.Linux); + opener = instantiationService.createInstance(TerminalSearchLinkOpener, capabilities, Promise.resolve(''), localFileOpener, localFolderOpener, OperatingSystem.Linux); }); test('should apply the cwd to the link only when the file exists and cwdDetection is enabled', async () => { @@ -150,7 +169,7 @@ suite('Workbench - TerminalLinkOpeners', () => { setup(() => { localFileOpener = instantiationService.createInstance(TerminalLocalFileLinkOpener, OperatingSystem.Windows); const localFolderOpener = instantiationService.createInstance(TerminalLocalFolderInWorkspaceLinkOpener); - opener = instantiationService.createInstance(TerminalSearchLinkOpener, capabilities, localFileOpener, localFolderOpener, OperatingSystem.Windows); + opener = instantiationService.createInstance(TerminalSearchLinkOpener, capabilities, Promise.resolve(''), localFileOpener, localFolderOpener, OperatingSystem.Windows); }); test('should apply the cwd to the link only when the file exists and cwdDetection is enabled', async () => { From 5333e5bd041c833bf9997db88f10dd686ba6f4e8 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 9 Jun 2022 10:55:30 -0700 Subject: [PATCH 16/32] Update src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts Co-authored-by: Megan Rogge --- .../contrib/terminal/browser/links/terminalLinkOpeners.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts index 76c7cb113d3..835b57f934e 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts @@ -183,7 +183,7 @@ export class TerminalSearchLinkOpener implements ITerminalLinkOpener { } private async _getExactMatch(sanitizedLink: string): Promise { - // Make the an absolute link relative to the cwd if it isn't absolute + // Make the link relative to the cwd if it isn't absolute const pathModule = osPathModule(this._os); const isAbsolute = pathModule.isAbsolute(sanitizedLink); let absolutePath: string | undefined = isAbsolute ? sanitizedLink : undefined; From 432cbc3b004c35d89aaed698a2a32938e557229e Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Thu, 9 Jun 2022 14:23:13 -0400 Subject: [PATCH 17/32] Ensure extension host errors get properly serialized (#151628) --- src/vs/base/common/errors.ts | 4 +++- src/vs/workbench/api/browser/mainThreadErrors.ts | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/base/common/errors.ts b/src/vs/base/common/errors.ts index 38ca3e4e102..91e7cce161a 100644 --- a/src/vs/base/common/errors.ts +++ b/src/vs/base/common/errors.ts @@ -95,6 +95,7 @@ export interface SerializedError { readonly name: string; readonly message: string; readonly stack: string; + readonly noTelemetry: boolean; } export function transformErrorForSerialization(error: Error): SerializedError; @@ -107,7 +108,8 @@ export function transformErrorForSerialization(error: any): any { $isError: true, name, message, - stack + stack, + noTelemetry: error instanceof ErrorNoTelemetry }; } diff --git a/src/vs/workbench/api/browser/mainThreadErrors.ts b/src/vs/workbench/api/browser/mainThreadErrors.ts index 36fdac455c6..2d05a6a0e44 100644 --- a/src/vs/workbench/api/browser/mainThreadErrors.ts +++ b/src/vs/workbench/api/browser/mainThreadErrors.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SerializedError, onUnexpectedError } from 'vs/base/common/errors'; +import { SerializedError, onUnexpectedError, ErrorNoTelemetry } from 'vs/base/common/errors'; import { extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers'; import { MainContext, MainThreadErrorsShape } from 'vs/workbench/api/common/extHost.protocol'; @@ -17,7 +17,7 @@ export class MainThreadErrors implements MainThreadErrorsShape { $onUnexpectedError(err: any | SerializedError): void { if (err && err.$isError) { const { name, message, stack } = err; - err = new Error(); + err = err.noTelemetry ? new ErrorNoTelemetry() : new Error(); err.message = message; err.name = name; err.stack = stack; From 84e4f769084cf226b042a04d3d3e050e9b4ee4e9 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Thu, 9 Jun 2022 11:32:13 -0700 Subject: [PATCH 18/32] 1.68.0 -> 1.69.0 (#151635) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cc87e68f1eb..584111cd29e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "code-oss-dev", - "version": "1.68.0", + "version": "1.69.0", "distro": "2966cd72fc1a3a5fb89bf2d85a1a66e56206961a", "author": { "name": "Microsoft Corporation" From a8de8e2112ad943b1328314c0630727193a72c90 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Thu, 9 Jun 2022 18:48:50 +0000 Subject: [PATCH 19/32] [markdown] Ignore brackets inside link text (#151610) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔨 Allow texts in bracket pairs inside link titles; [text](link) Signed-off-by: GitHub * 🔨 Allow texts in bracket pairs inside link titles; [text]() Signed-off-by: GitHub * ⚗️ Add tests to verify link titles can include bracket pairs Signed-off-by: GitHub --- .../src/languageFeatures/documentLinkProvider.ts | 4 ++-- .../src/test/documentLinkProvider.test.ts | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts b/extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts index d1457dd3e2a..337872e596f 100644 --- a/extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts +++ b/extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts @@ -185,12 +185,12 @@ function stripAngleBrackets(link: string) { /** * Matches `[text](link)` */ -const linkPattern = /(\[((!\[[^\]]*?\]\(\s*)([^\s\(\)]+?)\s*\)\]|(?:\\\]|[^\]])*\])\(\s*)(([^\s\(\)]|\([^\s\(\)]*?\))+)\s*("[^"]*"|'[^']*'|\([^\(\)]*\))?\s*\)/g; +const linkPattern = /(\[((!\[[^\]]*?\]\(\s*)([^\s\(\)]+?)\s*\)\]|(?:\\\]|[^\]]|\][^(])*\])\(\s*)(([^\s\(\)]|\([^\s\(\)]*?\))+)\s*("[^"]*"|'[^']*'|\([^\(\)]*\))?\s*\)/g; /** * Matches `[text]()` */ -const linkPatternAngle = /(\[((!\[[^\]]*?\]\(\s*)([^\s\(\)]+?)\s*\)\]|(?:\\\]|[^\]])*\])\(\s*<)(([^<>]|\([^\s\(\)]*?\))+)>\s*("[^"]*"|'[^']*'|\([^\(\)]*\))?\s*\)/g; +const linkPatternAngle = /(\[((!\[[^\]]*?\]\(\s*)([^\s\(\)]+?)\s*\)\]|(?:\\\]|[^\]]|\][^(])*\])\(\s*<)(([^<>]|\([^\s\(\)]*?\))+)>\s*("[^"]*"|'[^']*'|\([^\(\)]*\))?\s*\)/g; /** diff --git a/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts b/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts index 37d9330d357..ba71ca4d559 100644 --- a/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts +++ b/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts @@ -101,6 +101,21 @@ suite('markdown.DocumentLinkProvider', () => { } }); + test('Should ignore texts in brackets inside link title (#150921)', async () => { + { + const links = await getLinksForFile('[some [inner bracket pairs] in title]()'); + assertLinksEqual(links, [ + new vscode.Range(0, 39, 0, 43), + ]); + } + { + const links = await getLinksForFile('[some [inner bracket pairs] in title](link)'); + assertLinksEqual(links, [ + new vscode.Range(0, 38, 0, 42) + ]); + } + }); + test('Should handle two links without space', async () => { const links = await getLinksForFile('a ([test](test)[test2](test2)) c'); assertLinksEqual(links, [ From fa94ddc080496a67a6011887e6bca683a72cb41d Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 9 Jun 2022 12:02:55 -0800 Subject: [PATCH 20/32] use _ for private task vars (#151637) --- .../tasks/browser/abstractTaskService.ts | 994 +++++++++--------- .../tasks/browser/runAutomaticTasks.ts | 54 +- .../tasks/browser/task.contribution.ts | 58 +- .../contrib/tasks/browser/taskQuickPick.ts | 118 +-- .../contrib/tasks/browser/taskService.ts | 8 +- .../contrib/tasks/browser/tasksQuickAccess.ts | 26 +- .../tasks/browser/terminalTaskSystem.ts | 659 ++++++------ .../tasks/electron-sandbox/taskService.ts | 16 +- 8 files changed, 967 insertions(+), 966 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 64a03a0b4ef..a8ef17894d3 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -196,7 +196,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer public static OutputChannelId: string = 'tasks'; public static OutputChannelLabel: string = nls.localize('tasks', "Tasks"); - private static nextHandle: number = 0; + private static _nextHandle: number = 0; private _schemaVersion: JsonSchemaVersion | undefined; private _executionEngine: ExecutionEngine | undefined; @@ -225,58 +225,58 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer public onDidChangeTaskSystemInfo: Event = this._onDidChangeTaskSystemInfo.event; constructor( - @IConfigurationService private readonly configurationService: IConfigurationService, - @IMarkerService protected readonly markerService: IMarkerService, - @IOutputService protected readonly outputService: IOutputService, - @IPaneCompositePartService private readonly paneCompositeService: IPaneCompositePartService, - @IViewsService private readonly viewsService: IViewsService, - @ICommandService private readonly commandService: ICommandService, - @IEditorService private readonly editorService: IEditorService, - @IFileService protected readonly fileService: IFileService, - @IWorkspaceContextService protected readonly contextService: IWorkspaceContextService, - @ITelemetryService protected readonly telemetryService: ITelemetryService, - @ITextFileService private readonly textFileService: ITextFileService, - @IModelService protected readonly modelService: IModelService, - @IExtensionService private readonly extensionService: IExtensionService, - @IQuickInputService private readonly quickInputService: IQuickInputService, - @IConfigurationResolverService protected readonly configurationResolverService: IConfigurationResolverService, - @ITerminalService private readonly terminalService: ITerminalService, - @ITerminalGroupService private readonly terminalGroupService: ITerminalGroupService, - @IStorageService private readonly storageService: IStorageService, - @IProgressService private readonly progressService: IProgressService, - @IOpenerService private readonly openerService: IOpenerService, - @IDialogService protected readonly dialogService: IDialogService, - @INotificationService private readonly notificationService: INotificationService, - @IContextKeyService protected readonly contextKeyService: IContextKeyService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @ITerminalProfileResolverService private readonly terminalProfileResolverService: ITerminalProfileResolverService, - @IPathService private readonly pathService: IPathService, - @ITextModelService private readonly textModelResolverService: ITextModelService, - @IPreferencesService private readonly preferencesService: IPreferencesService, - @IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService, - @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService, - @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, - @ILogService private readonly logService: ILogService + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IMarkerService protected readonly _markerService: IMarkerService, + @IOutputService protected readonly _outputService: IOutputService, + @IPaneCompositePartService private readonly _paneCompositeService: IPaneCompositePartService, + @IViewsService private readonly _viewsService: IViewsService, + @ICommandService private readonly _commandService: ICommandService, + @IEditorService private readonly _editorService: IEditorService, + @IFileService protected readonly _fileService: IFileService, + @IWorkspaceContextService protected readonly _contextService: IWorkspaceContextService, + @ITelemetryService protected readonly _telemetryService: ITelemetryService, + @ITextFileService private readonly _textFileService: ITextFileService, + @IModelService protected readonly _modelService: IModelService, + @IExtensionService private readonly _extensionService: IExtensionService, + @IQuickInputService private readonly _quickInputService: IQuickInputService, + @IConfigurationResolverService protected readonly _configurationResolverService: IConfigurationResolverService, + @ITerminalService private readonly _terminalService: ITerminalService, + @ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService, + @IStorageService private readonly _storageService: IStorageService, + @IProgressService private readonly _progressService: IProgressService, + @IOpenerService private readonly _openerService: IOpenerService, + @IDialogService protected readonly _dialogService: IDialogService, + @INotificationService private readonly _notificationService: INotificationService, + @IContextKeyService protected readonly _contextKeyService: IContextKeyService, + @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, + @ITerminalProfileResolverService private readonly _terminalProfileResolverService: ITerminalProfileResolverService, + @IPathService private readonly _pathService: IPathService, + @ITextModelService private readonly _textModelResolverService: ITextModelService, + @IPreferencesService private readonly _preferencesService: IPreferencesService, + @IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService, + @IWorkspaceTrustRequestService private readonly _workspaceTrustRequestService: IWorkspaceTrustRequestService, + @IWorkspaceTrustManagementService private readonly _workspaceTrustManagementService: IWorkspaceTrustManagementService, + @ILogService private readonly _logService: ILogService ) { super(); this._workspaceTasksPromise = undefined; this._taskSystem = undefined; this._taskSystemListener = undefined; - this._outputChannel = this.outputService.getChannel(AbstractTaskService.OutputChannelId)!; + this._outputChannel = this._outputService.getChannel(AbstractTaskService.OutputChannelId)!; this._providers = new Map(); this._providerTypes = new Map(); this._taskSystemInfos = new Map(); - this._register(this.contextService.onDidChangeWorkspaceFolders(() => { - let folderSetup = this.computeWorkspaceFolderSetup(); + this._register(this._contextService.onDidChangeWorkspaceFolders(() => { + let folderSetup = this._computeWorkspaceFolderSetup(); if (this.executionEngine !== folderSetup[2]) { - this.disposeTaskSystemListeners(); + this._disposeTaskSystemListeners(); this._taskSystem = undefined; } - this.updateSetup(folderSetup); - return this.updateWorkspaceTasks(TaskRunSource.FolderOpen); + this._updateSetup(folderSetup); + return this._updateWorkspaceTasks(TaskRunSource.FolderOpen); })); - this._register(this.configurationService.onDidChangeConfiguration(() => { + this._register(this._configurationService.onDidChangeConfiguration(() => { if (!this._taskSystem && !this._workspaceTasksPromise) { return; } @@ -284,16 +284,16 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this._outputChannel.clear(); } - this.setTaskLRUCacheLimit(); - return this.updateWorkspaceTasks(TaskRunSource.ConfigurationChange); + this._setTaskLRUCacheLimit(); + return this._updateWorkspaceTasks(TaskRunSource.ConfigurationChange); })); - this._taskRunningState = TASK_RUNNING_STATE.bindTo(contextKeyService); + this._taskRunningState = TASK_RUNNING_STATE.bindTo(_contextKeyService); this._onDidStateChange = this._register(new Emitter()); - this.registerCommands(); - this.configurationResolverService.contributeVariable('defaultBuildTask', async (): Promise => { - let tasks = await this.getTasksForGroup(TaskGroup.Build); + this._registerCommands(); + this._configurationResolverService.contributeVariable('defaultBuildTask', async (): Promise => { + let tasks = await this._getTasksForGroup(TaskGroup.Build); if (tasks.length > 0) { - let { none, defaults } = this.splitPerGroupType(tasks); + let { none, defaults } = this._splitPerGroupType(tasks); if (defaults.length === 1) { return defaults[0]._label; } else if (defaults.length + none.length > 0) { @@ -303,7 +303,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer let entry: ITaskQuickPickEntry | null | undefined; if (tasks && tasks.length > 0) { - entry = await this.showQuickPick(tasks, nls.localize('TaskService.pickBuildTaskForLabel', 'Select the build task (there is no default build task defined)')); + entry = await this._showQuickPick(tasks, nls.localize('TaskService.pickBuildTaskForLabel', 'Select the build task (there is no default build task defined)')); } let task: Task | undefined | null = entry ? entry.task : undefined; @@ -316,21 +316,21 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this._waitForSupportedExecutions = new Promise(resolve => { once(this._onDidRegisterSupportedExecutions.event)(() => resolve()); }); - this.upgrade(); + this._upgrade(); } public registerSupportedExecutions(custom?: boolean, shell?: boolean, process?: boolean) { if (custom !== undefined) { - const customContext = CustomExecutionSupportedContext.bindTo(this.contextKeyService); + const customContext = CustomExecutionSupportedContext.bindTo(this._contextKeyService); customContext.set(custom); } - const isVirtual = !!VirtualWorkspaceContext.getValue(this.contextKeyService); + const isVirtual = !!VirtualWorkspaceContext.getValue(this._contextKeyService); if (shell !== undefined) { - const shellContext = ShellExecutionSupportedContext.bindTo(this.contextKeyService); + const shellContext = ShellExecutionSupportedContext.bindTo(this._contextKeyService); shellContext.set(shell && !isVirtual); } if (process !== undefined) { - const processContext = ProcessExecutionSupportedContext.bindTo(this.contextKeyService); + const processContext = ProcessExecutionSupportedContext.bindTo(this._contextKeyService); processContext.set(process && !isVirtual); } this._onDidRegisterSupportedExecutions.fire(); @@ -344,12 +344,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return this.inTerminal(); } - private registerCommands(): void { + private _registerCommands(): void { CommandsRegistry.registerCommand({ id: 'workbench.action.tasks.runTask', handler: async (accessor, arg) => { - if (await this.trust()) { - this.runTaskCommand(arg); + if (await this._trust()) { + this._runTaskCommand(arg); } }, description: { @@ -364,120 +364,120 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); CommandsRegistry.registerCommand('workbench.action.tasks.reRunTask', async (accessor, arg) => { - if (await this.trust()) { - this.reRunTaskCommand(); + if (await this._trust()) { + this._reRunTaskCommand(); } }); CommandsRegistry.registerCommand('workbench.action.tasks.restartTask', async (accessor, arg) => { - if (await this.trust()) { - this.runRestartTaskCommand(arg); + if (await this._trust()) { + this._runRestartTaskCommand(arg); } }); CommandsRegistry.registerCommand('workbench.action.tasks.terminate', async (accessor, arg) => { - if (await this.trust()) { - this.runTerminateCommand(arg); + if (await this._trust()) { + this._runTerminateCommand(arg); } }); CommandsRegistry.registerCommand('workbench.action.tasks.showLog', () => { - if (!this.canRunCommand()) { + if (!this._canRunCommand()) { return; } - this.showOutput(); + this._showOutput(); }); CommandsRegistry.registerCommand('workbench.action.tasks.build', async () => { - if (!this.canRunCommand()) { + if (!this._canRunCommand()) { return; } - if (await this.trust()) { - this.runBuildCommand(); + if (await this._trust()) { + this._runBuildCommand(); } }); CommandsRegistry.registerCommand('workbench.action.tasks.test', async () => { - if (!this.canRunCommand()) { + if (!this._canRunCommand()) { return; } - if (await this.trust()) { - this.runTestCommand(); + if (await this._trust()) { + this._runTestCommand(); } }); CommandsRegistry.registerCommand('workbench.action.tasks.configureTaskRunner', async () => { - if (await this.trust()) { - this.runConfigureTasks(); + if (await this._trust()) { + this._runConfigureTasks(); } }); CommandsRegistry.registerCommand('workbench.action.tasks.configureDefaultBuildTask', async () => { - if (await this.trust()) { - this.runConfigureDefaultBuildTask(); + if (await this._trust()) { + this._runConfigureDefaultBuildTask(); } }); CommandsRegistry.registerCommand('workbench.action.tasks.configureDefaultTestTask', async () => { - if (await this.trust()) { - this.runConfigureDefaultTestTask(); + if (await this._trust()) { + this._runConfigureDefaultTestTask(); } }); CommandsRegistry.registerCommand('workbench.action.tasks.showTasks', async () => { - if (await this.trust()) { + if (await this._trust()) { return this.runShowTasks(); } }); - CommandsRegistry.registerCommand('workbench.action.tasks.toggleProblems', () => this.commandService.executeCommand(Markers.TOGGLE_MARKERS_VIEW_ACTION_ID)); + CommandsRegistry.registerCommand('workbench.action.tasks.toggleProblems', () => this._commandService.executeCommand(Markers.TOGGLE_MARKERS_VIEW_ACTION_ID)); CommandsRegistry.registerCommand('workbench.action.tasks.openUserTasks', async () => { - const resource = this.getResourceForKind(TaskSourceKind.User); + const resource = this._getResourceForKind(TaskSourceKind.User); if (resource) { - this.openTaskFile(resource, TaskSourceKind.User); + this._openTaskFile(resource, TaskSourceKind.User); } }); CommandsRegistry.registerCommand('workbench.action.tasks.openWorkspaceFileTasks', async () => { - const resource = this.getResourceForKind(TaskSourceKind.WorkspaceFile); + const resource = this._getResourceForKind(TaskSourceKind.WorkspaceFile); if (resource) { - this.openTaskFile(resource, TaskSourceKind.WorkspaceFile); + this._openTaskFile(resource, TaskSourceKind.WorkspaceFile); } }); } private get workspaceFolders(): IWorkspaceFolder[] { if (!this._workspaceFolders) { - this.updateSetup(); + this._updateSetup(); } return this._workspaceFolders!; } private get ignoredWorkspaceFolders(): IWorkspaceFolder[] { if (!this._ignoredWorkspaceFolders) { - this.updateSetup(); + this._updateSetup(); } return this._ignoredWorkspaceFolders!; } protected get executionEngine(): ExecutionEngine { if (this._executionEngine === undefined) { - this.updateSetup(); + this._updateSetup(); } return this._executionEngine!; } private get schemaVersion(): JsonSchemaVersion { if (this._schemaVersion === undefined) { - this.updateSetup(); + this._updateSetup(); } return this._schemaVersion!; } private get showIgnoreMessage(): boolean { if (this._showIgnoreMessage === undefined) { - this._showIgnoreMessage = !this.storageService.getBoolean(AbstractTaskService.IgnoreTask010DonotShowAgain_key, StorageScope.WORKSPACE, false); + this._showIgnoreMessage = !this._storageService.getBoolean(AbstractTaskService.IgnoreTask010DonotShowAgain_key, StorageScope.WORKSPACE, false); } return this._showIgnoreMessage; } @@ -500,16 +500,16 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer private async _activateTaskProviders(type: string | undefined): Promise { // We need to first wait for extensions to be registered because we might read // the `TaskDefinitionRegistry` in case `type` is `undefined` - await this.extensionService.whenInstalledExtensionsRegistered(); + await this._extensionService.whenInstalledExtensionsRegistered(); await Promise.all( - this._getActivationEvents(type).map(activationEvent => this.extensionService.activateByEvent(activationEvent)) + this._getActivationEvents(type).map(activationEvent => this._extensionService.activateByEvent(activationEvent)) ); } - private updateSetup(setup?: [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion, IWorkspace | undefined]): void { + private _updateSetup(setup?: [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion, IWorkspace | undefined]): void { if (!setup) { - setup = this.computeWorkspaceFolderSetup(); + setup = this._computeWorkspaceFolderSetup(); } this._workspaceFolders = setup[0]; if (this._ignoredWorkspaceFolders) { @@ -532,19 +532,19 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this._workspace = setup[4]; } - protected showOutput(runSource: TaskRunSource = TaskRunSource.User): void { - if (!VirtualWorkspaceContext.getValue(this.contextKeyService) && ((runSource === TaskRunSource.User) || (runSource === TaskRunSource.ConfigurationChange))) { - this.notificationService.prompt(Severity.Warning, nls.localize('taskServiceOutputPrompt', 'There are task errors. See the output for details.'), + protected _showOutput(runSource: TaskRunSource = TaskRunSource.User): void { + if (!VirtualWorkspaceContext.getValue(this._contextKeyService) && ((runSource === TaskRunSource.User) || (runSource === TaskRunSource.ConfigurationChange))) { + this._notificationService.prompt(Severity.Warning, nls.localize('taskServiceOutputPrompt', 'There are task errors. See the output for details.'), [{ label: nls.localize('showOutput', "Show output"), run: () => { - this.outputService.showChannel(this._outputChannel.id, true); + this._outputService.showChannel(this._outputChannel.id, true); } }]); } } - protected disposeTaskSystemListeners(): void { + protected _disposeTaskSystemListeners(): void { if (this._taskSystemListener) { this._taskSystemListener.dispose(); } @@ -556,7 +556,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer dispose: () => { } }; } - let handle = AbstractTaskService.nextHandle++; + let handle = AbstractTaskService._nextHandle++; this._providers.set(handle, provider); this._providerTypes.set(handle, type); return { @@ -571,7 +571,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer let infosCount = Array.from(this._taskSystemInfos.values()).flat().length; // If there's a remoteAuthority, then we end up with 2 taskSystemInfos, // one for each extension host. - if (this.environmentService.remoteAuthority) { + if (this._environmentService.remoteAuthority) { return infosCount > 1; } return infosCount > 0; @@ -600,7 +600,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } - private getTaskSystemInfo(key: string): ITaskSystemInfo | undefined { + private _getTaskSystemInfo(key: string): ITaskSystemInfo | undefined { const infos = this._taskSystemInfos.get(key); return (infos && infos.length) ? infos[0] : undefined; } @@ -651,7 +651,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } public async getTask(folder: IWorkspace | IWorkspaceFolder | string, identifier: string | ITaskIdentifier, compareId: boolean = false): Promise { - if (!(await this.trust())) { + if (!(await this._trust())) { return; } const name = Types.isString(folder) ? folder : isWorkspaceFolder(folder) ? folder.name : folder.configuration ? resources.basename(folder.configuration) : undefined; @@ -687,7 +687,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } // We didn't find the task, so we need to ask all resolvers about it - return this.getGroupedTasks().then((map) => { + return this._getGroupedTasks().then((map) => { let values = map.get(folder); values = values.concat(map.get(USER_TASKS_GROUP_KEY)); @@ -700,7 +700,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } public async tryResolveTask(configuringTask: ConfiguringTask): Promise { - if (!(await this.trust())) { + if (!(await this._trust())) { return; } await this._activateTaskProviders(configuringTask.type); @@ -709,7 +709,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer for (const [handle, provider] of this._providers) { const providerType = this._providerTypes.get(handle); if (configuringTask.type === providerType) { - if (providerType && !this.isTaskProviderEnabled(providerType)) { + if (providerType && !this._isTaskProviderEnabled(providerType)) { matchingProviderUnavailable = true; continue; } @@ -750,16 +750,16 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return; } - protected abstract versionAndEngineCompatible(filter?: ITaskFilter): boolean; + protected abstract _versionAndEngineCompatible(filter?: ITaskFilter): boolean; public async tasks(filter?: ITaskFilter): Promise { - if (!(await this.trust())) { + if (!(await this._trust())) { return []; } - if (!this.versionAndEngineCompatible(filter)) { + if (!this._versionAndEngineCompatible(filter)) { return Promise.resolve([]); } - return this.getGroupedTasks(filter ? filter.type : undefined).then((map) => { + return this._getGroupedTasks(filter ? filter.type : undefined).then((map) => { if (!filter || !filter.type) { return map.all(); } @@ -786,9 +786,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer public taskTypes(): string[] { const types: string[] = []; - if (this.isProvideTasksEnabled()) { + if (this._isProvideTasksEnabled()) { for (const definition of TaskDefinitionRegistry.all()) { - if (this.isTaskProviderEnabled(definition.taskType)) { + if (this._isTaskProviderEnabled(definition.taskType)) { types.push(definition.taskType); } } @@ -797,10 +797,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } public createSorter(): TaskSorter { - return new TaskSorter(this.contextService.getWorkspace() ? this.contextService.getWorkspace().folders : []); + return new TaskSorter(this._contextService.getWorkspace() ? this._contextService.getWorkspace().folders : []); } - private isActive(): Promise { + private _isActive(): Promise { if (!this._taskSystem) { return Promise.resolve(false); } @@ -825,10 +825,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (this._recentlyUsedTasksV1) { return this._recentlyUsedTasksV1; } - const quickOpenHistoryLimit = this.configurationService.getValue(QUICKOPEN_HISTORY_LIMIT_CONFIG); + const quickOpenHistoryLimit = this._configurationService.getValue(QUICKOPEN_HISTORY_LIMIT_CONFIG); this._recentlyUsedTasksV1 = new LRUCache(quickOpenHistoryLimit); - let storageValue = this.storageService.get(AbstractTaskService.RecentlyUsedTasks_Key, StorageScope.WORKSPACE); + let storageValue = this._storageService.get(AbstractTaskService.RecentlyUsedTasks_Key, StorageScope.WORKSPACE); if (storageValue) { try { let values: string[] = JSON.parse(storageValue); @@ -844,14 +844,14 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return this._recentlyUsedTasksV1; } - private getRecentlyUsedTasks(): LRUCache { + private _getRecentlyUsedTasks(): LRUCache { if (this._recentlyUsedTasks) { return this._recentlyUsedTasks; } - const quickOpenHistoryLimit = this.configurationService.getValue(QUICKOPEN_HISTORY_LIMIT_CONFIG); + const quickOpenHistoryLimit = this._configurationService.getValue(QUICKOPEN_HISTORY_LIMIT_CONFIG); this._recentlyUsedTasks = new LRUCache(quickOpenHistoryLimit); - let storageValue = this.storageService.get(AbstractTaskService.RecentlyUsedTasks_KeyV2, StorageScope.WORKSPACE); + let storageValue = this._storageService.get(AbstractTaskService.RecentlyUsedTasks_KeyV2, StorageScope.WORKSPACE); if (storageValue) { try { let values: [string, string][] = JSON.parse(storageValue); @@ -867,7 +867,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return this._recentlyUsedTasks; } - private getFolderFromTaskKey(key: string): { folder: string | undefined; isWorkspaceFile: boolean | undefined } { + private _getFolderFromTaskKey(key: string): { folder: string | undefined; isWorkspaceFile: boolean | undefined } { const keyValue: { folder: string | undefined; id: string | undefined } = JSON.parse(key); return { folder: keyValue.folder, isWorkspaceFile: keyValue.id?.endsWith(TaskSourceKind.WorkspaceFile) @@ -881,7 +881,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); const folderToTasksMap: Map = new Map(); const workspaceToTaskMap: Map = new Map(); - const recentlyUsedTasks = this.getRecentlyUsedTasks(); + const recentlyUsedTasks = this._getRecentlyUsedTasks(); const tasks: (Task | ConfiguringTask)[] = []; function addTaskToMap(map: Map, folder: string | undefined, task: any) { @@ -896,7 +896,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer for (const entry of recentlyUsedTasks.entries()) { const key = entry[0]; const task = JSON.parse(entry[1]); - const folderInfo = this.getFolderFromTaskKey(key); + const folderInfo = this._getFolderFromTaskKey(key); addTaskToMap(folderInfo.isWorkspaceFile ? workspaceToTaskMap : folderToTasksMap, folderInfo.folder, task); } @@ -909,7 +909,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ? (isWorkspaceFile ? TaskConfig.TaskConfigSource.WorkspaceFile : TaskConfig.TaskConfigSource.TasksJson) : TaskConfig.TaskConfigSource.User); - await that.computeTasksForSingleConfig(folderMap[key] ?? await that.getAFolder(), { + await that._computeTasksForSingleConfig(folderMap[key] ?? await that._getAFolder(), { version: '2.0.0', tasks: map.get(key) }, TaskRunSource.System, custom, customized, taskConfigSource, true); @@ -939,27 +939,27 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } public removeRecentlyUsedTask(taskRecentlyUsedKey: string) { - if (this.getRecentlyUsedTasks().has(taskRecentlyUsedKey)) { - this.getRecentlyUsedTasks().delete(taskRecentlyUsedKey); - this.saveRecentlyUsedTasks(); + if (this._getRecentlyUsedTasks().has(taskRecentlyUsedKey)) { + this._getRecentlyUsedTasks().delete(taskRecentlyUsedKey); + this._saveRecentlyUsedTasks(); } } - private setTaskLRUCacheLimit() { - const quickOpenHistoryLimit = this.configurationService.getValue(QUICKOPEN_HISTORY_LIMIT_CONFIG); + private _setTaskLRUCacheLimit() { + const quickOpenHistoryLimit = this._configurationService.getValue(QUICKOPEN_HISTORY_LIMIT_CONFIG); if (this._recentlyUsedTasks) { this._recentlyUsedTasks.limit = quickOpenHistoryLimit; } } - private async setRecentlyUsedTask(task: Task): Promise { + private async _setRecentlyUsedTask(task: Task): Promise { let key = task.getRecentlyUsedKey(); if (!InMemoryTask.is(task) && key) { - const customizations = this.createCustomizableTask(task); + const customizations = this._createCustomizableTask(task); if (ContributedTask.is(task) && customizations) { let custom: CustomTask[] = []; let customized: IStringDictionary = Object.create(null); - await this.computeTasksForSingleConfig(task._source.workspaceFolder ?? this.workspaceFolders[0], { + await this._computeTasksForSingleConfig(task._source.workspaceFolder ?? this.workspaceFolders[0], { version: '2.0.0', tasks: [customizations] }, TaskRunSource.System, custom, customized, TaskConfig.TaskConfigSource.TasksJson, true); @@ -967,16 +967,16 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer key = customized[configuration].getRecentlyUsedKey()!; } } - this.getRecentlyUsedTasks().set(key, JSON.stringify(customizations)); - this.saveRecentlyUsedTasks(); + this._getRecentlyUsedTasks().set(key, JSON.stringify(customizations)); + this._saveRecentlyUsedTasks(); } } - private saveRecentlyUsedTasks(): void { + private _saveRecentlyUsedTasks(): void { if (!this._recentlyUsedTasks) { return; } - const quickOpenHistoryLimit = this.configurationService.getValue(QUICKOPEN_HISTORY_LIMIT_CONFIG); + const quickOpenHistoryLimit = this._configurationService.getValue(QUICKOPEN_HISTORY_LIMIT_CONFIG); // setting history limit to 0 means no LRU sorting if (quickOpenHistoryLimit === 0) { return; @@ -989,11 +989,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer for (const key of keys) { keyValues.push([key, this._recentlyUsedTasks.get(key, Touch.None)!]); } - this.storageService.store(AbstractTaskService.RecentlyUsedTasks_KeyV2, JSON.stringify(keyValues), StorageScope.WORKSPACE, StorageTarget.USER); + this._storageService.store(AbstractTaskService.RecentlyUsedTasks_KeyV2, JSON.stringify(keyValues), StorageScope.WORKSPACE, StorageTarget.USER); } - private openDocumentation(): void { - this.openerService.open(URI.parse('https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher')); + private _openDocumentation(): void { + this._openerService.open(URI.parse('https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher')); } private async _findSingleWorkspaceTaskOfGroup(group: TaskGroup): Promise { @@ -1012,14 +1012,14 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return undefined; } - private async build(): Promise { + private async _build(): Promise { const tryBuildShortcut = await this._findSingleWorkspaceTaskOfGroup(TaskGroup.Build); if (tryBuildShortcut) { return tryBuildShortcut; } - return this.getGroupedTasks().then((tasks) => { - let runnable = this.createRunnableTask(tasks, TaskGroup.Build); + return this._getGroupedTasks().then((tasks) => { + let runnable = this._createRunnableTask(tasks, TaskGroup.Build); if (!runnable || !runnable.task) { if (this.schemaVersion === JsonSchemaVersion.V0_1_0) { throw new TaskError(Severity.Info, nls.localize('TaskService.noBuildTask1', 'No build task defined. Mark a task with \'isBuildCommand\' in the tasks.json file.'), TaskErrors.NoBuildTask); @@ -1027,21 +1027,21 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer throw new TaskError(Severity.Info, nls.localize('TaskService.noBuildTask2', 'No build task defined. Mark a task with as a \'build\' group in the tasks.json file.'), TaskErrors.NoBuildTask); } } - return this.executeTask(runnable.task, runnable.resolver, TaskRunSource.User); + return this._executeTask(runnable.task, runnable.resolver, TaskRunSource.User); }).then(value => value, (error) => { - this.handleError(error); + this._handleError(error); return Promise.reject(error); }); } - private async runTest(): Promise { + private async _runTest(): Promise { const tryTestShortcut = await this._findSingleWorkspaceTaskOfGroup(TaskGroup.Test); if (tryTestShortcut) { return tryTestShortcut; } - return this.getGroupedTasks().then((tasks) => { - let runnable = this.createRunnableTask(tasks, TaskGroup.Test); + return this._getGroupedTasks().then((tasks) => { + let runnable = this._createRunnableTask(tasks, TaskGroup.Test); if (!runnable || !runnable.task) { if (this.schemaVersion === JsonSchemaVersion.V0_1_0) { throw new TaskError(Severity.Info, nls.localize('TaskService.noTestTask1', 'No test task defined. Mark a task with \'isTestCommand\' in the tasks.json file.'), TaskErrors.NoTestTask); @@ -1049,15 +1049,15 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer throw new TaskError(Severity.Info, nls.localize('TaskService.noTestTask2', 'No test task defined. Mark a task with as a \'test\' group in the tasks.json file.'), TaskErrors.NoTestTask); } } - return this.executeTask(runnable.task, runnable.resolver, TaskRunSource.User); + return this._executeTask(runnable.task, runnable.resolver, TaskRunSource.User); }).then(value => value, (error) => { - this.handleError(error); + this._handleError(error); return Promise.reject(error); }); } public async run(task: Task | undefined, options?: IProblemMatcherRunOptions, runSource: TaskRunSource = TaskRunSource.System): Promise { - if (!(await this.trust())) { + if (!(await this._trust())) { return; } @@ -1066,38 +1066,38 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } return new Promise((resolve) => { - let resolver = this.createResolver(); - if (options && options.attachProblemMatcher && this.shouldAttachProblemMatcher(task) && !InMemoryTask.is(task)) { - this.attachProblemMatcher(task).then(toExecute => { + let resolver = this._createResolver(); + if (options && options.attachProblemMatcher && this._shouldAttachProblemMatcher(task) && !InMemoryTask.is(task)) { + this._attachProblemMatcher(task).then(toExecute => { if (toExecute) { - resolve(this.executeTask(toExecute, resolver, runSource)); + resolve(this._executeTask(toExecute, resolver, runSource)); } else { resolve(undefined); } }); } else { - resolve(this.executeTask(task, resolver, runSource)); + resolve(this._executeTask(task, resolver, runSource)); } }).then((value) => { if (runSource === TaskRunSource.User) { this.getWorkspaceTasks().then(workspaceTasks => { - RunAutomaticTasks.promptForPermission(this, this.storageService, this.notificationService, this.workspaceTrustManagementService, this.openerService, workspaceTasks); + RunAutomaticTasks.promptForPermission(this, this._storageService, this._notificationService, this._workspaceTrustManagementService, this._openerService, workspaceTasks); }); } return value; }, (error) => { - this.handleError(error); + this._handleError(error); return Promise.reject(error); }); } - private isProvideTasksEnabled(): boolean { - const settingValue = this.configurationService.getValue('task.autoDetect'); + private _isProvideTasksEnabled(): boolean { + const settingValue = this._configurationService.getValue('task.autoDetect'); return settingValue === 'on'; } - private isProblemMatcherPromptEnabled(type?: string): boolean { - const settingValue = this.configurationService.getValue(PROBLEM_MATCHER_NEVER_CONFIG); + private _isProblemMatcherPromptEnabled(type?: string): boolean { + const settingValue = this._configurationService.getValue(PROBLEM_MATCHER_NEVER_CONFIG); if (Types.isBoolean(settingValue)) { return !settingValue; } @@ -1108,7 +1108,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return !settingValueMap[type]; } - private getTypeForTask(task: Task): string { + private _getTypeForTask(task: Task): string { let type: string; if (CustomTask.is(task)) { let configProperties: TaskConfig.IConfigurationProperties = task._source.config.element; @@ -1119,12 +1119,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return type; } - private shouldAttachProblemMatcher(task: Task): boolean { - const enabled = this.isProblemMatcherPromptEnabled(this.getTypeForTask(task)); + private _shouldAttachProblemMatcher(task: Task): boolean { + const enabled = this._isProblemMatcherPromptEnabled(this._getTypeForTask(task)); if (enabled === false) { return false; } - if (!this.canCustomize(task)) { + if (!this._canCustomize(task)) { return false; } if (task.configurationProperties.group !== undefined && task.configurationProperties.group !== TaskGroup.Build) { @@ -1143,8 +1143,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return false; } - private async updateNeverProblemMatcherSetting(type: string): Promise { - const current = this.configurationService.getValue(PROBLEM_MATCHER_NEVER_CONFIG); + private async _updateNeverProblemMatcherSetting(type: string): Promise { + const current = this._configurationService.getValue(PROBLEM_MATCHER_NEVER_CONFIG); if (current === true) { return; } @@ -1155,10 +1155,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer newValue = Object.create(null); } newValue[type] = true; - return this.configurationService.updateValue(PROBLEM_MATCHER_NEVER_CONFIG, newValue); + return this._configurationService.updateValue(PROBLEM_MATCHER_NEVER_CONFIG, newValue); } - private attachProblemMatcher(task: ContributedTask | CustomTask): Promise { + private _attachProblemMatcher(task: ContributedTask | CustomTask): Promise { interface IProblemMatcherPickEntry extends IQuickPickItem { matcher: INamedProblemMatcher | undefined; never?: boolean; @@ -1203,12 +1203,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer { 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, { + return this._quickInputService.pick(entries, { placeHolder: nls.localize('selectProblemMatcher', 'Select for which kind of errors and warnings to scan the task output'), }).then(async (selected) => { if (selected) { if (selected.learnMore) { - this.openDocumentation(); + this._openDocumentation(); return undefined; } else if (selected.never) { this.customize(task, { problemMatcher: [] }, true); @@ -1226,7 +1226,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this.customize(task, properties, true); return newTask; } else if (selected.setting) { - await this.updateNeverProblemMatcherSetting(selected.setting); + await this._updateNeverProblemMatcherSetting(selected.setting); return task; } else { return task; @@ -1239,8 +1239,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return Promise.resolve(task); } - private getTasksForGroup(group: TaskGroup): Promise { - return this.getGroupedTasks().then((groups) => { + private _getTasksForGroup(group: TaskGroup): Promise { + return this._getGroupedTasks().then((groups) => { let result: Task[] = []; groups.forEach((tasks) => { for (let task of tasks) { @@ -1255,10 +1255,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } public needsFolderQualification(): boolean { - return this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; + return this._contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; } - private canCustomize(task: Task): boolean { + private _canCustomize(task: Task): boolean { if (this.schemaVersion !== JsonSchemaVersion.V2_0_0) { return false; } @@ -1271,11 +1271,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return false; } - private async formatTaskForJson(resource: URI, task: TaskConfig.ICustomTask | TaskConfig.IConfiguringTask): Promise { + private async _formatTaskForJson(resource: URI, task: TaskConfig.ICustomTask | TaskConfig.IConfiguringTask): Promise { let reference: IReference | undefined; let stringValue: string = ''; try { - reference = await this.textModelResolverService.createModelReference(resource); + reference = await this._textModelResolverService.createModelReference(resource); const model = reference.object.textEditorModel; const { tabSize, insertSpaces } = model.getOptions(); const eol = model.getEOL(); @@ -1292,12 +1292,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return stringValue; } - private openEditorAtTask(resource: URI | undefined, task: TaskConfig.ICustomTask | TaskConfig.IConfiguringTask | string | undefined, configIndex: number = -1): Promise { + private _openEditorAtTask(resource: URI | undefined, task: TaskConfig.ICustomTask | TaskConfig.IConfiguringTask | string | undefined, configIndex: number = -1): Promise { if (resource === undefined) { return Promise.resolve(false); } let selection: ITextEditorSelection | undefined; - return this.fileService.readFile(resource).then(content => content.value).then(async content => { + return this._fileService.readFile(resource).then(content => content.value).then(async content => { if (!content) { return false; } @@ -1305,16 +1305,16 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer const contentValue = content.toString(); let stringValue: string | undefined; if (configIndex !== -1) { - const json: TaskConfig.IExternalTaskRunnerConfiguration = this.configurationService.getValue('tasks', { resource }); + const json: TaskConfig.IExternalTaskRunnerConfiguration = this._configurationService.getValue('tasks', { resource }); if (json.tasks && (json.tasks.length > configIndex)) { - stringValue = await this.formatTaskForJson(resource, json.tasks[configIndex]); + stringValue = await this._formatTaskForJson(resource, json.tasks[configIndex]); } } if (!stringValue) { if (typeof task === 'string') { stringValue = task; } else { - stringValue = await this.formatTaskForJson(resource, task); + stringValue = await this._formatTaskForJson(resource, task); } } @@ -1334,7 +1334,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer selection = startLineNumber > 1 ? { startLineNumber, startColumn: startLineNumber === endLineNumber ? 4 : 3, endLineNumber, endColumn: startLineNumber === endLineNumber ? undefined : 4 } : undefined; } - return this.editorService.openEditor({ + return this._editorService.openEditor({ resource, options: { pinned: false, @@ -1346,7 +1346,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); } - private createCustomizableTask(task: ContributedTask | CustomTask | ConfiguringTask): TaskConfig.ICustomTask | TaskConfig.IConfiguringTask | undefined { + private _createCustomizableTask(task: ContributedTask | CustomTask | ConfiguringTask): TaskConfig.ICustomTask | TaskConfig.IConfiguringTask | undefined { let toCustomize: TaskConfig.ICustomTask | TaskConfig.IConfiguringTask | undefined; let taskConfig = CustomTask.is(task) || ConfiguringTask.is(task) ? task._source.config : undefined; if (taskConfig && taskConfig.element) { @@ -1380,7 +1380,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } public async customize(task: ContributedTask | CustomTask | ConfiguringTask, properties?: ICustomizationProperties, openConfig?: boolean): Promise { - if (!(await this.trust())) { + if (!(await this._trust())) { return; } @@ -1388,14 +1388,14 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (!workspaceFolder) { return Promise.resolve(undefined); } - let configuration = this.getConfiguration(workspaceFolder, task._source.kind); + let configuration = this._getConfiguration(workspaceFolder, task._source.kind); if (configuration.hasParseErrors) { - this.notificationService.warn(nls.localize('customizeParseErrors', 'The current task configuration has errors. Please fix the errors first before customizing a task.')); + this._notificationService.warn(nls.localize('customizeParseErrors', 'The current task configuration has errors. Please fix the errors first before customizing a task.')); return Promise.resolve(undefined); } let fileConfig = configuration.config; - const toCustomize = this.createCustomizableTask(task); + const toCustomize = this._createCustomizableTask(task); if (!toCustomize) { return Promise.resolve(undefined); } @@ -1419,20 +1419,20 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer '{', nls.localize('tasksJsonComment', '\t// See https://go.microsoft.com/fwlink/?LinkId=733558 \n\t// for the documentation about the tasks.json format'), ].join('\n') + JSON.stringify(value, null, '\t').substr(1); - let editorConfig = this.configurationService.getValue(); + let editorConfig = this._configurationService.getValue(); if (editorConfig.editor.insertSpaces) { content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + ' '.repeat(s2.length * editorConfig.editor.tabSize)); } - promise = this.textFileService.create([{ resource: workspaceFolder.toResource('.vscode/tasks.json'), value: content }]).then(() => { }); + promise = this._textFileService.create([{ resource: workspaceFolder.toResource('.vscode/tasks.json'), value: content }]).then(() => { }); } else { // We have a global task configuration if ((index === -1) && properties) { if (properties.problemMatcher !== undefined) { fileConfig.problemMatcher = properties.problemMatcher; - promise = this.writeConfiguration(workspaceFolder, 'tasks.problemMatchers', fileConfig.problemMatcher, task._source.kind); + promise = this._writeConfiguration(workspaceFolder, 'tasks.problemMatchers', fileConfig.problemMatcher, task._source.kind); } else if (properties.group !== undefined) { fileConfig.group = properties.group; - promise = this.writeConfiguration(workspaceFolder, 'tasks.group', fileConfig.group, task._source.kind); + promise = this._writeConfiguration(workspaceFolder, 'tasks.group', fileConfig.group, task._source.kind); } } else { if (!Array.isArray(fileConfig.tasks)) { @@ -1443,7 +1443,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } else { fileConfig.tasks[index] = toCustomize; } - promise = this.writeConfiguration(workspaceFolder, 'tasks.tasks', fileConfig.tasks, task._source.kind); + promise = this._writeConfiguration(workspaceFolder, 'tasks.tasks', fileConfig.tasks, task._source.kind); } } if (!promise) { @@ -1451,34 +1451,34 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } return promise.then(() => { if (openConfig) { - this.openEditorAtTask(this.getResourceForTask(task), toCustomize); + this._openEditorAtTask(this._getResourceForTask(task), toCustomize); } }); } - private writeConfiguration(workspaceFolder: IWorkspaceFolder, key: string, value: any, source?: string): Promise | undefined { + private _writeConfiguration(workspaceFolder: IWorkspaceFolder, key: string, value: any, source?: string): Promise | undefined { let target: ConfigurationTarget | undefined = undefined; switch (source) { case TaskSourceKind.User: target = ConfigurationTarget.USER; break; case TaskSourceKind.WorkspaceFile: target = ConfigurationTarget.WORKSPACE; break; - default: if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + default: if (this._contextService.getWorkbenchState() === WorkbenchState.FOLDER) { target = ConfigurationTarget.WORKSPACE; - } else if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { + } else if (this._contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { target = ConfigurationTarget.WORKSPACE_FOLDER; } } if (target) { - return this.configurationService.updateValue(key, value, { resource: workspaceFolder.uri }, target); + return this._configurationService.updateValue(key, value, { resource: workspaceFolder.uri }, target); } else { return undefined; } } - private getResourceForKind(kind: string): URI | undefined { - this.updateSetup(); + private _getResourceForKind(kind: string): URI | undefined { + this._updateSetup(); switch (kind) { case TaskSourceKind.User: { - return resources.joinPath(resources.dirname(this.preferencesService.userSettingsResource), 'tasks.json'); + return resources.joinPath(resources.dirname(this._preferencesService.userSettingsResource), 'tasks.json'); } case TaskSourceKind.WorkspaceFile: { if (this._workspace && this._workspace.configuration) { @@ -1491,9 +1491,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } - private getResourceForTask(task: CustomTask | ConfiguringTask | ContributedTask): URI { + private _getResourceForTask(task: CustomTask | ConfiguringTask | ContributedTask): URI { if (CustomTask.is(task)) { - let uri = this.getResourceForKind(task._source.kind); + let uri = this._getResourceForKind(task._source.kind); if (!uri) { const taskFolder = task.getWorkspaceFolder(); if (taskFolder) { @@ -1511,14 +1511,14 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer public async openConfig(task: CustomTask | ConfiguringTask | undefined): Promise { let resource: URI | undefined; if (task) { - resource = this.getResourceForTask(task); + resource = this._getResourceForTask(task); } else { resource = (this._workspaceFolders && (this._workspaceFolders.length > 0)) ? this._workspaceFolders[0].toResource('.vscode/tasks.json') : undefined; } - return this.openEditorAtTask(resource, task ? task._label : undefined, task ? task._source.config.index : -1); + return this._openEditorAtTask(resource, task ? task._label : undefined, task ? task._source.config.index : -1); } - private createRunnableTask(tasks: TaskMap, group: TaskGroup): { task: Task; resolver: ITaskResolver } | undefined { + private _createRunnableTask(tasks: TaskMap, group: TaskGroup): { task: Task; resolver: ITaskResolver } | undefined { interface IResolverData { id: Map; label: Map; @@ -1594,7 +1594,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } - private createResolver(grouped?: TaskMap): ITaskResolver { + private _createResolver(grouped?: TaskMap): ITaskResolver { interface ResolverData { label: Map; identifier: Map; @@ -1631,7 +1631,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer async function getResolverData(that: AbstractTaskService) { if (resolverData === undefined) { resolverData = new Map(); - (grouped || await that.getGroupedTasks()).forEach((tasks, folder) => { + (grouped || await that._getGroupedTasks()).forEach((tasks, folder) => { let data = resolverData!.get(folder); if (!data) { data = { label: new Map(), identifier: new Map(), taskIdentifier: new Map() }; @@ -1680,19 +1680,19 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }; } - private async saveBeforeRun(): Promise { + private async _saveBeforeRun(): Promise { enum SaveBeforeRunConfigOptions { Always = 'always', Never = 'never', Prompt = 'prompt' } - const saveBeforeRunTaskConfig: SaveBeforeRunConfigOptions = this.configurationService.getValue('task.saveBeforeRun'); + const saveBeforeRunTaskConfig: SaveBeforeRunConfigOptions = this._configurationService.getValue('task.saveBeforeRun'); if (saveBeforeRunTaskConfig === SaveBeforeRunConfigOptions.Never) { return false; } else if (saveBeforeRunTaskConfig === SaveBeforeRunConfigOptions.Prompt) { - const dialogOptions = await this.dialogService.show( + const dialogOptions = await this._dialogService.show( Severity.Info, nls.localize('TaskSystem.saveBeforeRun.prompt.title', 'Save all editors?'), [nls.localize('saveBeforeRun.save', 'Save'), nls.localize('saveBeforeRun.dontSave', 'Don\'t save')], @@ -1706,15 +1706,15 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return false; } } - await this.editorService.saveAll({ reason: SaveReason.AUTO }); + await this._editorService.saveAll({ reason: SaveReason.AUTO }); return true; } - private async executeTask(task: Task, resolver: ITaskResolver, runSource: TaskRunSource): Promise { + private async _executeTask(task: Task, resolver: ITaskResolver, runSource: TaskRunSource): Promise { let taskToRun: Task = task; - if (await this.saveBeforeRun()) { - await this.configurationService.reloadConfiguration(); - await this.updateWorkspaceTasks(); + if (await this._saveBeforeRun()) { + await this._configurationService.reloadConfiguration(); + await this._updateWorkspaceTasks(); const taskFolder = task.getWorkspaceFolder(); const taskIdentifier = task.configurationProperties.identifier; // Since we save before running tasks, the task may have changed as part of the save. @@ -1724,28 +1724,28 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ? await this.getTask(taskFolder, taskIdentifier) : task) ?? task; } await ProblemMatcherRegistry.onReady(); - let executeResult = this.getTaskSystem().run(taskToRun, resolver); - return this.handleExecuteResult(executeResult, runSource); + let executeResult = this._getTaskSystem().run(taskToRun, resolver); + return this._handleExecuteResult(executeResult, runSource); } - private async handleExecuteResult(executeResult: ITaskExecuteResult, runSource?: TaskRunSource): Promise { + private async _handleExecuteResult(executeResult: ITaskExecuteResult, runSource?: TaskRunSource): Promise { if (runSource === TaskRunSource.User) { - await this.setRecentlyUsedTask(executeResult.task); + await this._setRecentlyUsedTask(executeResult.task); } if (executeResult.kind === TaskExecuteKind.Active) { let active = executeResult.active; if (active && active.same) { if (this._taskSystem?.isTaskVisible(executeResult.task)) { const message = nls.localize('TaskSystem.activeSame.noBackground', 'The task \'{0}\' is already active.', executeResult.task.getQualifiedLabel()); - let lastInstance = this.getTaskSystem().getLastInstance(executeResult.task) ?? executeResult.task; - this.notificationService.prompt(Severity.Warning, message, + let lastInstance = this._getTaskSystem().getLastInstance(executeResult.task) ?? executeResult.task; + this._notificationService.prompt(Severity.Warning, message, [{ label: nls.localize('terminateTask', "Terminate Task"), run: () => this.terminate(lastInstance) }, { label: nls.localize('restartTask', "Restart Task"), - run: () => this.restart(lastInstance) + run: () => this._restart(lastInstance) }], { sticky: true } ); @@ -1759,7 +1759,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return executeResult.promise; } - private restart(task: Task): void { + private _restart(task: Task): void { if (!this._taskSystem) { return; } @@ -1769,14 +1769,14 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer // eat the error, it has already been surfaced to the user and we don't care about it here }); } else { - this.notificationService.warn(nls.localize('TaskSystem.restartFailed', 'Failed to terminate and restart task {0}', Types.isString(task) ? task : task.configurationProperties.name)); + this._notificationService.warn(nls.localize('TaskSystem.restartFailed', 'Failed to terminate and restart task {0}', Types.isString(task) ? task : task.configurationProperties.name)); } return response; }); } public async terminate(task: Task): Promise { - if (!(await this.trust())) { + if (!(await this._trust())) { return { success: true, task: undefined }; } @@ -1786,24 +1786,24 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return this._taskSystem.terminate(task); } - private terminateAll(): Promise { + private _terminateAll(): Promise { if (!this._taskSystem) { return Promise.resolve([]); } return this._taskSystem.terminateAll(); } - protected createTerminalTaskSystem(): ITaskSystem { + protected _createTerminalTaskSystem(): ITaskSystem { return new TerminalTaskSystem( - this.terminalService, this.terminalGroupService, this.outputService, this.paneCompositeService, this.viewsService, this.markerService, - this.modelService, this.configurationResolverService, - this.contextService, this.environmentService, - AbstractTaskService.OutputChannelId, this.fileService, this.terminalProfileResolverService, - this.pathService, this.viewDescriptorService, this.logService, this.configurationService, this.notificationService, + this._terminalService, this._terminalGroupService, this._outputService, this._paneCompositeService, this._viewsService, this._markerService, + this._modelService, this._configurationResolverService, + this._contextService, this._environmentService, + AbstractTaskService.OutputChannelId, this._fileService, this._terminalProfileResolverService, + this._pathService, this._viewDescriptorService, this._logService, this._configurationService, this._notificationService, this, (workspaceFolder: IWorkspaceFolder | undefined) => { if (workspaceFolder) { - return this.getTaskSystemInfo(workspaceFolder.uri.scheme); + return this._getTaskSystemInfo(workspaceFolder.uri.scheme); } else if (this._taskSystemInfos.size > 0) { const infos = Array.from(this._taskSystemInfos.entries()); const notFile = infos.filter(info => info[0] !== Schemas.file); @@ -1818,15 +1818,15 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ); } - protected abstract getTaskSystem(): ITaskSystem; + protected abstract _getTaskSystem(): ITaskSystem; - private isTaskProviderEnabled(type: string) { + private _isTaskProviderEnabled(type: string) { const definition = TaskDefinitionRegistry.get(type); - return !definition || !definition.when || this.contextKeyService.contextMatchesRules(definition.when); + return !definition || !definition.when || this._contextKeyService.contextMatchesRules(definition.when); } - private getGroupedTasks(type?: string): Promise { - const needsRecentTasksMigration = this.needsRecentTasksMigration(); + private _getGroupedTasks(type?: string): Promise { + const needsRecentTasksMigration = this._needsRecentTasksMigration(); return this._activateTaskProviders(type).then(() => { let validTypes: IStringDictionary = Object.create(null); TaskDefinitionRegistry.all().forEach(definition => validTypes[definition.taskType] = true); @@ -1849,10 +1849,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this._outputChannel.append('Error: '); this._outputChannel.append(error.message); this._outputChannel.append('\n'); - this.showOutput(); + this._showOutput(); } else { this._outputChannel.append('Unknown error received while collecting tasks from providers.\n'); - this.showOutput(); + this._showOutput(); } } finally { if (--counter === 0) { @@ -1860,12 +1860,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } }; - if (this.isProvideTasksEnabled() && (this.schemaVersion === JsonSchemaVersion.V2_0_0) && (this._providers.size > 0)) { + if (this._isProvideTasksEnabled() && (this.schemaVersion === JsonSchemaVersion.V2_0_0) && (this._providers.size > 0)) { let foundAnyProviders = false; for (const [handle, provider] of this._providers) { const providerType = this._providerTypes.get(handle); if ((type === undefined) || (type === providerType)) { - if (providerType && !this.isTaskProviderEnabled(providerType)) { + if (providerType && !this._isTaskProviderEnabled(providerType)) { continue; } foundAnyProviders = true; @@ -1876,7 +1876,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (task.type !== this._providerTypes.get(handle)) { this._outputChannel.append(nls.localize('unexpectedTaskType', "The task provider for \"{0}\" tasks unexpectedly provided a task of type \"{1}\".\n", this._providerTypes.get(handle), task.type)); if ((task.type !== 'shell') && (task.type !== 'process')) { - this.showOutput(); + this._showOutput(); } break; } @@ -1916,11 +1916,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return; } - if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + if (this._contextService.getWorkbenchState() === WorkbenchState.EMPTY) { result.add(key, ...folderTasks.set.tasks); } else { let configurations = folderTasks.configurations; - let legacyTaskConfigurations = folderTasks.set ? this.getLegacyTaskConfigurations(folderTasks.set) : undefined; + let legacyTaskConfigurations = folderTasks.set ? this._getLegacyTaskConfigurations(folderTasks.set) : undefined; let customTasksToDelete: Task[] = []; if (configurations || legacyTaskConfigurations) { let unUsedConfigurations: Set = new Set(); @@ -1979,7 +1979,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer for (const [handle, provider] of this._providers) { const providerType = this._providerTypes.get(handle); if (configuringTask.type === providerType) { - if (providerType && !this.isTaskProviderEnabled(providerType)) { + if (providerType && !this._isTaskProviderEnabled(providerType)) { requiredTaskProviderUnavailable = true; continue; } @@ -2009,7 +2009,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer configuringTask.configures.type, JSON.stringify(configuringTask._source.config.element, undefined, 4) )); - this.showOutput(); + this._showOutput(); } }); @@ -2024,7 +2024,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer await Promise.all(customTasksPromises); if (needsRecentTasksMigration) { // At this point we have all the tasks and can migrate the recently used tasks. - await this.migrateRecentTasks(result.all()); + await this._migrateRecentTasks(result.all()); } return result; }, () => { @@ -2043,7 +2043,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); } - private getLegacyTaskConfigurations(workspaceTasks: ITaskSet): IStringDictionary | undefined { + private _getLegacyTaskConfigurations(workspaceTasks: ITaskSet): IStringDictionary | undefined { let result: IStringDictionary | undefined; function getResult(): IStringDictionary { if (result) { @@ -2070,34 +2070,34 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } public async getWorkspaceTasks(runSource: TaskRunSource = TaskRunSource.User): Promise> { - if (!(await this.trust())) { + if (!(await this._trust())) { return new Map(); } await this._waitForSupportedExecutions; if (this._workspaceTasksPromise) { return this._workspaceTasksPromise; } - return this.updateWorkspaceTasks(runSource); + return this._updateWorkspaceTasks(runSource); } - private updateWorkspaceTasks(runSource: TaskRunSource = TaskRunSource.User): Promise> { - this._workspaceTasksPromise = this.computeWorkspaceTasks(runSource); + private _updateWorkspaceTasks(runSource: TaskRunSource = TaskRunSource.User): Promise> { + this._workspaceTasksPromise = this._computeWorkspaceTasks(runSource); return this._workspaceTasksPromise; } - private async getAFolder(): Promise { + private async _getAFolder(): Promise { let folder = this.workspaceFolders.length > 0 ? this.workspaceFolders[0] : undefined; if (!folder) { - const userhome = await this.pathService.userHome(); + const userhome = await this._pathService.userHome(); folder = new WorkspaceFolder({ uri: userhome, name: resources.basename(userhome), index: 0 }); } return folder; } - protected computeWorkspaceTasks(runSource: TaskRunSource = TaskRunSource.User): Promise> { + protected _computeWorkspaceTasks(runSource: TaskRunSource = TaskRunSource.User): Promise> { let promises: Promise[] = []; for (let folder of this.workspaceFolders) { - promises.push(this.computeWorkspaceFolderTasks(folder, runSource).then((value) => value, () => undefined)); + promises.push(this._computeWorkspaceFolderTasks(folder, runSource).then((value) => value, () => undefined)); } return Promise.all(promises).then(async (values) => { let result = new Map(); @@ -2107,15 +2107,15 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } - const folder = await this.getAFolder(); - if (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY) { - const workspaceFileTasks = await this.computeWorkspaceFileTasks(folder, runSource).then((value) => value, () => undefined); + const folder = await this._getAFolder(); + if (this._contextService.getWorkbenchState() !== WorkbenchState.EMPTY) { + const workspaceFileTasks = await this._computeWorkspaceFileTasks(folder, runSource).then((value) => value, () => undefined); if (workspaceFileTasks && this._workspace && this._workspace.configuration) { result.set(this._workspace.configuration.toString(), workspaceFileTasks); } } - const userTasks = await this.computeUserTasks(folder, runSource).then((value) => value, () => undefined); + const userTasks = await this._computeUserTasks(folder, runSource).then((value) => value, () => undefined); if (userTasks) { result.set(USER_TASKS_GROUP_KEY, userTasks); } @@ -2123,26 +2123,26 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); } - private get jsonTasksSupported(): boolean { - return !!ShellExecutionSupportedContext.getValue(this.contextKeyService) && !!ProcessExecutionSupportedContext.getValue(this.contextKeyService); + private get _jsonTasksSupported(): boolean { + return !!ShellExecutionSupportedContext.getValue(this._contextKeyService) && !!ProcessExecutionSupportedContext.getValue(this._contextKeyService); } - private computeWorkspaceFolderTasks(workspaceFolder: IWorkspaceFolder, runSource: TaskRunSource = TaskRunSource.User): Promise { - return (this.executionEngine === ExecutionEngine.Process - ? this.computeLegacyConfiguration(workspaceFolder) - : this.computeConfiguration(workspaceFolder)). + private _computeWorkspaceFolderTasks(workspaceFolder: IWorkspaceFolder, runSource: TaskRunSource = TaskRunSource.User): Promise { + return (this._executionEngine === ExecutionEngine.Process + ? this._computeLegacyConfiguration(workspaceFolder) + : this._computeConfiguration(workspaceFolder)). then((workspaceFolderConfiguration) => { if (!workspaceFolderConfiguration || !workspaceFolderConfiguration.config || workspaceFolderConfiguration.hasErrors) { return Promise.resolve({ workspaceFolder, set: undefined, configurations: undefined, hasErrors: workspaceFolderConfiguration ? workspaceFolderConfiguration.hasErrors : false }); } return ProblemMatcherRegistry.onReady().then(async (): Promise => { - let taskSystemInfo: ITaskSystemInfo | undefined = this.getTaskSystemInfo(workspaceFolder.uri.scheme); + let taskSystemInfo: ITaskSystemInfo | undefined = this._getTaskSystemInfo(workspaceFolder.uri.scheme); let problemReporter = new ProblemReporter(this._outputChannel); - let parseResult = TaskConfig.parse(workspaceFolder, undefined, taskSystemInfo ? taskSystemInfo.platform : Platform.platform, workspaceFolderConfiguration.config!, problemReporter, TaskConfig.TaskConfigSource.TasksJson, this.contextKeyService); + let parseResult = TaskConfig.parse(workspaceFolder, undefined, taskSystemInfo ? taskSystemInfo.platform : Platform.platform, workspaceFolderConfiguration.config!, problemReporter, TaskConfig.TaskConfigSource.TasksJson, this._contextKeyService); let hasErrors = false; if (!parseResult.validationStatus.isOK() && (parseResult.validationStatus.state !== ValidationState.Info)) { hasErrors = true; - this.showOutput(runSource); + this._showOutput(runSource); } if (problemReporter.status.isFatal()) { problemReporter.fatal(nls.localize('TaskSystem.configurationErrors', 'Error: the provided task configuration has validation errors and can\'t not be used. Please correct the errors first.')); @@ -2157,15 +2157,15 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer customizedTasks.byIdentifier[task.configures._key] = task; } } - if (!this.jsonTasksSupported && (parseResult.custom.length > 0)) { + if (!this._jsonTasksSupported && (parseResult.custom.length > 0)) { console.warn('Custom workspace tasks are not supported.'); } - return { workspaceFolder, set: { tasks: this.jsonTasksSupported ? parseResult.custom : [] }, configurations: customizedTasks, hasErrors }; + return { workspaceFolder, set: { tasks: this._jsonTasksSupported ? parseResult.custom : [] }, configurations: customizedTasks, hasErrors }; }); }); } - private testParseExternalConfig(config: TaskConfig.IExternalTaskRunnerConfiguration | undefined, location: string): { config: TaskConfig.IExternalTaskRunnerConfiguration | undefined; hasParseErrors: boolean } { + private _testParseExternalConfig(config: TaskConfig.IExternalTaskRunnerConfiguration | undefined, location: string): { config: TaskConfig.IExternalTaskRunnerConfiguration | undefined; hasParseErrors: boolean } { if (!config) { return { config: undefined, hasParseErrors: false }; } @@ -2180,67 +2180,67 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } if (isAffected) { this._outputChannel.append(nls.localize({ key: 'TaskSystem.invalidTaskJsonOther', comment: ['Message notifies of an error in one of several places there is tasks related json, not necessarily in a file named tasks.json'] }, 'Error: The content of the tasks json in {0} has syntax errors. Please correct them before executing a task.\n', location)); - this.showOutput(); + this._showOutput(); return { config, hasParseErrors: true }; } } return { config, hasParseErrors: false }; } - private async computeWorkspaceFileTasks(workspaceFolder: IWorkspaceFolder, runSource: TaskRunSource = TaskRunSource.User): Promise { - if (this.executionEngine === ExecutionEngine.Process) { - return this.emptyWorkspaceTaskResults(workspaceFolder); + private async _computeWorkspaceFileTasks(workspaceFolder: IWorkspaceFolder, runSource: TaskRunSource = TaskRunSource.User): Promise { + if (this._executionEngine === ExecutionEngine.Process) { + return this._emptyWorkspaceTaskResults(workspaceFolder); } - const workspaceFileConfig = this.getConfiguration(workspaceFolder, TaskSourceKind.WorkspaceFile); - const configuration = this.testParseExternalConfig(workspaceFileConfig.config, nls.localize('TasksSystem.locationWorkspaceConfig', 'workspace file')); + const workspaceFileConfig = this._getConfiguration(workspaceFolder, TaskSourceKind.WorkspaceFile); + const configuration = this._testParseExternalConfig(workspaceFileConfig.config, nls.localize('TasksSystem.locationWorkspaceConfig', 'workspace file')); let customizedTasks: { byIdentifier: IStringDictionary } = { byIdentifier: Object.create(null) }; const custom: CustomTask[] = []; - await this.computeTasksForSingleConfig(workspaceFolder, configuration.config, runSource, custom, customizedTasks.byIdentifier, TaskConfig.TaskConfigSource.WorkspaceFile); + await this._computeTasksForSingleConfig(workspaceFolder, configuration.config, runSource, custom, customizedTasks.byIdentifier, TaskConfig.TaskConfigSource.WorkspaceFile); const engine = configuration.config ? TaskConfig.ExecutionEngine.from(configuration.config) : ExecutionEngine.Terminal; if (engine === ExecutionEngine.Process) { - this.notificationService.warn(nls.localize('TaskSystem.versionWorkspaceFile', 'Only tasks version 2.0.0 permitted in workspace configuration files.')); - return this.emptyWorkspaceTaskResults(workspaceFolder); + this._notificationService.warn(nls.localize('TaskSystem.versionWorkspaceFile', 'Only tasks version 2.0.0 permitted in workspace configuration files.')); + return this._emptyWorkspaceTaskResults(workspaceFolder); } return { workspaceFolder, set: { tasks: custom }, configurations: customizedTasks, hasErrors: configuration.hasParseErrors }; } - private async computeUserTasks(workspaceFolder: IWorkspaceFolder, runSource: TaskRunSource = TaskRunSource.User): Promise { - if (this.executionEngine === ExecutionEngine.Process) { - return this.emptyWorkspaceTaskResults(workspaceFolder); + private async _computeUserTasks(workspaceFolder: IWorkspaceFolder, runSource: TaskRunSource = TaskRunSource.User): Promise { + if (this._executionEngine === ExecutionEngine.Process) { + return this._emptyWorkspaceTaskResults(workspaceFolder); } - const userTasksConfig = this.getConfiguration(workspaceFolder, TaskSourceKind.User); - const configuration = this.testParseExternalConfig(userTasksConfig.config, nls.localize('TasksSystem.locationUserConfig', 'user settings')); + const userTasksConfig = this._getConfiguration(workspaceFolder, TaskSourceKind.User); + const configuration = this._testParseExternalConfig(userTasksConfig.config, nls.localize('TasksSystem.locationUserConfig', 'user settings')); let customizedTasks: { byIdentifier: IStringDictionary } = { byIdentifier: Object.create(null) }; const custom: CustomTask[] = []; - await this.computeTasksForSingleConfig(workspaceFolder, configuration.config, runSource, custom, customizedTasks.byIdentifier, TaskConfig.TaskConfigSource.User); + await this._computeTasksForSingleConfig(workspaceFolder, configuration.config, runSource, custom, customizedTasks.byIdentifier, TaskConfig.TaskConfigSource.User); const engine = configuration.config ? TaskConfig.ExecutionEngine.from(configuration.config) : ExecutionEngine.Terminal; if (engine === ExecutionEngine.Process) { - this.notificationService.warn(nls.localize('TaskSystem.versionSettings', 'Only tasks version 2.0.0 permitted in user settings.')); - return this.emptyWorkspaceTaskResults(workspaceFolder); + this._notificationService.warn(nls.localize('TaskSystem.versionSettings', 'Only tasks version 2.0.0 permitted in user settings.')); + return this._emptyWorkspaceTaskResults(workspaceFolder); } return { workspaceFolder, set: { tasks: custom }, configurations: customizedTasks, hasErrors: configuration.hasParseErrors }; } - private emptyWorkspaceTaskResults(workspaceFolder: IWorkspaceFolder): IWorkspaceFolderTaskResult { + private _emptyWorkspaceTaskResults(workspaceFolder: IWorkspaceFolder): IWorkspaceFolderTaskResult { return { workspaceFolder, set: undefined, configurations: undefined, hasErrors: false }; } - private async computeTasksForSingleConfig(workspaceFolder: IWorkspaceFolder, config: TaskConfig.IExternalTaskRunnerConfiguration | undefined, runSource: TaskRunSource, custom: CustomTask[], customized: IStringDictionary, source: TaskConfig.TaskConfigSource, isRecentTask: boolean = false): Promise { + private async _computeTasksForSingleConfig(workspaceFolder: IWorkspaceFolder, config: TaskConfig.IExternalTaskRunnerConfiguration | undefined, runSource: TaskRunSource, custom: CustomTask[], customized: IStringDictionary, source: TaskConfig.TaskConfigSource, isRecentTask: boolean = false): Promise { if (!config) { return false; } - let taskSystemInfo: ITaskSystemInfo | undefined = workspaceFolder ? this.getTaskSystemInfo(workspaceFolder.uri.scheme) : undefined; + let taskSystemInfo: ITaskSystemInfo | undefined = workspaceFolder ? this._getTaskSystemInfo(workspaceFolder.uri.scheme) : undefined; let problemReporter = new ProblemReporter(this._outputChannel); - let parseResult = TaskConfig.parse(workspaceFolder, this._workspace, taskSystemInfo ? taskSystemInfo.platform : Platform.platform, config, problemReporter, source, this.contextKeyService, isRecentTask); + let parseResult = TaskConfig.parse(workspaceFolder, this._workspace, taskSystemInfo ? taskSystemInfo.platform : Platform.platform, config, problemReporter, source, this._contextKeyService, isRecentTask); let hasErrors = false; if (!parseResult.validationStatus.isOK() && (parseResult.validationStatus.state !== ValidationState.Info)) { - this.showOutput(runSource); + this._showOutput(runSource); hasErrors = true; } if (problemReporter.status.isFatal()) { @@ -2252,7 +2252,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer customized[task.configures._key] = task; } } - if (!this.jsonTasksSupported && (parseResult.custom.length > 0)) { + if (!this._jsonTasksSupported && (parseResult.custom.length > 0)) { console.warn('Custom workspace tasks are not supported.'); } else { for (let task of parseResult.custom) { @@ -2262,23 +2262,23 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return hasErrors; } - private computeConfiguration(workspaceFolder: IWorkspaceFolder): Promise { - let { config, hasParseErrors } = this.getConfiguration(workspaceFolder); + private _computeConfiguration(workspaceFolder: IWorkspaceFolder): Promise { + let { config, hasParseErrors } = this._getConfiguration(workspaceFolder); return Promise.resolve({ workspaceFolder, config, hasErrors: hasParseErrors }); } - protected abstract computeLegacyConfiguration(workspaceFolder: IWorkspaceFolder): Promise; + protected abstract _computeLegacyConfiguration(workspaceFolder: IWorkspaceFolder): Promise; - private computeWorkspaceFolderSetup(): [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion, IWorkspace | undefined] { + private _computeWorkspaceFolderSetup(): [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion, IWorkspace | undefined] { let workspaceFolders: IWorkspaceFolder[] = []; let ignoredWorkspaceFolders: IWorkspaceFolder[] = []; let executionEngine = ExecutionEngine.Terminal; let schemaVersion = JsonSchemaVersion.V2_0_0; let workspace: IWorkspace | undefined; - if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { - let workspaceFolder: IWorkspaceFolder = this.contextService.getWorkspace().folders[0]; + if (this._contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + let workspaceFolder: IWorkspaceFolder = this._contextService.getWorkspace().folders[0]; workspaceFolders.push(workspaceFolder); - executionEngine = this.computeExecutionEngine(workspaceFolder); + executionEngine = this._computeExecutionEngine(workspaceFolder); const telemetryData: { [key: string]: any } = { executionEngineVersion: executionEngine }; @@ -2289,12 +2289,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer "executionEngineVersion" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "The engine version of tasks." } } */ - this.telemetryService.publicLog('taskService.engineVersion', telemetryData); - schemaVersion = this.computeJsonSchemaVersion(workspaceFolder); - } else if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { - workspace = this.contextService.getWorkspace(); - for (let workspaceFolder of this.contextService.getWorkspace().folders) { - if (schemaVersion === this.computeJsonSchemaVersion(workspaceFolder)) { + this._telemetryService.publicLog('taskService.engineVersion', telemetryData); + schemaVersion = this._computeJsonSchemaVersion(workspaceFolder); + } else if (this._contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { + workspace = this._contextService.getWorkspace(); + for (let workspaceFolder of this._contextService.getWorkspace().folders) { + if (schemaVersion === this._computeJsonSchemaVersion(workspaceFolder)) { workspaceFolders.push(workspaceFolder); } else { ignoredWorkspaceFolders.push(workspaceFolder); @@ -2308,28 +2308,28 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return [workspaceFolders, ignoredWorkspaceFolders, executionEngine, schemaVersion, workspace]; } - private computeExecutionEngine(workspaceFolder: IWorkspaceFolder): ExecutionEngine { - let { config } = this.getConfiguration(workspaceFolder); + private _computeExecutionEngine(workspaceFolder: IWorkspaceFolder): ExecutionEngine { + let { config } = this._getConfiguration(workspaceFolder); if (!config) { return ExecutionEngine._default; } return TaskConfig.ExecutionEngine.from(config); } - private computeJsonSchemaVersion(workspaceFolder: IWorkspaceFolder): JsonSchemaVersion { - let { config } = this.getConfiguration(workspaceFolder); + private _computeJsonSchemaVersion(workspaceFolder: IWorkspaceFolder): JsonSchemaVersion { + let { config } = this._getConfiguration(workspaceFolder); if (!config) { return JsonSchemaVersion.V2_0_0; } return TaskConfig.JsonSchemaVersion.from(config); } - protected getConfiguration(workspaceFolder: IWorkspaceFolder, source?: string): { config: TaskConfig.IExternalTaskRunnerConfiguration | undefined; hasParseErrors: boolean } { + protected _getConfiguration(workspaceFolder: IWorkspaceFolder, source?: string): { config: TaskConfig.IExternalTaskRunnerConfiguration | undefined; hasParseErrors: boolean } { let result; - if ((source !== TaskSourceKind.User) && (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY)) { + if ((source !== TaskSourceKind.User) && (this._contextService.getWorkbenchState() === WorkbenchState.EMPTY)) { result = undefined; } else { - const wholeConfig = this.configurationService.inspect('tasks', { resource: workspaceFolder.uri }); + const wholeConfig = this._configurationService.inspect('tasks', { resource: workspaceFolder.uri }); switch (source) { case TaskSourceKind.User: { if (wholeConfig.userValue !== wholeConfig.workspaceFolderValue) { @@ -2339,7 +2339,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } case TaskSourceKind.Workspace: result = Objects.deepClone(wholeConfig.workspaceFolderValue); break; case TaskSourceKind.WorkspaceFile: { - if ((this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) + if ((this._contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) && (wholeConfig.workspaceFolderValue !== wholeConfig.workspaceValue)) { result = Objects.deepClone(wholeConfig.workspaceValue); } @@ -2362,7 +2362,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } if (isAffected) { this._outputChannel.append(nls.localize('TaskSystem.invalidTaskJson', 'Error: The content of the tasks.json file has syntax errors. Please correct them before executing a task.\n')); - this.showOutput(); + this._showOutput(); return { config: undefined, hasParseErrors: true }; } } @@ -2373,67 +2373,67 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (this._taskSystem) { return this._taskSystem instanceof TerminalTaskSystem; } - return this.executionEngine === ExecutionEngine.Terminal; + return this._executionEngine === ExecutionEngine.Terminal; } public configureAction(): Action { const thisCapture: AbstractTaskService = this; return new class extends Action { constructor() { - super(ConfigureTaskAction.ID, ConfigureTaskAction.TEXT, undefined, true, () => { thisCapture.runConfigureTasks(); return Promise.resolve(undefined); }); + super(ConfigureTaskAction.ID, ConfigureTaskAction.TEXT, undefined, true, () => { thisCapture._runConfigureTasks(); return Promise.resolve(undefined); }); } }; } - private handleError(err: any): void { + private _handleError(err: any): void { let showOutput = true; if (err instanceof TaskError) { let buildError = err; let needsConfig = buildError.code === TaskErrors.NotConfigured || buildError.code === TaskErrors.NoBuildTask || buildError.code === TaskErrors.NoTestTask; let needsTerminate = buildError.code === TaskErrors.RunningTask; if (needsConfig || needsTerminate) { - this.notificationService.prompt(buildError.severity, buildError.message, [{ + this._notificationService.prompt(buildError.severity, buildError.message, [{ label: needsConfig ? ConfigureTaskAction.TEXT : nls.localize('TerminateAction.label', "Terminate Task"), run: () => { if (needsConfig) { - this.runConfigureTasks(); + this._runConfigureTasks(); } else { - this.runTerminateCommand(); + this._runTerminateCommand(); } } }]); } else { - this.notificationService.notify({ severity: buildError.severity, message: buildError.message }); + this._notificationService.notify({ severity: buildError.severity, message: buildError.message }); } } else if (err instanceof Error) { let error = err; - this.notificationService.error(error.message); + this._notificationService.error(error.message); showOutput = false; } else if (Types.isString(err)) { - this.notificationService.error(err); + this._notificationService.error(err); } else { - this.notificationService.error(nls.localize('TaskSystem.unknownError', 'An error has occurred while running a task. See task log for details.')); + this._notificationService.error(nls.localize('TaskSystem.unknownError', 'An error has occurred while running a task. See task log for details.')); } if (showOutput) { - this.showOutput(); + this._showOutput(); } } - private canRunCommand(): boolean { + private _canRunCommand(): boolean { return true; } - private showDetail(): boolean { - return this.configurationService.getValue(QUICKOPEN_DETAIL_CONFIG); + private _showDetail(): boolean { + return this._configurationService.getValue(QUICKOPEN_DETAIL_CONFIG); } - private async createTaskQuickPickEntries(tasks: Task[], group: boolean = false, sort: boolean = false, selectedEntry?: ITaskQuickPickEntry, includeRecents: boolean = true): Promise { + private async _createTaskQuickPickEntries(tasks: Task[], group: boolean = false, sort: boolean = false, selectedEntry?: ITaskQuickPickEntry, includeRecents: boolean = true): Promise { let encounteredTasks: { [key: string]: ITaskQuickPickEntry[] } = {}; if (tasks === undefined || tasks === null || tasks.length === 0) { return []; } const TaskQuickPickEntry = (task: Task): ITaskQuickPickEntry => { - const newEntry = { label: task._label, description: this.getTaskDescription(task), task, detail: this.showDetail() ? task.configurationProperties.detail : undefined }; + const newEntry = { label: task._label, description: this.getTaskDescription(task), task, detail: this._showDetail() ? task.configurationProperties.detail : undefined }; if (encounteredTasks[task._id]) { if (encounteredTasks[task._id].length === 1) { encounteredTasks[task._id][0].label += ' (1)'; @@ -2518,23 +2518,23 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return entries; } - private async showTwoLevelQuickPick(placeHolder: string, defaultEntry?: ITaskQuickPickEntry) { - return TaskQuickPick.show(this, this.configurationService, this.quickInputService, this.notificationService, this.dialogService, placeHolder, defaultEntry); + private async _showTwoLevelQuickPick(placeHolder: string, defaultEntry?: ITaskQuickPickEntry) { + return TaskQuickPick.show(this, this._configurationService, this._quickInputService, this._notificationService, this._dialogService, placeHolder, defaultEntry); } - private async showQuickPick(tasks: Promise | Task[], placeHolder: string, defaultEntry?: ITaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: ITaskQuickPickEntry, additionalEntries?: ITaskQuickPickEntry[]): Promise { + private async _showQuickPick(tasks: Promise | Task[], placeHolder: string, defaultEntry?: ITaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: ITaskQuickPickEntry, additionalEntries?: ITaskQuickPickEntry[]): Promise { const tokenSource = new CancellationTokenSource(); const cancellationToken: CancellationToken = tokenSource.token; - let _createEntries = new Promise[]>((resolve) => { + let createEntries = new Promise[]>((resolve) => { if (Array.isArray(tasks)) { - resolve(this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry)); + resolve(this._createTaskQuickPickEntries(tasks, group, sort, selectedEntry)); } else { - resolve(tasks.then((tasks) => this.createTaskQuickPickEntries(tasks, group, sort, selectedEntry))); + resolve(tasks.then((tasks) => this._createTaskQuickPickEntries(tasks, group, sort, selectedEntry))); } }); const timeout: boolean = await Promise.race([new Promise((resolve) => { - _createEntries.then(() => resolve(false)); + createEntries.then(() => resolve(false)); }), new Promise((resolve) => { const timer = setTimeout(() => { clearTimeout(timer); @@ -2542,12 +2542,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }, 200); })]); - if (!timeout && ((await _createEntries).length === 1) && this.configurationService.getValue(QUICKOPEN_SKIP_CONFIG)) { - return ((await _createEntries)[0]); + if (!timeout && ((await createEntries).length === 1) && this._configurationService.getValue(QUICKOPEN_SKIP_CONFIG)) { + return ((await createEntries)[0]); } - const pickEntries = _createEntries.then((entries) => { - if ((entries.length === 1) && this.configurationService.getValue(QUICKOPEN_SKIP_CONFIG)) { + const pickEntries = createEntries.then((entries) => { + if ((entries.length === 1) && this._configurationService.getValue(QUICKOPEN_SKIP_CONFIG)) { tokenSource.cancel(); } else if ((entries.length === 0) && defaultEntry) { entries.push(defaultEntry); @@ -2558,13 +2558,13 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return entries; }); - const picker: IQuickPick = this.quickInputService.createQuickPick(); + const picker: IQuickPick = this._quickInputService.createQuickPick(); picker.placeholder = placeHolder; picker.matchOnDescription = true; picker.onDidTriggerItemButton(context => { let task = context.item.task; - this.quickInputService.cancel(); + this._quickInputService.cancel(); if (ContributedTask.is(task)) { this.customize(task, undefined, true); } else if (CustomTask.is(task)) { @@ -2597,12 +2597,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); } - private needsRecentTasksMigration(): boolean { - return (this.getRecentlyUsedTasksV1().size > 0) && (this.getRecentlyUsedTasks().size === 0); + private _needsRecentTasksMigration(): boolean { + return (this.getRecentlyUsedTasksV1().size > 0) && (this._getRecentlyUsedTasks().size === 0); } - private async migrateRecentTasks(tasks: Task[]) { - if (!this.needsRecentTasksMigration()) { + private async _migrateRecentTasks(tasks: Task[]) { + if (!this._needsRecentTasksMigration()) { return; } let recentlyUsedTasks = this.getRecentlyUsedTasksV1(); @@ -2617,25 +2617,25 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer for (const key in reversed) { let task = taskMap[key]; if (task) { - await this.setRecentlyUsedTask(task); + await this._setRecentlyUsedTask(task); } } - this.storageService.remove(AbstractTaskService.RecentlyUsedTasks_Key, StorageScope.WORKSPACE); + this._storageService.remove(AbstractTaskService.RecentlyUsedTasks_Key, StorageScope.WORKSPACE); } - private showIgnoredFoldersMessage(): Promise { + private _showIgnoredFoldersMessage(): Promise { if (this.ignoredWorkspaceFolders.length === 0 || !this.showIgnoreMessage) { return Promise.resolve(undefined); } - this.notificationService.prompt( + this._notificationService.prompt( Severity.Info, nls.localize('TaskService.ignoredFolder', 'The following workspace folders are ignored since they use task version 0.1.0: {0}', this.ignoredWorkspaceFolders.map(f => f.name).join(', ')), [{ label: nls.localize('TaskService.notAgain', "Don't Show Again"), isSecondary: true, run: () => { - this.storageService.store(AbstractTaskService.IgnoreTask010DonotShowAgain_key, true, StorageScope.WORKSPACE, StorageTarget.USER); + this._storageService.store(AbstractTaskService.IgnoreTask010DonotShowAgain_key, true, StorageScope.WORKSPACE, StorageTarget.USER); this._showIgnoreMessage = false; } }] @@ -2644,24 +2644,24 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return Promise.resolve(undefined); } - private async trust(): Promise { - return (await this.workspaceTrustRequestService.requestWorkspaceTrust( + private async _trust(): Promise { + return (await this._workspaceTrustRequestService.requestWorkspaceTrust( { message: nls.localize('TaskService.requestTrust', "Listing and running tasks requires that some of the files in this workspace be executed as code.") })) === true; } - private runTaskCommand(arg?: any): void { - if (!this.canRunCommand()) { + private _runTaskCommand(arg?: any): void { + if (!this._canRunCommand()) { return; } - let identifier = this.getTaskIdentifier(arg); + let identifier = this._getTaskIdentifier(arg); if (identifier !== undefined) { - this.getGroupedTasks().then(async (grouped) => { - let resolver = this.createResolver(grouped); - let folderURIs: (URI | string)[] = this.contextService.getWorkspace().folders.map(folder => folder.uri); - if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { - folderURIs.push(this.contextService.getWorkspace().configuration!); + this._getGroupedTasks().then(async (grouped) => { + let resolver = this._createResolver(grouped); + let folderURIs: (URI | string)[] = this._contextService.getWorkspace().folders.map(folder => folder.uri); + if (this._contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { + folderURIs.push(this._contextService.getWorkspace().configuration!); } folderURIs.push(USER_TASKS_GROUP_KEY); for (let uri of folderURIs) { @@ -2673,20 +2673,20 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return; } } - this.doRunTaskCommand(grouped.all()); + this._doRunTaskCommand(grouped.all()); }, () => { - this.doRunTaskCommand(); + this._doRunTaskCommand(); }); } else { - this.doRunTaskCommand(); + this._doRunTaskCommand(); } } - private tasksAndGroupedTasks(filter?: ITaskFilter): { tasks: Promise; grouped: Promise } { - if (!this.versionAndEngineCompatible(filter)) { + private _tasksAndGroupedTasks(filter?: ITaskFilter): { tasks: Promise; grouped: Promise } { + if (!this._versionAndEngineCompatible(filter)) { return { tasks: Promise.resolve([]), grouped: Promise.resolve(new TaskMap()) }; } - const grouped = this.getGroupedTasks(filter ? filter.type : undefined); + const grouped = this._getGroupedTasks(filter ? filter.type : undefined); const tasks = grouped.then((map) => { if (!filter || !filter.type) { return map.all(); @@ -2713,13 +2713,13 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return { tasks, grouped }; } - private doRunTaskCommand(tasks?: Task[]): void { + private _doRunTaskCommand(tasks?: Task[]): void { const pickThen = (task: Task | undefined | null) => { if (task === undefined) { return; } if (task === null) { - this.runConfigureTasks(); + this._runConfigureTasks(); } else { this.run(task, { attachProblemMatcher: true }, TaskRunSource.User).then(undefined, reason => { // eat the error, it has already been surfaced to the user and we don't care about it here @@ -2729,13 +2729,13 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer const placeholder = nls.localize('TaskService.pickRunTask', 'Select the task to run'); - this.showIgnoredFoldersMessage().then(() => { - if (this.configurationService.getValue(USE_SLOW_PICKER)) { + this._showIgnoredFoldersMessage().then(() => { + if (this._configurationService.getValue(USE_SLOW_PICKER)) { let taskResult: { tasks: Promise; grouped: Promise } | undefined = undefined; if (!tasks) { - taskResult = this.tasksAndGroupedTasks(); + taskResult = this._tasksAndGroupedTasks(); } - this.showQuickPick(tasks ? tasks : taskResult!.tasks, placeholder, + this._showQuickPick(tasks ? tasks : taskResult!.tasks, placeholder, { label: nls.localize('TaskService.noEntryToRunSlow', '$(plus) Configure a Task'), task: null @@ -2745,7 +2745,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return pickThen(entry ? entry.task : undefined); }); } else { - this.showTwoLevelQuickPick(placeholder, + this._showTwoLevelQuickPick(placeholder, { label: nls.localize('TaskService.noEntryToRun', '$(plus) Configure a Task'), task: null @@ -2755,18 +2755,18 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); } - private reRunTaskCommand(): void { - if (!this.canRunCommand()) { + private _reRunTaskCommand(): void { + if (!this._canRunCommand()) { return; } ProblemMatcherRegistry.onReady().then(() => { - return this.editorService.saveAll({ reason: SaveReason.AUTO }).then(() => { // make sure all dirty editors are saved - let executeResult = this.getTaskSystem().rerun(); + return this._editorService.saveAll({ reason: SaveReason.AUTO }).then(() => { // make sure all dirty editors are saved + let executeResult = this._getTaskSystem().rerun(); if (executeResult) { - return this.handleExecuteResult(executeResult); + return this._handleExecuteResult(executeResult); } else { - this.doRunTaskCommand(); + this._doRunTaskCommand(); return Promise.resolve(undefined); } }); @@ -2780,7 +2780,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer * @param taskGlobsInList - This tells splitPerGroupType to filter out globbed tasks (into default), otherwise fall back to boolean * @returns */ - private splitPerGroupType(tasks: Task[], taskGlobsInList: boolean = false): { none: Task[]; defaults: Task[] } { + private _splitPerGroupType(tasks: Task[], taskGlobsInList: boolean = false): { none: Task[]; defaults: Task[] } { let none: Task[] = []; let defaults: Task[] = []; for (let task of tasks) { @@ -2796,12 +2796,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return { none, defaults }; } - private runTaskGroupCommand(taskGroup: TaskGroup, strings: { + private _runTaskGroupCommand(taskGroup: TaskGroup, strings: { fetching: string; select: string; notFoundConfigure: string; }, configure: () => void, legacyCommand: () => void): void { - if (!this.canRunCommand()) { + if (!this._canRunCommand()) { return; } if (this.schemaVersion === JsonSchemaVersion.V0_1_0) { @@ -2823,8 +2823,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } const chooseAndRunTask = (tasks: Task[]) => { - this.showIgnoredFoldersMessage().then(() => { - this.showQuickPick(tasks, + this._showIgnoredFoldersMessage().then(() => { + this._showQuickPick(tasks, strings.select, { label: strings.notFoundConfigure, @@ -2845,9 +2845,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }; // First check for globs before checking for the default tasks of the task group - const absoluteURI = EditorResourceAccessor.getOriginalUri(this.editorService.activeEditor); + const absoluteURI = EditorResourceAccessor.getOriginalUri(this._editorService.activeEditor); if (absoluteURI) { - const workspaceFolder = this.contextService.getWorkspaceFolder(absoluteURI); + const workspaceFolder = this._contextService.getWorkspaceFolder(absoluteURI); // fallback to absolute path of the file if it is not in a workspace or relative path cannot be found const relativePath = workspaceFolder?.uri ? (resources.relativePath(workspaceFolder.uri, absoluteURI) ?? absoluteURI.path) : absoluteURI.path; @@ -2862,11 +2862,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } const handleMultipleTasks = (areGlobTasks: boolean) => { - return this.getTasksForGroup(taskGroup).then((tasks) => { + return this._getTasksForGroup(taskGroup).then((tasks) => { if (tasks.length > 0) { // If we're dealing with tasks that were chosen because of a glob match, // then put globs in the defaults and everything else in none - let { none, defaults } = this.splitPerGroupType(tasks, areGlobTasks); + let { none, defaults } = this._splitPerGroupType(tasks, areGlobTasks); if (defaults.length === 1) { runSingleTask(defaults[0], undefined, this); return; @@ -2915,35 +2915,35 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer // Multiple default tasks returned, show the quickPicker return handleMultipleTasks(false); })(); - this.progressService.withProgress(options, () => promise); + this._progressService.withProgress(options, () => promise); } - private runBuildCommand(): void { - return this.runTaskGroupCommand(TaskGroup.Build, { + private _runBuildCommand(): void { + return this._runTaskGroupCommand(TaskGroup.Build, { fetching: nls.localize('TaskService.fetchingBuildTasks', 'Fetching build tasks...'), select: nls.localize('TaskService.pickBuildTask', 'Select the build task to run'), notFoundConfigure: nls.localize('TaskService.noBuildTask', 'No build task to run found. Configure Build Task...') - }, this.runConfigureDefaultBuildTask, this.build); + }, this._runConfigureDefaultBuildTask, this._build); } - private runTestCommand(): void { - return this.runTaskGroupCommand(TaskGroup.Test, { + private _runTestCommand(): void { + return this._runTaskGroupCommand(TaskGroup.Test, { fetching: nls.localize('TaskService.fetchingTestTasks', 'Fetching test tasks...'), select: nls.localize('TaskService.pickTestTask', 'Select the test task to run'), notFoundConfigure: nls.localize('TaskService.noTestTaskTerminal', 'No test task to run found. Configure Tasks...') - }, this.runConfigureDefaultTestTask, this.runTest); + }, this._runConfigureDefaultTestTask, this._runTest); } - private runTerminateCommand(arg?: any): void { - if (!this.canRunCommand()) { + private _runTerminateCommand(arg?: any): void { + if (!this._canRunCommand()) { return; } if (arg === 'terminateAll') { - this.terminateAll(); + this._terminateAll(); return; } let runQuickPick = (promise?: Promise) => { - this.showQuickPick(promise || this.getActiveTasks(), + this._showQuickPick(promise || this.getActiveTasks(), nls.localize('TaskService.taskToTerminate', 'Select a task to terminate'), { label: nls.localize('TaskService.noTaskRunning', 'No task is currently running'), @@ -2958,7 +2958,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }] ).then(entry => { if (entry && entry.id === 'terminateAll') { - this.terminateAll(); + this._terminateAll(); } let task: Task | undefined | null = entry ? entry.task : undefined; if (task === undefined || task === null) { @@ -2968,7 +2968,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); }; if (this.inTerminal()) { - let identifier = this.getTaskIdentifier(arg); + let identifier = this._getTaskIdentifier(arg); let promise: Promise; if (identifier !== undefined) { promise = this.getActiveTasks(); @@ -2985,18 +2985,18 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer runQuickPick(); } } else { - this.isActive().then((active) => { + this._isActive().then((active) => { if (active) { - this.terminateAll().then((responses) => { + this._terminateAll().then((responses) => { // the output runner has only one task let response = responses[0]; if (response.success) { return; } if (response.code && response.code === TerminateResponseCode.ProcessNotFound) { - this.notificationService.error(nls.localize('TerminateAction.noProcess', 'The launched process doesn\'t exist anymore. If the task spawned background tasks exiting VS Code might result in orphaned processes.')); + this._notificationService.error(nls.localize('TerminateAction.noProcess', 'The launched process doesn\'t exist anymore. If the task spawned background tasks exiting VS Code might result in orphaned processes.')); } else { - this.notificationService.error(nls.localize('TerminateAction.failed', 'Failed to terminate running task')); + this._notificationService.error(nls.localize('TerminateAction.failed', 'Failed to terminate running task')); } }); } @@ -3004,12 +3004,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } - private runRestartTaskCommand(arg?: any): void { - if (!this.canRunCommand()) { + private _runRestartTaskCommand(arg?: any): void { + if (!this._canRunCommand()) { return; } let runQuickPick = (promise?: Promise) => { - this.showQuickPick(promise || this.getActiveTasks(), + this._showQuickPick(promise || this.getActiveTasks(), nls.localize('TaskService.taskToRestart', 'Select the task to restart'), { label: nls.localize('TaskService.noTaskToRestart', 'No task to restart'), @@ -3021,18 +3021,18 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (task === undefined || task === null) { return; } - this.restart(task); + this._restart(task); }); }; if (this.inTerminal()) { - let identifier = this.getTaskIdentifier(arg); + let identifier = this._getTaskIdentifier(arg); let promise: Promise; if (identifier !== undefined) { promise = this.getActiveTasks(); promise.then((tasks) => { for (let task of tasks) { if (task.matches(identifier)) { - this.restart(task); + this._restart(task); return; } } @@ -3047,12 +3047,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return; } let task = activeTasks[0]; - this.restart(task); + this._restart(task); }); } } - private getTaskIdentifier(arg?: any): string | KeyedTaskIdentifier | undefined { + private _getTaskIdentifier(arg?: any): string | KeyedTaskIdentifier | undefined { let result: string | KeyedTaskIdentifier | undefined = undefined; if (Types.isString(arg)) { result = arg; @@ -3062,30 +3062,30 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return result; } - private configHasTasks(taskConfig?: TaskConfig.IExternalTaskRunnerConfiguration): boolean { + private _configHasTasks(taskConfig?: TaskConfig.IExternalTaskRunnerConfiguration): boolean { return !!taskConfig && !!taskConfig.tasks && taskConfig.tasks.length > 0; } - private openTaskFile(resource: URI, taskSource: string) { + private _openTaskFile(resource: URI, taskSource: string) { let configFileCreated = false; - this.fileService.stat(resource).then((stat) => stat, () => undefined).then(async (stat) => { + this._fileService.stat(resource).then((stat) => stat, () => undefined).then(async (stat) => { const fileExists: boolean = !!stat; - const configValue = this.configurationService.inspect('tasks'); + const configValue = this._configurationService.inspect('tasks'); let tasksExistInFile: boolean; let target: ConfigurationTarget; switch (taskSource) { - case TaskSourceKind.User: tasksExistInFile = this.configHasTasks(configValue.userValue); target = ConfigurationTarget.USER; break; - case TaskSourceKind.WorkspaceFile: tasksExistInFile = this.configHasTasks(configValue.workspaceValue); target = ConfigurationTarget.WORKSPACE; break; - default: tasksExistInFile = this.configHasTasks(configValue.workspaceFolderValue); target = ConfigurationTarget.WORKSPACE_FOLDER; + case TaskSourceKind.User: tasksExistInFile = this._configHasTasks(configValue.userValue); target = ConfigurationTarget.USER; break; + case TaskSourceKind.WorkspaceFile: tasksExistInFile = this._configHasTasks(configValue.workspaceValue); target = ConfigurationTarget.WORKSPACE; break; + default: tasksExistInFile = this._configHasTasks(configValue.workspaceFolderValue); target = ConfigurationTarget.WORKSPACE_FOLDER; } let content; if (!tasksExistInFile) { - const pickTemplateResult = await this.quickInputService.pick(getTaskTemplates(), { placeHolder: nls.localize('TaskService.template', 'Select a Task Template') }); + const pickTemplateResult = await this._quickInputService.pick(getTaskTemplates(), { placeHolder: nls.localize('TaskService.template', 'Select a Task Template') }); if (!pickTemplateResult) { return Promise.resolve(undefined); } content = pickTemplateResult.content; - let editorConfig = this.configurationService.getValue() as any; + let editorConfig = this._configurationService.getValue() as any; if (editorConfig.editor.insertSpaces) { content = content.replace(/(\n)(\t+)/g, (_, s1, s2) => s1 + ' '.repeat(s2.length * editorConfig.editor.tabSize)); } @@ -3093,12 +3093,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } if (!fileExists && content) { - return this.textFileService.create([{ resource, value: content }]).then(result => { + return this._textFileService.create([{ resource, value: content }]).then(result => { return result[0].resource; }); } else if (fileExists && (tasksExistInFile || content)) { if (content) { - this.configurationService.updateValue('tasks', json.parse(content), target); + this._configurationService.updateValue('tasks', json.parse(content), target); } return stat?.resource; } @@ -3107,7 +3107,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (!resource) { return; } - this.editorService.openEditor({ + this._editorService.openEditor({ resource, options: { pinned: configFileCreated // pin only if config file is created #8727 @@ -3116,17 +3116,17 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); } - private isTaskEntry(value: IQuickPickItem): value is IQuickPickItem & { task: Task } { + private _isTaskEntry(value: IQuickPickItem): value is IQuickPickItem & { task: Task } { let candidate: IQuickPickItem & { task: Task } = value as any; return candidate && !!candidate.task; } - private isSettingEntry(value: IQuickPickItem): value is IQuickPickItem & { settingType: string } { + private _isSettingEntry(value: IQuickPickItem): value is IQuickPickItem & { settingType: string } { let candidate: IQuickPickItem & { settingType: string } = value as any; return candidate && !!candidate.settingType; } - private configureTask(task: Task) { + private _configureTask(task: Task) { if (ContributedTask.is(task)) { this.customize(task, undefined, true); } else if (CustomTask.is(task)) { @@ -3136,21 +3136,21 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } - private handleSelection(selection: TaskQuickPickEntryType | undefined) { + private _handleSelection(selection: TaskQuickPickEntryType | undefined) { if (!selection) { return; } - if (this.isTaskEntry(selection)) { - this.configureTask(selection.task); - } else if (this.isSettingEntry(selection)) { - const taskQuickPick = new TaskQuickPick(this, this.configurationService, this.quickInputService, this.notificationService, this.dialogService); + if (this._isTaskEntry(selection)) { + this._configureTask(selection.task); + } else if (this._isSettingEntry(selection)) { + const taskQuickPick = new TaskQuickPick(this, this._configurationService, this._quickInputService, this._notificationService, this._dialogService); taskQuickPick.handleSettingOption(selection.settingType); - } else if (selection.folder && (this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY)) { - this.openTaskFile(selection.folder.toResource('.vscode/tasks.json'), TaskSourceKind.Workspace); + } else if (selection.folder && (this._contextService.getWorkbenchState() !== WorkbenchState.EMPTY)) { + this._openTaskFile(selection.folder.toResource('.vscode/tasks.json'), TaskSourceKind.Workspace); } else { - const resource = this.getResourceForKind(TaskSourceKind.User); + const resource = this._getResourceForKind(TaskSourceKind.User); if (resource) { - this.openTaskFile(resource, TaskSourceKind.User); + this._openTaskFile(resource, TaskSourceKind.User); } } } @@ -3170,23 +3170,23 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return description; } - private async runConfigureTasks(): Promise { - if (!(await this.trust())) { + private async _runConfigureTasks(): Promise { + if (!(await this._trust())) { return; } - if (!this.canRunCommand()) { + if (!this._canRunCommand()) { return undefined; } let taskPromise: Promise; if (this.schemaVersion === JsonSchemaVersion.V2_0_0) { - taskPromise = this.getGroupedTasks(); + taskPromise = this._getGroupedTasks(); } else { taskPromise = Promise.resolve(new TaskMap()); } - let stats = this.contextService.getWorkspace().folders.map>((folder) => { - return this.fileService.stat(folder.toResource('.vscode/tasks.json')).then(stat => stat, () => undefined); + let stats = this._contextService.getWorkspace().folders.map>((folder) => { + return this._fileService.stat(folder.toResource('.vscode/tasks.json')).then(stat => stat, () => undefined); }); let createLabel = nls.localize('TaskService.createJsonFile', 'Create tasks.json file from template'); @@ -3201,7 +3201,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (tasks.length > 0) { tasks = tasks.sort((a, b) => a._label.localeCompare(b._label)); for (let task of tasks) { - entries.push({ label: task._label, task, description: this.getTaskDescription(task), detail: this.showDetail() ? task.configurationProperties.detail : undefined }); + entries.push({ label: task._label, task, description: this.getTaskDescription(task), detail: this._showDetail() ? task.configurationProperties.detail : undefined }); if (!ContributedTask.is(task)) { configuredCount++; } @@ -3214,7 +3214,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (entries.length) { entries.push({ type: 'separator' }); } - entries.push({ label, folder: this.contextService.getWorkspace().folders[0] }); + entries.push({ label, folder: this._contextService.getWorkspace().folders[0] }); } if ((entries.length === 1) && !needsCreateOrOpen) { tokenSource.cancel(); @@ -3232,20 +3232,20 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }, 200); })]); - if (!timeout && ((await entries).length === 1) && this.configurationService.getValue(QUICKOPEN_SKIP_CONFIG)) { + if (!timeout && ((await entries).length === 1) && this._configurationService.getValue(QUICKOPEN_SKIP_CONFIG)) { const entry: any = ((await entries)[0]); if (entry.task) { - this.handleSelection(entry); + this._handleSelection(entry); return; } } const entriesWithSettings = entries.then(resolvedEntries => { - resolvedEntries.push(...TaskQuickPick.allSettingEntries(this.configurationService)); + resolvedEntries.push(...TaskQuickPick.allSettingEntries(this._configurationService)); return resolvedEntries; }); - this.quickInputService.pick(entriesWithSettings, + this._quickInputService.pick(entriesWithSettings, { placeHolder: nls.localize('TaskService.pickTask', 'Select a task to configure') }, cancellationToken). then(async (selection) => { if (cancellationToken.isCancellationRequested) { @@ -3255,18 +3255,18 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer selection = task; } } - this.handleSelection(selection); + this._handleSelection(selection); }); } - private runConfigureDefaultBuildTask(): void { - if (!this.canRunCommand()) { + private _runConfigureDefaultBuildTask(): void { + if (!this._canRunCommand()) { return; } if (this.schemaVersion === JsonSchemaVersion.V2_0_0) { this.tasks().then((tasks => { if (tasks.length === 0) { - this.runConfigureTasks(); + this._runConfigureTasks(); return; } let selectedTask: Task | undefined; @@ -3282,11 +3282,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer selectedEntry = { label: nls.localize('TaskService.defaultBuildTaskExists', '{0} is already marked as the default build task', selectedTask.getQualifiedLabel()), task: selectedTask, - detail: this.showDetail() ? selectedTask.configurationProperties.detail : undefined + detail: this._showDetail() ? selectedTask.configurationProperties.detail : undefined }; } - this.showIgnoredFoldersMessage().then(() => { - this.showQuickPick(tasks, + this._showIgnoredFoldersMessage().then(() => { + this._showQuickPick(tasks, nls.localize('TaskService.pickDefaultBuildTask', 'Select the task to be used as the default build task'), undefined, true, false, selectedEntry). then((entry) => { let task: Task | undefined | null = entry ? entry.task : undefined; @@ -3307,18 +3307,18 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); })); } else { - this.runConfigureTasks(); + this._runConfigureTasks(); } } - private runConfigureDefaultTestTask(): void { - if (!this.canRunCommand()) { + private _runConfigureDefaultTestTask(): void { + if (!this._canRunCommand()) { return; } if (this.schemaVersion === JsonSchemaVersion.V2_0_0) { this.tasks().then((tasks => { if (tasks.length === 0) { - this.runConfigureTasks(); + this._runConfigureTasks(); return; } let selectedTask: Task | undefined; @@ -3335,12 +3335,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer selectedEntry = { label: nls.localize('TaskService.defaultTestTaskExists', '{0} is already marked as the default test task.', selectedTask.getQualifiedLabel()), task: selectedTask, - detail: this.showDetail() ? selectedTask.configurationProperties.detail : undefined + detail: this._showDetail() ? selectedTask.configurationProperties.detail : undefined }; } - this.showIgnoredFoldersMessage().then(() => { - this.showQuickPick(tasks, + this._showIgnoredFoldersMessage().then(() => { + this._showQuickPick(tasks, nls.localize('TaskService.pickDefaultTestTask', 'Select the task to be used as the default test task'), undefined, true, false, selectedEntry).then((entry) => { let task: Task | undefined | null = entry ? entry.task : undefined; if (!task) { @@ -3360,12 +3360,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); })); } else { - this.runConfigureTasks(); + this._runConfigureTasks(); } } public async runShowTasks(): Promise { - if (!this.canRunCommand()) { + if (!this._canRunCommand()) { return; } const activeTasksPromise: Promise = this.getActiveTasks(); @@ -3385,7 +3385,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer })) { this._taskSystem!.revealTask(activeTasks[0]); } else { - this.showQuickPick(activeTasksPromise, + this._showQuickPick(activeTasksPromise, nls.localize('TaskService.pickShowTask', 'Select the task to show its output'), { label: nls.localize('TaskService.noTaskIsRunning', 'No task is running'), @@ -3402,17 +3402,17 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } } - private async createTasksDotOld(folder: IWorkspaceFolder): Promise<[URI, URI] | undefined> { + private async _createTasksDotOld(folder: IWorkspaceFolder): Promise<[URI, URI] | undefined> { const tasksFile = folder.toResource('.vscode/tasks.json'); - if (await this.fileService.exists(tasksFile)) { + if (await this._fileService.exists(tasksFile)) { const oldFile = tasksFile.with({ path: `${tasksFile.path}.old` }); - await this.fileService.copy(tasksFile, oldFile, true); + await this._fileService.copy(tasksFile, oldFile, true); return [oldFile, tasksFile]; } return undefined; } - private upgradeTask(task: Task, suppressTaskName: boolean, globalConfig: { windows?: ICommandUpgrade; osx?: ICommandUpgrade; linux?: ICommandUpgrade }): TaskConfig.ICustomTask | TaskConfig.IConfiguringTask | undefined { + private _upgradeTask(task: Task, suppressTaskName: boolean, globalConfig: { windows?: ICommandUpgrade; osx?: ICommandUpgrade; linux?: ICommandUpgrade }): TaskConfig.ICustomTask | TaskConfig.IConfiguringTask | undefined { if (!CustomTask.is(task)) { return; } @@ -3456,31 +3456,31 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer task._source.config.element = configElement; const tempTask = new CustomTask(task._id, task._source, task._label, task.type, task.command, task.hasDefinedMatchers, task.runOptions, task.configurationProperties); - const configTask = this.createCustomizableTask(tempTask); + const configTask = this._createCustomizableTask(tempTask); if (configTask) { return configTask; } return; } - private async upgrade(): Promise { + private async _upgrade(): Promise { if (this.schemaVersion === JsonSchemaVersion.V2_0_0) { return; } - if (!this.workspaceTrustManagementService.isWorkspaceTrusted()) { - this._register(Event.once(this.workspaceTrustManagementService.onDidChangeTrust)(isTrusted => { + if (!this._workspaceTrustManagementService.isWorkspaceTrusted()) { + this._register(Event.once(this._workspaceTrustManagementService.onDidChangeTrust)(isTrusted => { if (isTrusted) { - this.upgrade(); + this._upgrade(); } })); return; } - const tasks = await this.getGroupedTasks(); + const tasks = await this._getGroupedTasks(); const fileDiffs: [URI, URI][] = []; for (const folder of this.workspaceFolders) { - const diff = await this.createTasksDotOld(folder); + const diff = await this._createTasksDotOld(folder); if (diff) { fileDiffs.push(diff); } @@ -3489,35 +3489,35 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } const configTasks: (TaskConfig.ICustomTask | TaskConfig.IConfiguringTask)[] = []; - const suppressTaskName = !!this.configurationService.getValue('tasks.suppressTaskName', { resource: folder.uri }); + const suppressTaskName = !!this._configurationService.getValue('tasks.suppressTaskName', { resource: folder.uri }); const globalConfig = { - windows: this.configurationService.getValue('tasks.windows', { resource: folder.uri }), - osx: this.configurationService.getValue('tasks.osx', { resource: folder.uri }), - linux: this.configurationService.getValue('tasks.linux', { resource: folder.uri }) + windows: this._configurationService.getValue('tasks.windows', { resource: folder.uri }), + osx: this._configurationService.getValue('tasks.osx', { resource: folder.uri }), + linux: this._configurationService.getValue('tasks.linux', { resource: folder.uri }) }; tasks.get(folder).forEach(task => { - const configTask = this.upgradeTask(task, suppressTaskName, globalConfig); + const configTask = this._upgradeTask(task, suppressTaskName, globalConfig); if (configTask) { configTasks.push(configTask); } }); this._taskSystem = undefined; this._workspaceTasksPromise = undefined; - await this.writeConfiguration(folder, 'tasks.tasks', configTasks); - await this.writeConfiguration(folder, 'tasks.version', '2.0.0'); - if (this.configurationService.getValue('tasks.showOutput', { resource: folder.uri })) { - await this.configurationService.updateValue('tasks.showOutput', undefined, { resource: folder.uri }); + await this._writeConfiguration(folder, 'tasks.tasks', configTasks); + await this._writeConfiguration(folder, 'tasks.version', '2.0.0'); + if (this._configurationService.getValue('tasks.showOutput', { resource: folder.uri })) { + await this._configurationService.updateValue('tasks.showOutput', undefined, { resource: folder.uri }); } - if (this.configurationService.getValue('tasks.isShellCommand', { resource: folder.uri })) { - await this.configurationService.updateValue('tasks.isShellCommand', undefined, { resource: folder.uri }); + if (this._configurationService.getValue('tasks.isShellCommand', { resource: folder.uri })) { + await this._configurationService.updateValue('tasks.isShellCommand', undefined, { resource: folder.uri }); } - if (this.configurationService.getValue('tasks.suppressTaskName', { resource: folder.uri })) { - await this.configurationService.updateValue('tasks.suppressTaskName', undefined, { resource: folder.uri }); + if (this._configurationService.getValue('tasks.suppressTaskName', { resource: folder.uri })) { + await this._configurationService.updateValue('tasks.suppressTaskName', undefined, { resource: folder.uri }); } } - this.updateSetup(); + this._updateSetup(); - this.notificationService.prompt(Severity.Warning, + this._notificationService.prompt(Severity.Warning, fileDiffs.length === 1 ? nls.localize('taskService.upgradeVersion', "The deprecated tasks version 0.1.0 has been removed. Your tasks have been upgraded to version 2.0.0. Open the diff to review the upgrade.") : nls.localize('taskService.upgradeVersionPlural', "The deprecated tasks version 0.1.0 has been removed. Your tasks have been upgraded to version 2.0.0. Open the diffs to review the upgrade."), @@ -3525,7 +3525,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer label: fileDiffs.length === 1 ? nls.localize('taskService.openDiff', "Open diff") : nls.localize('taskService.openDiffs', "Open diffs"), run: async () => { for (const upgrade of fileDiffs) { - await this.editorService.openEditor({ + await this._editorService.openEditor({ original: { resource: upgrade[0] }, modified: { resource: upgrade[1] } }); diff --git a/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts b/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts index 74deb605b11..99b878b9ffd 100644 --- a/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts +++ b/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts @@ -26,40 +26,40 @@ const ARE_AUTOMATIC_TASKS_ALLOWED_IN_WORKSPACE = 'tasks.run.allowAutomatic'; export class RunAutomaticTasks extends Disposable implements IWorkbenchContribution { constructor( - @ITaskService private readonly taskService: ITaskService, - @IStorageService private readonly storageService: IStorageService, - @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, - @ILogService private readonly logService: ILogService) { + @ITaskService private readonly _taskService: ITaskService, + @IStorageService private readonly _storageService: IStorageService, + @IWorkspaceTrustManagementService private readonly _workspaceTrustManagementService: IWorkspaceTrustManagementService, + @ILogService private readonly _logService: ILogService) { super(); - this.tryRunTasks(); + this._tryRunTasks(); } - private async tryRunTasks() { - this.logService.trace('RunAutomaticTasks: Trying to run tasks.'); + private async _tryRunTasks() { + this._logService.trace('RunAutomaticTasks: Trying to run tasks.'); // Wait until we have task system info (the extension host and workspace folders are available). - if (!this.taskService.hasTaskSystemInfo) { - this.logService.trace('RunAutomaticTasks: Awaiting task system info.'); - await Event.toPromise(Event.once(this.taskService.onDidChangeTaskSystemInfo)); + if (!this._taskService.hasTaskSystemInfo) { + this._logService.trace('RunAutomaticTasks: Awaiting task system info.'); + await Event.toPromise(Event.once(this._taskService.onDidChangeTaskSystemInfo)); } - this.logService.trace('RunAutomaticTasks: Checking if automatic tasks should run.'); - const isFolderAutomaticAllowed = this.storageService.getBoolean(ARE_AUTOMATIC_TASKS_ALLOWED_IN_WORKSPACE, StorageScope.WORKSPACE, undefined); - await this.workspaceTrustManagementService.workspaceTrustInitialized; - const isWorkspaceTrusted = this.workspaceTrustManagementService.isWorkspaceTrusted(); + this._logService.trace('RunAutomaticTasks: Checking if automatic tasks should run.'); + const isFolderAutomaticAllowed = this._storageService.getBoolean(ARE_AUTOMATIC_TASKS_ALLOWED_IN_WORKSPACE, StorageScope.WORKSPACE, undefined); + await this._workspaceTrustManagementService.workspaceTrustInitialized; + const isWorkspaceTrusted = this._workspaceTrustManagementService.isWorkspaceTrusted(); // Only run if allowed. Prompting for permission occurs when a user first tries to run a task. if (isFolderAutomaticAllowed && isWorkspaceTrusted) { - this.taskService.getWorkspaceTasks(TaskRunSource.FolderOpen).then(workspaceTaskResult => { - let { tasks } = RunAutomaticTasks.findAutoTasks(this.taskService, workspaceTaskResult); - this.logService.trace(`RunAutomaticTasks: Found ${tasks.length} automatic tasks tasks`); + this._taskService.getWorkspaceTasks(TaskRunSource.FolderOpen).then(workspaceTaskResult => { + let { tasks } = RunAutomaticTasks._findAutoTasks(this._taskService, workspaceTaskResult); + this._logService.trace(`RunAutomaticTasks: Found ${tasks.length} automatic tasks tasks`); if (tasks.length > 0) { - RunAutomaticTasks.runTasks(this.taskService, tasks); + RunAutomaticTasks._runTasks(this._taskService, tasks); } }); } } - private static runTasks(taskService: ITaskService, tasks: Array>) { + private static _runTasks(taskService: ITaskService, tasks: Array>) { tasks.forEach(task => { if (task instanceof Promise) { task.then(promiseResult => { @@ -73,7 +73,7 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut }); } - private static getTaskSource(source: TaskSource): URI | undefined { + private static _getTaskSource(source: TaskSource): URI | undefined { const taskKind = TaskSourceKind.toConfigurationTarget(source.kind); switch (taskKind) { case ConfigurationTarget.WORKSPACE_FOLDER: { @@ -86,7 +86,7 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut return undefined; } - private static findAutoTasks(taskService: ITaskService, workspaceTaskResult: Map): { tasks: Array>; taskNames: Array; locations: Map } { + private static _findAutoTasks(taskService: ITaskService, workspaceTaskResult: Map): { tasks: Array>; taskNames: Array; locations: Map } { const tasks = new Array>(); const taskNames = new Array(); const locations = new Map(); @@ -98,7 +98,7 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut if (task.runOptions.runOn === RunOnOptions.folderOpen) { tasks.push(task); taskNames.push(task._label); - const location = RunAutomaticTasks.getTaskSource(task._source); + const location = RunAutomaticTasks._getTaskSource(task._source); if (location) { locations.set(location.fsPath, location); } @@ -116,7 +116,7 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut } else { taskNames.push(configedTask.value.configures.task); } - const location = RunAutomaticTasks.getTaskSource(configedTask.value._source); + const location = RunAutomaticTasks._getTaskSource(configedTask.value._source); if (location) { locations.set(location.fsPath, location); } @@ -140,18 +140,18 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut return; } - let { tasks, taskNames, locations } = RunAutomaticTasks.findAutoTasks(taskService, workspaceTaskResult); + let { tasks, taskNames, locations } = RunAutomaticTasks._findAutoTasks(taskService, workspaceTaskResult); if (taskNames.length > 0) { // We have automatic tasks, prompt to allow. - this.showPrompt(notificationService, storageService, taskService, openerService, taskNames, locations).then(allow => { + this._showPrompt(notificationService, storageService, taskService, openerService, taskNames, locations).then(allow => { if (allow) { - RunAutomaticTasks.runTasks(taskService, tasks); + RunAutomaticTasks._runTasks(taskService, tasks); } }); } } - private static showPrompt(notificationService: INotificationService, storageService: IStorageService, taskService: ITaskService, + private static _showPrompt(notificationService: INotificationService, storageService: IStorageService, taskService: ITaskService, openerService: IOpenerService, taskNames: Array, locations: Map): Promise { return new Promise(resolve => { notificationService.prompt(Severity.Info, nls.localize('tasks.run.allowAutomatic', diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index 4fa5859c889..dad714c86c4 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -56,31 +56,31 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { }); export class TaskStatusBarContributions extends Disposable implements IWorkbenchContribution { - private runningTasksStatusItem: IStatusbarEntryAccessor | undefined; - private activeTasksCount: number = 0; + private _runningTasksStatusItem: IStatusbarEntryAccessor | undefined; + private _activeTasksCount: number = 0; constructor( - @ITaskService private readonly taskService: ITaskService, - @IStatusbarService private readonly statusbarService: IStatusbarService, - @IProgressService private readonly progressService: IProgressService + @ITaskService private readonly _taskService: ITaskService, + @IStatusbarService private readonly _statusbarService: IStatusbarService, + @IProgressService private readonly _progressService: IProgressService ) { super(); - this.registerListeners(); + this._registerListeners(); } - private registerListeners(): void { + private _registerListeners(): void { let promise: Promise | undefined = undefined; let resolver: (value?: void | Thenable) => void; - this.taskService.onDidStateChange(event => { + this._taskService.onDidStateChange(event => { if (event.kind === TaskEventKind.Changed) { - this.updateRunningTasksStatus(); + this._updateRunningTasksStatus(); } - if (!this.ignoreEventForUpdateRunningTasksCount(event)) { + if (!this._ignoreEventForUpdateRunningTasksCount(event)) { switch (event.kind) { case TaskEventKind.Active: - this.activeTasksCount++; - if (this.activeTasksCount === 1) { + this._activeTasksCount++; + if (this._activeTasksCount === 1) { if (!promise) { promise = new Promise((resolve) => { resolver = resolve; @@ -91,9 +91,9 @@ export class TaskStatusBarContributions extends Disposable implements IWorkbench case TaskEventKind.Inactive: // Since the exiting of the sub process is communicated async we can't order inactive and terminate events. // So try to treat them accordingly. - if (this.activeTasksCount > 0) { - this.activeTasksCount--; - if (this.activeTasksCount === 0) { + if (this._activeTasksCount > 0) { + this._activeTasksCount--; + if (this._activeTasksCount === 0) { if (promise && resolver!) { resolver!(); } @@ -101,8 +101,8 @@ export class TaskStatusBarContributions extends Disposable implements IWorkbench } break; case TaskEventKind.Terminated: - if (this.activeTasksCount !== 0) { - this.activeTasksCount = 0; + if (this._activeTasksCount !== 0) { + this._activeTasksCount = 0; if (promise && resolver!) { resolver!(); } @@ -111,8 +111,8 @@ export class TaskStatusBarContributions extends Disposable implements IWorkbench } } - if (promise && (event.kind === TaskEventKind.Active) && (this.activeTasksCount === 1)) { - this.progressService.withProgress({ location: ProgressLocation.Window, command: 'workbench.action.tasks.showTasks' }, progress => { + if (promise && (event.kind === TaskEventKind.Active) && (this._activeTasksCount === 1)) { + this._progressService.withProgress({ location: ProgressLocation.Window, command: 'workbench.action.tasks.showTasks' }, progress => { progress.report({ message: nls.localize('building', 'Building...') }); return promise!; }).then(() => { @@ -122,12 +122,12 @@ export class TaskStatusBarContributions extends Disposable implements IWorkbench }); } - private async updateRunningTasksStatus(): Promise { - const tasks = await this.taskService.getActiveTasks(); + private async _updateRunningTasksStatus(): Promise { + const tasks = await this._taskService.getActiveTasks(); if (tasks.length === 0) { - if (this.runningTasksStatusItem) { - this.runningTasksStatusItem.dispose(); - this.runningTasksStatusItem = undefined; + if (this._runningTasksStatusItem) { + this._runningTasksStatusItem.dispose(); + this._runningTasksStatusItem = undefined; } } else { const itemProps: IStatusbarEntry = { @@ -138,16 +138,16 @@ export class TaskStatusBarContributions extends Disposable implements IWorkbench command: 'workbench.action.tasks.showTasks', }; - if (!this.runningTasksStatusItem) { - this.runningTasksStatusItem = this.statusbarService.addEntry(itemProps, 'status.runningTasks', StatusbarAlignment.LEFT, 49 /* Medium Priority, next to Markers */); + if (!this._runningTasksStatusItem) { + this._runningTasksStatusItem = this._statusbarService.addEntry(itemProps, 'status.runningTasks', StatusbarAlignment.LEFT, 49 /* Medium Priority, next to Markers */); } else { - this.runningTasksStatusItem.update(itemProps); + this._runningTasksStatusItem.update(itemProps); } } } - private ignoreEventForUpdateRunningTasksCount(event: ITaskEvent): boolean { - if (!this.taskService.inTerminal()) { + private _ignoreEventForUpdateRunningTasksCount(event: ITaskEvent): boolean { + if (!this._taskService.inTerminal()) { return false; } diff --git a/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts b/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts index fd9f0ff7a6e..bbc24b0a8a8 100644 --- a/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts +++ b/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts @@ -42,24 +42,24 @@ export const configureTaskIcon = registerIcon('tasks-list-configure', Codicon.ge const removeTaskIcon = registerIcon('tasks-remove', Codicon.close, nls.localize('removeTaskIcon', 'Icon for remove in the tasks selection list.')); export class TaskQuickPick extends Disposable { - private sorter: TaskSorter; - private topLevelEntries: QuickPickInput[] | undefined; + private _sorter: TaskSorter; + private _topLevelEntries: QuickPickInput[] | undefined; constructor( - private taskService: ITaskService, - private configurationService: IConfigurationService, - private quickInputService: IQuickInputService, - private notificationService: INotificationService, - private dialogService: IDialogService) { + private _taskService: ITaskService, + private _configurationService: IConfigurationService, + private _quickInputService: IQuickInputService, + private _notificationService: INotificationService, + private _dialogService: IDialogService) { super(); - this.sorter = this.taskService.createSorter(); + this._sorter = this._taskService.createSorter(); } - private showDetail(): boolean { + private _showDetail(): boolean { // Ensure invalid values get converted into boolean values - return !!this.configurationService.getValue(QUICKOPEN_DETAIL_CONFIG); + return !!this._configurationService.getValue(QUICKOPEN_DETAIL_CONFIG); } - private guessTaskLabel(task: Task | ConfiguringTask): string { + private _guessTaskLabel(task: Task | ConfiguringTask): string { if (task._label) { return task._label; } @@ -74,21 +74,21 @@ export class TaskQuickPick extends Disposable { return ''; } - private createTaskEntry(task: Task | ConfiguringTask, extraButtons: IQuickInputButton[] = []): ITaskTwoLevelQuickPickEntry { - const entry: ITaskTwoLevelQuickPickEntry = { label: this.guessTaskLabel(task), description: this.taskService.getTaskDescription(task), task, detail: this.showDetail() ? task.configurationProperties.detail : undefined }; + private _createTaskEntry(task: Task | ConfiguringTask, extraButtons: IQuickInputButton[] = []): ITaskTwoLevelQuickPickEntry { + const entry: ITaskTwoLevelQuickPickEntry = { label: this._guessTaskLabel(task), description: this._taskService.getTaskDescription(task), task, detail: this._showDetail() ? task.configurationProperties.detail : undefined }; entry.buttons = [{ iconClass: ThemeIcon.asClassName(configureTaskIcon), tooltip: nls.localize('configureTask', "Configure Task") }, ...extraButtons]; return entry; } - private createEntriesForGroup(entries: QuickPickInput[], tasks: (Task | ConfiguringTask)[], + private _createEntriesForGroup(entries: QuickPickInput[], tasks: (Task | ConfiguringTask)[], groupLabel: string, extraButtons: IQuickInputButton[] = []) { entries.push({ type: 'separator', label: groupLabel }); tasks.forEach(task => { - entries.push(this.createTaskEntry(task, extraButtons)); + entries.push(this._createTaskEntry(task, extraButtons)); }); } - private createTypeEntries(entries: QuickPickInput[], types: string[]) { + private _createTypeEntries(entries: QuickPickInput[], types: string[]) { entries.push({ type: 'separator', label: nls.localize('contributedTasks', "contributed") }); types.forEach(type => { entries.push({ label: `$(folder) ${type}`, task: type, ariaLabel: nls.localize('taskType', "All {0} tasks", type) }); @@ -96,7 +96,7 @@ export class TaskQuickPick extends Disposable { entries.push({ label: SHOW_ALL, task: SHOW_ALL, alwaysShow: true }); } - private handleFolderTaskResult(result: Map): (Task | ConfiguringTask)[] { + private _handleFolderTaskResult(result: Map): (Task | ConfiguringTask)[] { let tasks: (Task | ConfiguringTask)[] = []; Array.from(result).forEach(([key, folderTasks]) => { if (folderTasks.set) { @@ -111,7 +111,7 @@ export class TaskQuickPick extends Disposable { return tasks; } - private dedupeConfiguredAndRecent(recentTasks: (Task | ConfiguringTask)[], configuredTasks: (Task | ConfiguringTask)[]): { configuredTasks: (Task | ConfiguringTask)[]; recentTasks: (Task | ConfiguringTask)[] } { + private _dedupeConfiguredAndRecent(recentTasks: (Task | ConfiguringTask)[], configuredTasks: (Task | ConfiguringTask)[]): { configuredTasks: (Task | ConfiguringTask)[]; recentTasks: (Task | ConfiguringTask)[] } { let dedupedConfiguredTasks: (Task | ConfiguringTask)[] = []; const foundRecentTasks: boolean[] = Array(recentTasks.length).fill(false); for (let j = 0; j < configuredTasks.length; j++) { @@ -132,7 +132,7 @@ export class TaskQuickPick extends Disposable { foundRecentTasks[findIndex] = true; } } - dedupedConfiguredTasks = dedupedConfiguredTasks.sort((a, b) => this.sorter.compare(a, b)); + dedupedConfiguredTasks = dedupedConfiguredTasks.sort((a, b) => this._sorter.compare(a, b)); const prunedRecentTasks: (Task | ConfiguringTask)[] = []; for (let i = 0; i < recentTasks.length; i++) { if (foundRecentTasks[i] || ConfiguringTask.is(recentTasks[i])) { @@ -143,15 +143,15 @@ export class TaskQuickPick extends Disposable { } public async getTopLevelEntries(defaultEntry?: ITaskQuickPickEntry): Promise<{ entries: QuickPickInput[]; isSingleConfigured?: Task | ConfiguringTask }> { - if (this.topLevelEntries !== undefined) { - return { entries: this.topLevelEntries }; + if (this._topLevelEntries !== undefined) { + return { entries: this._topLevelEntries }; } - let recentTasks: (Task | ConfiguringTask)[] = (await this.taskService.readRecentTasks()).reverse(); - const configuredTasks: (Task | ConfiguringTask)[] = this.handleFolderTaskResult(await this.taskService.getWorkspaceTasks()); - const extensionTaskTypes = this.taskService.taskTypes(); - this.topLevelEntries = []; + let recentTasks: (Task | ConfiguringTask)[] = (await this._taskService.readRecentTasks()).reverse(); + const configuredTasks: (Task | ConfiguringTask)[] = this._handleFolderTaskResult(await this._taskService.getWorkspaceTasks()); + const extensionTaskTypes = this._taskService.taskTypes(); + this._topLevelEntries = []; // Dedupe will update recent tasks if they've changed in tasks.json. - const dedupeAndPrune = this.dedupeConfiguredAndRecent(recentTasks, configuredTasks); + const dedupeAndPrune = this._dedupeConfiguredAndRecent(recentTasks, configuredTasks); let dedupedConfiguredTasks: (Task | ConfiguringTask)[] = dedupeAndPrune.configuredTasks; recentTasks = dedupeAndPrune.recentTasks; if (recentTasks.length > 0) { @@ -159,34 +159,34 @@ export class TaskQuickPick extends Disposable { iconClass: ThemeIcon.asClassName(removeTaskIcon), tooltip: nls.localize('removeRecent', 'Remove Recently Used Task') }; - this.createEntriesForGroup(this.topLevelEntries, recentTasks, nls.localize('recentlyUsed', 'recently used'), [removeRecentButton]); + this._createEntriesForGroup(this._topLevelEntries, recentTasks, nls.localize('recentlyUsed', 'recently used'), [removeRecentButton]); } if (configuredTasks.length > 0) { if (dedupedConfiguredTasks.length > 0) { - this.createEntriesForGroup(this.topLevelEntries, dedupedConfiguredTasks, nls.localize('configured', 'configured')); + this._createEntriesForGroup(this._topLevelEntries, dedupedConfiguredTasks, nls.localize('configured', 'configured')); } } if (defaultEntry && (configuredTasks.length === 0)) { - this.topLevelEntries.push({ type: 'separator', label: nls.localize('configured', 'configured') }); - this.topLevelEntries.push(defaultEntry); + this._topLevelEntries.push({ type: 'separator', label: nls.localize('configured', 'configured') }); + this._topLevelEntries.push(defaultEntry); } if (extensionTaskTypes.length > 0) { - this.createTypeEntries(this.topLevelEntries, extensionTaskTypes); + this._createTypeEntries(this._topLevelEntries, extensionTaskTypes); } - return { entries: this.topLevelEntries, isSingleConfigured: configuredTasks.length === 1 ? configuredTasks[0] : undefined }; + return { entries: this._topLevelEntries, isSingleConfigured: configuredTasks.length === 1 ? configuredTasks[0] : undefined }; } public async handleSettingOption(selectedType: string) { const noButton = nls.localize('TaskQuickPick.changeSettingNo', "No"); const yesButton = nls.localize('TaskQuickPick.changeSettingYes', "Yes"); - const changeSettingResult = await this.dialogService.show(Severity.Warning, + const changeSettingResult = await this._dialogService.show(Severity.Warning, nls.localize('TaskQuickPick.changeSettingDetails', "Task detection for {0} tasks causes files in any workspace you open to be run as code. Enabling {0} task detection is a user setting and will apply to any workspace you open. Do you want to enable {0} task detection for all workspaces?", selectedType), [noButton, yesButton]); if (changeSettingResult.choice === 1) { - await this.configurationService.updateValue(`${selectedType}.autoDetect`, 'on'); + await this._configurationService.updateValue(`${selectedType}.autoDetect`, 'on'); await new Promise(resolve => setTimeout(() => resolve(), 100)); return this.show(nls.localize('TaskService.pickRunTask', 'Select the task to run'), undefined, selectedType); } @@ -194,7 +194,7 @@ export class TaskQuickPick extends Disposable { } public async show(placeHolder: string, defaultEntry?: ITaskQuickPickEntry, startAtType?: string): Promise { - const picker: IQuickPick = this.quickInputService.createQuickPick(); + const picker: IQuickPick = this._quickInputService.createQuickPick(); picker.placeholder = placeHolder; picker.matchOnDescription = true; picker.ignoreFocusOut = false; @@ -205,25 +205,25 @@ export class TaskQuickPick extends Disposable { if (context.button.iconClass === ThemeIcon.asClassName(removeTaskIcon)) { const key = (task && !Types.isString(task)) ? task.getRecentlyUsedKey() : undefined; if (key) { - this.taskService.removeRecentlyUsedTask(key); + this._taskService.removeRecentlyUsedTask(key); } const indexToRemove = picker.items.indexOf(context.item); if (indexToRemove >= 0) { picker.items = [...picker.items.slice(0, indexToRemove), ...picker.items.slice(indexToRemove + 1)]; } } else { - this.quickInputService.cancel(); + this._quickInputService.cancel(); if (ContributedTask.is(task)) { - this.taskService.customize(task, undefined, true); + this._taskService.customize(task, undefined, true); } else if (CustomTask.is(task) || ConfiguringTask.is(task)) { let canOpenConfig: boolean = false; try { - canOpenConfig = await this.taskService.openConfig(task); + canOpenConfig = await this._taskService.openConfig(task); } catch (e) { // do nothing. } if (!canOpenConfig) { - this.taskService.customize(task, undefined, true); + this._taskService.customize(task, undefined, true); } } } @@ -233,30 +233,30 @@ export class TaskQuickPick extends Disposable { if (!firstLevelTask) { // First show recent tasks configured tasks. Other tasks will be available at a second level const topLevelEntriesResult = await this.getTopLevelEntries(defaultEntry); - if (topLevelEntriesResult.isSingleConfigured && this.configurationService.getValue(QUICKOPEN_SKIP_CONFIG)) { + if (topLevelEntriesResult.isSingleConfigured && this._configurationService.getValue(QUICKOPEN_SKIP_CONFIG)) { picker.dispose(); - return this.toTask(topLevelEntriesResult.isSingleConfigured); + return this._toTask(topLevelEntriesResult.isSingleConfigured); } const taskQuickPickEntries: QuickPickInput[] = topLevelEntriesResult.entries; - firstLevelTask = await this.doPickerFirstLevel(picker, taskQuickPickEntries); + firstLevelTask = await this._doPickerFirstLevel(picker, taskQuickPickEntries); } do { if (Types.isString(firstLevelTask)) { // Proceed to second level of quick pick - const selectedEntry = await this.doPickerSecondLevel(picker, firstLevelTask); + const selectedEntry = await this._doPickerSecondLevel(picker, firstLevelTask); if (selectedEntry && !selectedEntry.settingType && selectedEntry.task === null) { // The user has chosen to go back to the first level - firstLevelTask = await this.doPickerFirstLevel(picker, (await this.getTopLevelEntries(defaultEntry)).entries); + firstLevelTask = await this._doPickerFirstLevel(picker, (await this.getTopLevelEntries(defaultEntry)).entries); } else if (selectedEntry && Types.isString(selectedEntry.settingType)) { picker.dispose(); return this.handleSettingOption(selectedEntry.settingType); } else { picker.dispose(); - return (selectedEntry?.task && !Types.isString(selectedEntry?.task)) ? this.toTask(selectedEntry?.task) : undefined; + return (selectedEntry?.task && !Types.isString(selectedEntry?.task)) ? this._toTask(selectedEntry?.task) : undefined; } } else if (firstLevelTask) { picker.dispose(); - return this.toTask(firstLevelTask); + return this._toTask(firstLevelTask); } else { picker.dispose(); return firstLevelTask; @@ -265,7 +265,7 @@ export class TaskQuickPick extends Disposable { return; } - private async doPickerFirstLevel(picker: IQuickPick, taskQuickPickEntries: QuickPickInput[]): Promise { + private async _doPickerFirstLevel(picker: IQuickPick, taskQuickPickEntries: QuickPickInput[]): Promise { picker.items = taskQuickPickEntries; const firstLevelPickerResult = await new Promise(resolve => { Event.once(picker.onDidAccept)(async () => { @@ -275,15 +275,15 @@ export class TaskQuickPick extends Disposable { return firstLevelPickerResult?.task; } - private async doPickerSecondLevel(picker: IQuickPick, type: string) { + private async _doPickerSecondLevel(picker: IQuickPick, type: string) { picker.busy = true; if (type === SHOW_ALL) { - const items = (await this.taskService.tasks()).sort((a, b) => this.sorter.compare(a, b)).map(task => this.createTaskEntry(task)); - items.push(...TaskQuickPick.allSettingEntries(this.configurationService)); + const items = (await this._taskService.tasks()).sort((a, b) => this._sorter.compare(a, b)).map(task => this._createTaskEntry(task)); + items.push(...TaskQuickPick.allSettingEntries(this._configurationService)); picker.items = items; } else { picker.value = ''; - picker.items = await this.getEntriesForProvider(type); + picker.items = await this._getEntriesForProvider(type); } picker.busy = false; const secondLevelPickerResult = await new Promise(resolve => { @@ -325,11 +325,11 @@ export class TaskQuickPick extends Disposable { return undefined; } - private async getEntriesForProvider(type: string): Promise[]> { - const tasks = (await this.taskService.tasks({ type })).sort((a, b) => this.sorter.compare(a, b)); + private async _getEntriesForProvider(type: string): Promise[]> { + const tasks = (await this._taskService.tasks({ type })).sort((a, b) => this._sorter.compare(a, b)); let taskQuickPickEntries: QuickPickInput[]; if (tasks.length > 0) { - taskQuickPickEntries = tasks.map(task => this.createTaskEntry(task)); + taskQuickPickEntries = tasks.map(task => this._createTaskEntry(task)); taskQuickPickEntries.push({ type: 'separator' }, { @@ -345,22 +345,22 @@ export class TaskQuickPick extends Disposable { }]; } - const settingEntry = TaskQuickPick.getSettingEntry(this.configurationService, type); + const settingEntry = TaskQuickPick.getSettingEntry(this._configurationService, type); if (settingEntry) { taskQuickPickEntries.push(settingEntry); } return taskQuickPickEntries; } - private async toTask(task: Task | ConfiguringTask): Promise { + private async _toTask(task: Task | ConfiguringTask): Promise { if (!ConfiguringTask.is(task)) { return task; } - const resolvedTask = await this.taskService.tryResolveTask(task); + const resolvedTask = await this._taskService.tryResolveTask(task); if (!resolvedTask) { - this.notificationService.error(nls.localize('noProviderForTask', "There is no task provider registered for tasks of type \"{0}\".", task.type)); + this._notificationService.error(nls.localize('noProviderForTask', "There is no task provider registered for tasks of type \"{0}\".", task.type)); } return resolvedTask; } diff --git a/src/vs/workbench/contrib/tasks/browser/taskService.ts b/src/vs/workbench/contrib/tasks/browser/taskService.ts index 65028c8ab75..efb6f0bb872 100644 --- a/src/vs/workbench/contrib/tasks/browser/taskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/taskService.ts @@ -14,12 +14,12 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class TaskService extends AbstractTaskService { private static readonly ProcessTaskSystemSupportMessage = nls.localize('taskService.processTaskSystem', 'Process task system is not support in the web.'); - protected getTaskSystem(): ITaskSystem { + protected _getTaskSystem(): ITaskSystem { if (this._taskSystem) { return this._taskSystem; } if (this.executionEngine === ExecutionEngine.Terminal) { - this._taskSystem = this.createTerminalTaskSystem(); + this._taskSystem = this._createTerminalTaskSystem(); } else { throw new Error(TaskService.ProcessTaskSystemSupportMessage); } @@ -32,11 +32,11 @@ export class TaskService extends AbstractTaskService { return this._taskSystem!; } - protected computeLegacyConfiguration(workspaceFolder: IWorkspaceFolder): Promise { + protected _computeLegacyConfiguration(workspaceFolder: IWorkspaceFolder): Promise { throw new Error(TaskService.ProcessTaskSystemSupportMessage); } - protected versionAndEngineCompatible(filter?: ITaskFilter): boolean { + protected _versionAndEngineCompatible(filter?: ITaskFilter): boolean { return this.executionEngine === ExecutionEngine.Terminal; } } diff --git a/src/vs/workbench/contrib/tasks/browser/tasksQuickAccess.ts b/src/vs/workbench/contrib/tasks/browser/tasksQuickAccess.ts index 6c4080090bb..5f9af57d660 100644 --- a/src/vs/workbench/contrib/tasks/browser/tasksQuickAccess.ts +++ b/src/vs/workbench/contrib/tasks/browser/tasksQuickAccess.ts @@ -24,11 +24,11 @@ export class TasksQuickAccessProvider extends PickerQuickAccessProvider = []; @@ -63,14 +63,14 @@ export class TasksQuickAccessProvider extends PickerQuickAccessProvider { + private async _toTask(task: Task | ConfiguringTask): Promise { if (!ConfiguringTask.is(task)) { return task; } - return this.taskService.tryResolveTask(task); + return this._taskService.tryResolveTask(task); } } diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index db3cdbd6a79..864396f1f20 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -84,21 +84,21 @@ class InstanceManager { } class VariableResolver { - private static regex = /\$\{(.*?)\}/g; + private static _regex = /\$\{(.*?)\}/g; constructor(public workspaceFolder: IWorkspaceFolder | undefined, public taskSystemInfo: ITaskSystemInfo | undefined, public readonly values: Map, private _service: IConfigurationResolverService | undefined) { } async resolve(value: string): Promise { const replacers: Promise[] = []; - value.replace(VariableResolver.regex, (match, ...args) => { - replacers.push(this.replacer(match, args)); + value.replace(VariableResolver._regex, (match, ...args) => { + replacers.push(this._replacer(match, args)); return match; }); const resolvedReplacers = await Promise.all(replacers); - return value.replace(VariableResolver.regex, () => resolvedReplacers.shift()!); + return value.replace(VariableResolver._regex, () => resolvedReplacers.shift()!); } - private async replacer(match: string, args: string[]): Promise { + private async _replacer(match: string, args: string[]): Promise { // Strip out the ${} because the map contains them variables without those characters. let result = this.values.get(match.substring(2, match.length - 1)); if ((result !== undefined) && (result !== null)) { @@ -149,7 +149,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { private static readonly ProcessVarName = '__process__'; - private static shellQuotes: IStringDictionary = { + private static _shellQuotes: IStringDictionary = { 'cmd': { strong: '"' }, @@ -179,126 +179,127 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } }; - private static osShellQuotes: IStringDictionary = { - 'Linux': TerminalTaskSystem.shellQuotes['bash'], - 'Mac': TerminalTaskSystem.shellQuotes['bash'], - 'Windows': TerminalTaskSystem.shellQuotes['powershell'] + private static _osShellQuotes: IStringDictionary = { + 'Linux': TerminalTaskSystem._shellQuotes['bash'], + 'Mac': TerminalTaskSystem._shellQuotes['bash'], + 'Windows': TerminalTaskSystem._shellQuotes['powershell'] }; - private activeTasks: IStringDictionary; - private instances: IStringDictionary; - private busyTasks: IStringDictionary; - private terminals: IStringDictionary; - private idleTaskTerminals: LinkedMap; - private sameTaskTerminals: IStringDictionary; - private taskSystemInfoResolver: ITaskSystemInfoResolver; - private lastTask: VerifiedTask | undefined; + private _activeTasks: IStringDictionary; + private _instances: IStringDictionary; + private _busyTasks: IStringDictionary; + private _terminals: IStringDictionary; + private _idleTaskTerminals: LinkedMap; + private _sameTaskTerminals: IStringDictionary; + private _taskSystemInfoResolver: ITaskSystemInfoResolver; + private _lastTask: VerifiedTask | undefined; // Should always be set in run - private currentTask!: VerifiedTask; - private isRerun: boolean = false; - private previousPanelId: string | undefined; - private previousTerminalInstance: ITerminalInstance | undefined; - private terminalStatusManager: TaskTerminalStatus; - private terminalCreationQueue: Promise = Promise.resolve(); + private _currentTask!: VerifiedTask; + private _isRerun: boolean = false; + private _previousPanelId: string | undefined; + private _previousTerminalInstance: ITerminalInstance | undefined; + private _terminalStatusManager: TaskTerminalStatus; + private _terminalCreationQueue: Promise = Promise.resolve(); private readonly _onDidStateChange: Emitter; constructor( - private terminalService: ITerminalService, - private terminalGroupService: ITerminalGroupService, - private outputService: IOutputService, - private paneCompositeService: IPaneCompositePartService, - private viewsService: IViewsService, - private markerService: IMarkerService, private modelService: IModelService, - private configurationResolverService: IConfigurationResolverService, - private contextService: IWorkspaceContextService, - private environmentService: IWorkbenchEnvironmentService, - private outputChannelId: string, - private fileService: IFileService, - private terminalProfileResolverService: ITerminalProfileResolverService, - private pathService: IPathService, - private viewDescriptorService: IViewDescriptorService, - private logService: ILogService, - private configurationService: IConfigurationService, - private notificationService: INotificationService, + private _terminalService: ITerminalService, + private _terminalGroupService: ITerminalGroupService, + private _outputService: IOutputService, + private _paneCompositeService: IPaneCompositePartService, + private _viewsService: IViewsService, + private _markerService: IMarkerService, + private _modelService: IModelService, + private _configurationResolverService: IConfigurationResolverService, + private _contextService: IWorkspaceContextService, + private _environmentService: IWorkbenchEnvironmentService, + private _outputChannelId: string, + private _fileService: IFileService, + private _terminalProfileResolverService: ITerminalProfileResolverService, + private _pathService: IPathService, + private _viewDescriptorService: IViewDescriptorService, + private _logService: ILogService, + private _configurationService: IConfigurationService, + private _notificationService: INotificationService, taskService: ITaskService, taskSystemInfoResolver: ITaskSystemInfoResolver, ) { super(); - this.activeTasks = Object.create(null); - this.instances = Object.create(null); - this.busyTasks = Object.create(null); - this.terminals = Object.create(null); - this.idleTaskTerminals = new LinkedMap(); - this.sameTaskTerminals = Object.create(null); + this._activeTasks = Object.create(null); + this._instances = Object.create(null); + this._busyTasks = Object.create(null); + this._terminals = Object.create(null); + this._idleTaskTerminals = new LinkedMap(); + this._sameTaskTerminals = Object.create(null); this._onDidStateChange = new Emitter(); - this.taskSystemInfoResolver = taskSystemInfoResolver; - this._register(this.terminalStatusManager = new TaskTerminalStatus(taskService)); + this._taskSystemInfoResolver = taskSystemInfoResolver; + this._register(this._terminalStatusManager = new TaskTerminalStatus(taskService)); } public get onDidStateChange(): Event { return this._onDidStateChange.event; } - private log(value: string): void { - this.appendOutput(value + '\n'); + private _log(value: string): void { + this._appendOutput(value + '\n'); } - protected showOutput(): void { - this.outputService.showChannel(this.outputChannelId, true); + protected _showOutput(): void { + this._outputService.showChannel(this._outputChannelId, true); } public run(task: Task, resolver: ITaskResolver, trigger: string = Triggers.command): ITaskExecuteResult { task = task.clone(); // A small amount of task state is stored in the task (instance) and tasks passed in to run may have that set already. const recentTaskKey = task.getRecentlyUsedKey() ?? ''; - let validInstance = task.runOptions && task.runOptions.instanceLimit && this.instances[recentTaskKey] && this.instances[recentTaskKey].instances < task.runOptions.instanceLimit; - let instance = this.instances[recentTaskKey] ? this.instances[recentTaskKey].instances : 0; - this.currentTask = new VerifiedTask(task, resolver, trigger); + let validInstance = task.runOptions && task.runOptions.instanceLimit && this._instances[recentTaskKey] && this._instances[recentTaskKey].instances < task.runOptions.instanceLimit; + let instance = this._instances[recentTaskKey] ? this._instances[recentTaskKey].instances : 0; + this._currentTask = new VerifiedTask(task, resolver, trigger); if (instance > 0) { - task.instance = this.instances[recentTaskKey].counter; + task.instance = this._instances[recentTaskKey].counter; } let lastTaskInstance = this.getLastInstance(task); - let terminalData = lastTaskInstance ? this.activeTasks[lastTaskInstance.getMapKey()] : undefined; + let terminalData = lastTaskInstance ? this._activeTasks[lastTaskInstance.getMapKey()] : undefined; if (terminalData && terminalData.promise && !validInstance) { - this.lastTask = this.currentTask; + this._lastTask = this._currentTask; return { kind: TaskExecuteKind.Active, task: terminalData.task, active: { same: true, background: task.configurationProperties.isBackground! }, promise: terminalData.promise }; } try { - const executeResult = { kind: TaskExecuteKind.Started, task, started: {}, promise: this.executeTask(task, resolver, trigger, new Set()) }; + const executeResult = { kind: TaskExecuteKind.Started, task, started: {}, promise: this._executeTask(task, resolver, trigger, new Set()) }; executeResult.promise.then(summary => { - this.lastTask = this.currentTask; + this._lastTask = this._currentTask; }); - if (InMemoryTask.is(task) || !this.isTaskEmpty(task)) { - if (!this.instances[recentTaskKey]) { - this.instances[recentTaskKey] = new InstanceManager(); + if (InMemoryTask.is(task) || !this._isTaskEmpty(task)) { + if (!this._instances[recentTaskKey]) { + this._instances[recentTaskKey] = new InstanceManager(); } - this.instances[recentTaskKey].addInstance(); + this._instances[recentTaskKey].addInstance(); } return executeResult; } catch (error) { if (error instanceof TaskError) { throw error; } else if (error instanceof Error) { - this.log(error.message); + this._log(error.message); throw new TaskError(Severity.Error, error.message, TaskErrors.UnknownError); } else { - this.log(error.toString()); + this._log(error.toString()); throw new TaskError(Severity.Error, nls.localize('TerminalTaskSystem.unknownError', 'A unknown error has occurred while executing a task. See task output log for details.'), TaskErrors.UnknownError); } } } public rerun(): ITaskExecuteResult | undefined { - if (this.lastTask && this.lastTask.verify()) { - if ((this.lastTask.task.runOptions.reevaluateOnRerun !== undefined) && !this.lastTask.task.runOptions.reevaluateOnRerun) { - this.isRerun = true; + if (this._lastTask && this._lastTask.verify()) { + if ((this._lastTask.task.runOptions.reevaluateOnRerun !== undefined) && !this._lastTask.task.runOptions.reevaluateOnRerun) { + this._isRerun = true; } - const result = this.run(this.lastTask.task, this.lastTask.resolver); + const result = this.run(this._lastTask.task, this._lastTask.resolver); result.promise.then(summary => { - this.isRerun = false; + this._isRerun = false; }); return result; } else { @@ -306,59 +307,59 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } } - private showTaskLoadErrors(task: Task) { + private _showTaskLoadErrors(task: Task) { if (task.taskLoadMessages && task.taskLoadMessages.length > 0) { task.taskLoadMessages.forEach(loadMessage => { - this.log(loadMessage + '\n'); + this._log(loadMessage + '\n'); }); const openOutput = 'Show Output'; - this.notificationService.prompt(Severity.Warning, + this._notificationService.prompt(Severity.Warning, nls.localize('TerminalTaskSystem.taskLoadReporting', "There are issues with task \"{0}\". See the output for more details.", task._label), [{ label: openOutput, - run: () => this.showOutput() + run: () => this._showOutput() }]); } } public isTaskVisible(task: Task): boolean { - let terminalData = this.activeTasks[task.getMapKey()]; + let terminalData = this._activeTasks[task.getMapKey()]; if (!terminalData) { return false; } - const activeTerminalInstance = this.terminalService.activeInstance; - const isPanelShowingTerminal = !!this.viewsService.getActiveViewWithId(TERMINAL_VIEW_ID); + const activeTerminalInstance = this._terminalService.activeInstance; + const isPanelShowingTerminal = !!this._viewsService.getActiveViewWithId(TERMINAL_VIEW_ID); return isPanelShowingTerminal && (activeTerminalInstance?.instanceId === terminalData.terminal.instanceId); } public revealTask(task: Task): boolean { - let terminalData = this.activeTasks[task.getMapKey()]; + let terminalData = this._activeTasks[task.getMapKey()]; if (!terminalData) { return false; } - const isTerminalInPanel: boolean = this.viewDescriptorService.getViewLocationById(TERMINAL_VIEW_ID) === ViewContainerLocation.Panel; + const isTerminalInPanel: boolean = this._viewDescriptorService.getViewLocationById(TERMINAL_VIEW_ID) === ViewContainerLocation.Panel; if (isTerminalInPanel && this.isTaskVisible(task)) { - if (this.previousPanelId) { - if (this.previousTerminalInstance) { - this.terminalService.setActiveInstance(this.previousTerminalInstance); + if (this._previousPanelId) { + if (this._previousTerminalInstance) { + this._terminalService.setActiveInstance(this._previousTerminalInstance); } - this.paneCompositeService.openPaneComposite(this.previousPanelId, ViewContainerLocation.Panel); + this._paneCompositeService.openPaneComposite(this._previousPanelId, ViewContainerLocation.Panel); } else { - this.paneCompositeService.hideActivePaneComposite(ViewContainerLocation.Panel); + this._paneCompositeService.hideActivePaneComposite(ViewContainerLocation.Panel); } - this.previousPanelId = undefined; - this.previousTerminalInstance = undefined; + this._previousPanelId = undefined; + this._previousTerminalInstance = undefined; } else { if (isTerminalInPanel) { - this.previousPanelId = this.paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel)?.getId(); - if (this.previousPanelId === TERMINAL_VIEW_ID) { - this.previousTerminalInstance = this.terminalService.activeInstance ?? undefined; + this._previousPanelId = this._paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel)?.getId(); + if (this._previousPanelId === TERMINAL_VIEW_ID) { + this._previousTerminalInstance = this._terminalService.activeInstance ?? undefined; } } - this.terminalService.setActiveInstance(terminalData.terminal); + this._terminalService.setActiveInstance(terminalData.terminal); if (CustomTask.is(task) || ContributedTask.is(task)) { - this.terminalGroupService.showPanel(task.command.presentation!.focus); + this._terminalGroupService.showPanel(task.command.presentation!.focus); } } return true; @@ -369,34 +370,34 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } public isActiveSync(): boolean { - return Object.keys(this.activeTasks).length > 0; + return Object.keys(this._activeTasks).length > 0; } public canAutoTerminate(): boolean { - return Object.keys(this.activeTasks).every(key => !this.activeTasks[key].task.configurationProperties.promptOnClose); + return Object.keys(this._activeTasks).every(key => !this._activeTasks[key].task.configurationProperties.promptOnClose); } public getActiveTasks(): Task[] { - return Object.keys(this.activeTasks).map(key => this.activeTasks[key].task); + return Object.keys(this._activeTasks).map(key => this._activeTasks[key].task); } public getLastInstance(task: Task): Task | undefined { let lastInstance = undefined; const recentKey = task.getRecentlyUsedKey(); - Object.keys(this.activeTasks).forEach((key) => { - if (recentKey && recentKey === this.activeTasks[key].task.getRecentlyUsedKey()) { - lastInstance = this.activeTasks[key].task; + Object.keys(this._activeTasks).forEach((key) => { + if (recentKey && recentKey === this._activeTasks[key].task.getRecentlyUsedKey()) { + lastInstance = this._activeTasks[key].task; } }); return lastInstance; } public getBusyTasks(): Task[] { - return Object.keys(this.busyTasks).map(key => this.busyTasks[key]); + return Object.keys(this._busyTasks).map(key => this._busyTasks[key]); } public customExecutionComplete(task: Task, result: number): Promise { - let activeTerminal = this.activeTasks[task.getMapKey()]; + let activeTerminal = this._activeTasks[task.getMapKey()]; if (!activeTerminal) { return Promise.reject(new Error('Expected to have a terminal for an custom execution task')); } @@ -407,27 +408,27 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { }); } - private removeInstances(task: Task) { + private _removeInstances(task: Task) { const recentTaskKey = task.getRecentlyUsedKey() ?? ''; - if (this.instances[recentTaskKey]) { - this.instances[recentTaskKey].removeInstance(); - if (this.instances[recentTaskKey].instances === 0) { - delete this.instances[recentTaskKey]; + if (this._instances[recentTaskKey]) { + this._instances[recentTaskKey].removeInstance(); + if (this._instances[recentTaskKey].instances === 0) { + delete this._instances[recentTaskKey]; } } } - private removeFromActiveTasks(task: Task): void { - if (!this.activeTasks[task.getMapKey()]) { + private _removeFromActiveTasks(task: Task): void { + if (!this._activeTasks[task.getMapKey()]) { return; } - delete this.activeTasks[task.getMapKey()]; - this.removeInstances(task); + delete this._activeTasks[task.getMapKey()]; + this._removeInstances(task); } - private fireTaskEvent(event: ITaskEvent) { + private _fireTaskEvent(event: ITaskEvent) { if (event.__task) { - const activeTask = this.activeTasks[event.__task.getMapKey()]; + const activeTask = this._activeTasks[event.__task.getMapKey()]; if (activeTask) { activeTask.state = event.kind; } @@ -436,7 +437,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } public terminate(task: Task): Promise { - let activeTerminal = this.activeTasks[task.getMapKey()]; + let activeTerminal = this._activeTasks[task.getMapKey()]; if (!activeTerminal) { return Promise.resolve({ success: false, task: undefined }); } @@ -447,7 +448,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { let task = activeTerminal.task; try { onExit.dispose(); - this.fireTaskEvent(TaskEvent.create(TaskEventKind.Terminated, task)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.Terminated, task)); } catch (error) { // Do nothing. } @@ -459,15 +460,15 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { public terminateAll(): Promise { let promises: Promise[] = []; - Object.keys(this.activeTasks).forEach((key) => { - let terminalData = this.activeTasks[key]; + Object.keys(this._activeTasks).forEach((key) => { + let terminalData = this._activeTasks[key]; let terminal = terminalData.terminal; promises.push(new Promise((resolve, reject) => { const onExit = terminal.onExit(() => { let task = terminalData.task; try { onExit.dispose(); - this.fireTaskEvent(TaskEvent.create(TaskEventKind.Terminated, task)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.Terminated, task)); } catch (error) { // Do nothing. } @@ -476,26 +477,26 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { })); terminal.dispose(); }); - this.activeTasks = Object.create(null); + this._activeTasks = Object.create(null); return Promise.all(promises); } - private showDependencyCycleMessage(task: Task) { - this.log(nls.localize('dependencyCycle', + private _showDependencyCycleMessage(task: Task) { + this._log(nls.localize('dependencyCycle', 'There is a dependency cycle. See task "{0}".', task._label )); - this.showOutput(); + this._showOutput(); } - private async executeTask(task: Task, resolver: ITaskResolver, trigger: string, encounteredDependencies: Set, alreadyResolved?: Map): Promise { + private async _executeTask(task: Task, resolver: ITaskResolver, trigger: string, encounteredDependencies: Set, alreadyResolved?: Map): Promise { if (encounteredDependencies.has(task.getCommonTaskId())) { - this.showDependencyCycleMessage(task); + this._showDependencyCycleMessage(task); return {}; } - this.showTaskLoadErrors(task); + this._showTaskLoadErrors(task); alreadyResolved = alreadyResolved ?? new Map(); let promises: Promise[] = []; @@ -504,11 +505,11 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { let dependencyTask = await resolver.resolve(dependency.uri, dependency.task!); if (dependencyTask) { let key = dependencyTask.getMapKey(); - let promise = this.activeTasks[key] ? this.getDependencyPromise(this.activeTasks[key]) : undefined; + let promise = this._activeTasks[key] ? this._getDependencyPromise(this._activeTasks[key]) : undefined; if (!promise) { - this.fireTaskEvent(TaskEvent.create(TaskEventKind.DependsOnStarted, task)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.DependsOnStarted, task)); encounteredDependencies.add(task.getCommonTaskId()); - promise = this.executeDependencyTask(dependencyTask, resolver, trigger, encounteredDependencies, alreadyResolved); + promise = this._executeDependencyTask(dependencyTask, resolver, trigger, encounteredDependencies, alreadyResolved); } promises.push(promise); if (task.configurationProperties.dependsOrder === DependsOrder.sequence) { @@ -522,12 +523,12 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } promises.push(promise); } else { - this.log(nls.localize('dependencyFailed', + this._log(nls.localize('dependencyFailed', 'Couldn\'t resolve dependent task \'{0}\' in workspace folder \'{1}\'', Types.isString(dependency.task) ? dependency.task : JSON.stringify(dependency.task, undefined, 0), dependency.uri.toString() )); - this.showOutput(); + this._showOutput(); } } } @@ -537,14 +538,14 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { encounteredDependencies.delete(task.getCommonTaskId()); for (let summary of summaries) { if (summary.exitCode !== 0) { - this.removeInstances(task); + this._removeInstances(task); return { exitCode: summary.exitCode }; } } - if (this.isRerun) { - return this.reexecuteCommand(task, trigger, alreadyResolved!); + if (this._isRerun) { + return this._reexecuteCommand(task, trigger, alreadyResolved!); } else { - return this.executeCommand(task, trigger, alreadyResolved!); + return this._executeCommand(task, trigger, alreadyResolved!); } }); } else { @@ -560,7 +561,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } } - private createInactiveDependencyPromise(task: Task): Promise { + private _createInactiveDependencyPromise(task: Task): Promise { return new Promise(resolve => { const taskInactiveDisposable = this.onDidStateChange(taskEvent => { if ((taskEvent.kind === TaskEventKind.Inactive) && (taskEvent.__task === task)) { @@ -571,7 +572,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { }); } - private async getDependencyPromise(task: IActiveTerminalData): Promise { + private async _getDependencyPromise(task: IActiveTerminalData): Promise { if (!task.task.configurationProperties.isBackground) { return task.promise; } @@ -581,24 +582,24 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (task.state === TaskEventKind.Inactive) { return { exitCode: 0 }; } - return this.createInactiveDependencyPromise(task.task); + return this._createInactiveDependencyPromise(task.task); } - private async executeDependencyTask(task: Task, resolver: ITaskResolver, trigger: string, encounteredDependencies: Set, alreadyResolved?: Map): Promise { + private async _executeDependencyTask(task: Task, resolver: ITaskResolver, trigger: string, encounteredDependencies: Set, alreadyResolved?: Map): Promise { // If the task is a background task with a watching problem matcher, we don't wait for the whole task to finish, // just for the problem matcher to go inactive. if (!task.configurationProperties.isBackground) { - return this.executeTask(task, resolver, trigger, encounteredDependencies, alreadyResolved); + return this._executeTask(task, resolver, trigger, encounteredDependencies, alreadyResolved); } - const inactivePromise = this.createInactiveDependencyPromise(task); - return Promise.race([inactivePromise, this.executeTask(task, resolver, trigger, encounteredDependencies, alreadyResolved)]); + const inactivePromise = this._createInactiveDependencyPromise(task); + return Promise.race([inactivePromise, this._executeTask(task, resolver, trigger, encounteredDependencies, alreadyResolved)]); } - private async resolveAndFindExecutable(systemInfo: ITaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder | undefined, task: CustomTask | ContributedTask, cwd: string | undefined, envPath: string | undefined): Promise { - const command = await this.configurationResolverService.resolveAsync(workspaceFolder, CommandString.value(task.command.name!)); - cwd = cwd ? await this.configurationResolverService.resolveAsync(workspaceFolder, cwd) : undefined; - const paths = envPath ? await Promise.all(envPath.split(path.delimiter).map(p => this.configurationResolverService.resolveAsync(workspaceFolder, p))) : undefined; + private async _resolveAndFindExecutable(systemInfo: ITaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder | undefined, task: CustomTask | ContributedTask, cwd: string | undefined, envPath: string | undefined): Promise { + const command = await this._configurationResolverService.resolveAsync(workspaceFolder, CommandString.value(task.command.name!)); + cwd = cwd ? await this._configurationResolverService.resolveAsync(workspaceFolder, cwd) : undefined; + const paths = envPath ? await Promise.all(envPath.split(path.delimiter).map(p => this._configurationResolverService.resolveAsync(workspaceFolder, p))) : undefined; let foundExecutable = await systemInfo?.findExecutable(command, cwd, paths); if (!foundExecutable) { foundExecutable = path.join(cwd ?? '', command); @@ -606,7 +607,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { return foundExecutable; } - private findUnresolvedVariables(variables: Set, alreadyResolved: Map): Set { + private _findUnresolvedVariables(variables: Set, alreadyResolved: Map): Set { if (alreadyResolved.size === 0) { return variables; } @@ -619,7 +620,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { return unresolved; } - private mergeMaps(mergeInto: Map, mergeFrom: Map) { + private _mergeMaps(mergeInto: Map, mergeFrom: Map) { for (const entry of mergeFrom) { if (!mergeInto.has(entry[0])) { mergeInto.set(entry[0], entry[1]); @@ -627,13 +628,13 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } } - private async acquireInput(taskSystemInfo: ITaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder | undefined, task: CustomTask | ContributedTask, variables: Set, alreadyResolved: Map): Promise { - const resolved = await this.resolveVariablesFromSet(taskSystemInfo, workspaceFolder, task, variables, alreadyResolved); - this.fireTaskEvent(TaskEvent.create(TaskEventKind.AcquiredInput, task)); + private async _acquireInput(taskSystemInfo: ITaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder | undefined, task: CustomTask | ContributedTask, variables: Set, alreadyResolved: Map): Promise { + const resolved = await this._resolveVariablesFromSet(taskSystemInfo, workspaceFolder, task, variables, alreadyResolved); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.AcquiredInput, task)); return resolved; } - private resolveVariablesFromSet(taskSystemInfo: ITaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder | undefined, task: CustomTask | ContributedTask, variables: Set, alreadyResolved: Map): Promise { + private _resolveVariablesFromSet(taskSystemInfo: ITaskSystemInfo | undefined, workspaceFolder: IWorkspaceFolder | undefined, task: CustomTask | ContributedTask, variables: Set, alreadyResolved: Map): Promise { let isProcess = task.command && task.command.runtime === RuntimeType.Process; let options = task.command && task.command.options ? task.command.options : undefined; let cwd = options ? options.cwd : undefined; @@ -648,7 +649,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } } } - const unresolved = this.findUnresolvedVariables(variables, alreadyResolved); + const unresolved = this._findUnresolvedVariables(variables, alreadyResolved); let resolvedVariables: Promise; if (taskSystemInfo && workspaceFolder) { let resolveSet: IResolveSet = { @@ -669,12 +670,12 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { return undefined; } - this.mergeMaps(alreadyResolved, resolved.variables); + this._mergeMaps(alreadyResolved, resolved.variables); resolved.variables = new Map(alreadyResolved); if (isProcess) { let process = CommandString.value(task.command.name!); if (taskSystemInfo.platform === Platform.Platform.Windows) { - process = await this.resolveAndFindExecutable(taskSystemInfo, workspaceFolder, task, cwd, envPath); + process = await this._resolveAndFindExecutable(taskSystemInfo, workspaceFolder, task, cwd, envPath); } resolved.variables.set(TerminalTaskSystem.ProcessVarName, process); } @@ -686,16 +687,16 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { unresolved.forEach(variable => variablesArray.push(variable)); return new Promise((resolve, reject) => { - this.configurationResolverService.resolveWithInteraction(workspaceFolder, variablesArray, 'tasks', undefined, TaskSourceKind.toConfigurationTarget(task._source.kind)).then(async (resolvedVariablesMap: Map | undefined) => { + this._configurationResolverService.resolveWithInteraction(workspaceFolder, variablesArray, 'tasks', undefined, TaskSourceKind.toConfigurationTarget(task._source.kind)).then(async (resolvedVariablesMap: Map | undefined) => { if (resolvedVariablesMap) { - this.mergeMaps(alreadyResolved, resolvedVariablesMap); + this._mergeMaps(alreadyResolved, resolvedVariablesMap); resolvedVariablesMap = new Map(alreadyResolved); if (isProcess) { let processVarValue: string; if (Platform.isWindows) { - processVarValue = await this.resolveAndFindExecutable(taskSystemInfo, workspaceFolder, task, cwd, envPath); + processVarValue = await this._resolveAndFindExecutable(taskSystemInfo, workspaceFolder, task, cwd, envPath); } else { - processVarValue = await this.configurationResolverService.resolveAsync(workspaceFolder, CommandString.value(task.command.name!)); + processVarValue = await this._configurationResolverService.resolveAsync(workspaceFolder, CommandString.value(task.command.name!)); } resolvedVariablesMap.set(TerminalTaskSystem.ProcessVarName, processVarValue); } @@ -713,28 +714,28 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } } - private executeCommand(task: CustomTask | ContributedTask, trigger: string, alreadyResolved: Map): Promise { + private _executeCommand(task: CustomTask | ContributedTask, trigger: string, alreadyResolved: Map): Promise { const taskWorkspaceFolder = task.getWorkspaceFolder(); let workspaceFolder: IWorkspaceFolder | undefined; if (taskWorkspaceFolder) { - workspaceFolder = this.currentTask.workspaceFolder = taskWorkspaceFolder; + workspaceFolder = this._currentTask.workspaceFolder = taskWorkspaceFolder; } else { - const folders = this.contextService.getWorkspace().folders; + const folders = this._contextService.getWorkspace().folders; workspaceFolder = folders.length > 0 ? folders[0] : undefined; } - const systemInfo: ITaskSystemInfo | undefined = this.currentTask.systemInfo = this.taskSystemInfoResolver(workspaceFolder); + const systemInfo: ITaskSystemInfo | undefined = this._currentTask.systemInfo = this._taskSystemInfoResolver(workspaceFolder); let variables = new Set(); - this.collectTaskVariables(variables, task); - const resolvedVariables = this.acquireInput(systemInfo, workspaceFolder, task, variables, alreadyResolved); + this._collectTaskVariables(variables, task); + const resolvedVariables = this._acquireInput(systemInfo, workspaceFolder, task, variables, alreadyResolved); return resolvedVariables.then((resolvedVariables) => { - if (resolvedVariables && !this.isTaskEmpty(task)) { - this.currentTask.resolvedVariables = resolvedVariables; - return this.executeInTerminal(task, trigger, new VariableResolver(workspaceFolder, systemInfo, resolvedVariables.variables, this.configurationResolverService), workspaceFolder); + if (resolvedVariables && !this._isTaskEmpty(task)) { + this._currentTask.resolvedVariables = resolvedVariables; + return this._executeInTerminal(task, trigger, new VariableResolver(workspaceFolder, systemInfo, resolvedVariables.variables, this._configurationResolverService), workspaceFolder); } else { // Allows the taskExecutions array to be updated in the extension host - this.fireTaskEvent(TaskEvent.create(TaskEventKind.End, task)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.End, task)); return Promise.resolve({ exitCode: 0 }); } }, reason => { @@ -742,19 +743,19 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { }); } - private isTaskEmpty(task: CustomTask | ContributedTask): boolean { + private _isTaskEmpty(task: CustomTask | ContributedTask): boolean { const isCustomExecution = (task.command.runtime === RuntimeType.CustomExecution); return !((task.command !== undefined) && task.command.runtime && (isCustomExecution || (task.command.name !== undefined))); } - private reexecuteCommand(task: CustomTask | ContributedTask, trigger: string, alreadyResolved: Map): Promise { - const lastTask = this.lastTask; + private _reexecuteCommand(task: CustomTask | ContributedTask, trigger: string, alreadyResolved: Map): Promise { + const lastTask = this._lastTask; if (!lastTask) { return Promise.reject(new Error('No task previously run')); } - const workspaceFolder = this.currentTask.workspaceFolder = lastTask.workspaceFolder; + const workspaceFolder = this._currentTask.workspaceFolder = lastTask.workspaceFolder; let variables = new Set(); - this.collectTaskVariables(variables, task); + this._collectTaskVariables(variables, task); // Check that the task hasn't changed to include new variables let hasAllVariables = true; @@ -765,33 +766,33 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { }); if (!hasAllVariables) { - return this.acquireInput(lastTask.getVerifiedTask().systemInfo, lastTask.getVerifiedTask().workspaceFolder, task, variables, alreadyResolved).then((resolvedVariables) => { + return this._acquireInput(lastTask.getVerifiedTask().systemInfo, lastTask.getVerifiedTask().workspaceFolder, task, variables, alreadyResolved).then((resolvedVariables) => { if (!resolvedVariables) { // Allows the taskExecutions array to be updated in the extension host - this.fireTaskEvent(TaskEvent.create(TaskEventKind.End, task)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.End, task)); return { exitCode: 0 }; } - this.currentTask.resolvedVariables = resolvedVariables; - return this.executeInTerminal(task, trigger, new VariableResolver(lastTask.getVerifiedTask().workspaceFolder, lastTask.getVerifiedTask().systemInfo, resolvedVariables.variables, this.configurationResolverService), workspaceFolder!); + this._currentTask.resolvedVariables = resolvedVariables; + return this._executeInTerminal(task, trigger, new VariableResolver(lastTask.getVerifiedTask().workspaceFolder, lastTask.getVerifiedTask().systemInfo, resolvedVariables.variables, this._configurationResolverService), workspaceFolder!); }, reason => { return Promise.reject(reason); }); } else { - this.currentTask.resolvedVariables = lastTask.getVerifiedTask().resolvedVariables; - return this.executeInTerminal(task, trigger, new VariableResolver(lastTask.getVerifiedTask().workspaceFolder, lastTask.getVerifiedTask().systemInfo, lastTask.getVerifiedTask().resolvedVariables.variables, this.configurationResolverService), workspaceFolder!); + this._currentTask.resolvedVariables = lastTask.getVerifiedTask().resolvedVariables; + return this._executeInTerminal(task, trigger, new VariableResolver(lastTask.getVerifiedTask().workspaceFolder, lastTask.getVerifiedTask().systemInfo, lastTask.getVerifiedTask().resolvedVariables.variables, this._configurationResolverService), workspaceFolder!); } } - private async executeInTerminal(task: CustomTask | ContributedTask, trigger: string, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder | undefined): Promise { + private async _executeInTerminal(task: CustomTask | ContributedTask, trigger: string, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder | undefined): Promise { let terminal: ITerminalInstance | undefined = undefined; let error: TaskError | undefined = undefined; let promise: Promise | undefined = undefined; if (task.configurationProperties.isBackground) { - const problemMatchers = await this.resolveMatchers(resolver, task.configurationProperties.problemMatchers); - let watchingProblemMatcher = new WatchingProblemCollector(problemMatchers, this.markerService, this.modelService, this.fileService); + const problemMatchers = await this._resolveMatchers(resolver, task.configurationProperties.problemMatchers); + let watchingProblemMatcher = new WatchingProblemCollector(problemMatchers, this._markerService, this._modelService, this._fileService); if ((problemMatchers.length > 0) && !watchingProblemMatcher.isWatching()) { - this.appendOutput(nls.localize('TerminalTaskSystem.nonWatchingMatcher', 'Task {0} is a background task but uses a problem matcher without a background pattern', task._label)); - this.showOutput(); + this._appendOutput(nls.localize('TerminalTaskSystem.nonWatchingMatcher', 'Task {0} is a background task but uses a problem matcher without a background pattern', task._label)); + this._showOutput(); } const toDispose = new DisposableStore(); let eventCounter: number = 0; @@ -799,24 +800,24 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { toDispose.add(watchingProblemMatcher.onDidStateChange((event) => { if (event.kind === ProblemCollectorEventKind.BackgroundProcessingBegins) { eventCounter++; - this.busyTasks[mapKey] = task; - this.fireTaskEvent(TaskEvent.create(TaskEventKind.Active, task)); + this._busyTasks[mapKey] = task; + this._fireTaskEvent(TaskEvent.create(TaskEventKind.Active, task)); } else if (event.kind === ProblemCollectorEventKind.BackgroundProcessingEnds) { eventCounter--; - if (this.busyTasks[mapKey]) { - delete this.busyTasks[mapKey]; + if (this._busyTasks[mapKey]) { + delete this._busyTasks[mapKey]; } - this.fireTaskEvent(TaskEvent.create(TaskEventKind.Inactive, task)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.Inactive, task)); if (eventCounter === 0) { if ((watchingProblemMatcher.numberOfMatches > 0) && watchingProblemMatcher.maxMarkerSeverity && (watchingProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error)) { let reveal = task.command.presentation!.reveal; let revealProblems = task.command.presentation!.revealProblems; if (revealProblems === RevealProblemKind.OnProblem) { - this.viewsService.openView(Markers.MARKERS_VIEW_ID, true); + this._viewsService.openView(Markers.MARKERS_VIEW_ID, true); } else if (reveal === RevealKind.Silent) { - this.terminalService.setActiveInstance(terminal!); - this.terminalGroupService.showPanel(false); + this._terminalService.setActiveInstance(terminal!); + this._terminalGroupService.showPanel(false); } } } @@ -824,7 +825,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { })); watchingProblemMatcher.aboutToStart(); let delayer: Async.Delayer | undefined = undefined; - [terminal, error] = await this.createTerminal(task, resolver, workspaceFolder); + [terminal, error] = await this._createTerminal(task, resolver, workspaceFolder); if (error) { return Promise.reject(new Error((error).message)); @@ -832,18 +833,18 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (!terminal) { return Promise.reject(new Error(`Failed to create terminal for task ${task._label}`)); } - this.terminalStatusManager.addTerminal(task, terminal, watchingProblemMatcher); + this._terminalStatusManager.addTerminal(task, terminal, watchingProblemMatcher); let processStartedSignaled = false; terminal.processReady.then(() => { if (!processStartedSignaled) { - this.fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!)); processStartedSignaled = true; } }, (_error) => { - this.logService.error('Task terminal process never got ready'); + this._logService.error('Task terminal process never got ready'); }); - this.fireTaskEvent(TaskEvent.create(TaskEventKind.Start, task, terminal.instanceId)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.Start, task, terminal.instanceId)); const onData = terminal.onLineData((line) => { watchingProblemMatcher.processLine(line); if (!delayer) { @@ -860,19 +861,19 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { onData.dispose(); onExit.dispose(); let key = task.getMapKey(); - if (this.busyTasks[mapKey]) { - delete this.busyTasks[mapKey]; + if (this._busyTasks[mapKey]) { + delete this._busyTasks[mapKey]; } - this.removeFromActiveTasks(task); - this.fireTaskEvent(TaskEvent.create(TaskEventKind.Changed)); + this._removeFromActiveTasks(task); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.Changed)); if (terminalLaunchResult !== undefined) { // Only keep a reference to the terminal if it is not being disposed. switch (task.command.presentation!.panel) { case PanelKind.Dedicated: - this.sameTaskTerminals[key] = terminal!.instanceId.toString(); + this._sameTaskTerminals[key] = terminal!.instanceId.toString(); break; case PanelKind.Shared: - this.idleTaskTerminals.set(key, terminal!.instanceId.toString(), Touch.AsOld); + this._idleTaskTerminals.set(key, terminal!.instanceId.toString(), Touch.AsOld); break; } } @@ -880,8 +881,8 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if ((reveal === RevealKind.Silent) && ((exitCode !== 0) || (watchingProblemMatcher.numberOfMatches > 0) && watchingProblemMatcher.maxMarkerSeverity && (watchingProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error))) { try { - this.terminalService.setActiveInstance(terminal!); - this.terminalGroupService.showPanel(false); + this._terminalService.setActiveInstance(terminal!); + this._terminalGroupService.showPanel(false); } catch (e) { // If the terminal has already been disposed, then setting the active instance will fail. #99828 // There is nothing else to do here. @@ -890,23 +891,23 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { watchingProblemMatcher.done(); watchingProblemMatcher.dispose(); if (!processStartedSignaled) { - this.fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!)); processStartedSignaled = true; } - this.fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessEnded, task, exitCode ?? undefined)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessEnded, task, exitCode ?? undefined)); for (let i = 0; i < eventCounter; i++) { - this.fireTaskEvent(TaskEvent.create(TaskEventKind.Inactive, task)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.Inactive, task)); } eventCounter = 0; - this.fireTaskEvent(TaskEvent.create(TaskEventKind.End, task)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.End, task)); toDispose.dispose(); resolve({ exitCode: exitCode ?? undefined }); }); }); } else { - [terminal, error] = await this.createTerminal(task, resolver, workspaceFolder); + [terminal, error] = await this._createTerminal(task, resolver, workspaceFolder); if (error) { return Promise.reject(new Error((error).message)); @@ -918,19 +919,19 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { let processStartedSignaled = false; terminal.processReady.then(() => { if (!processStartedSignaled) { - this.fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!)); processStartedSignaled = true; } }, (_error) => { // The process never got ready. Need to think how to handle this. }); - this.fireTaskEvent(TaskEvent.create(TaskEventKind.Start, task, terminal.instanceId, resolver.values)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.Start, task, terminal.instanceId, resolver.values)); const mapKey = task.getMapKey(); - this.busyTasks[mapKey] = task; - this.fireTaskEvent(TaskEvent.create(TaskEventKind.Active, task)); - let problemMatchers = await this.resolveMatchers(resolver, task.configurationProperties.problemMatchers); - let startStopProblemMatcher = new StartStopProblemCollector(problemMatchers, this.markerService, this.modelService, ProblemHandlingStrategy.Clean, this.fileService); - this.terminalStatusManager.addTerminal(task, terminal, startStopProblemMatcher); + this._busyTasks[mapKey] = task; + this._fireTaskEvent(TaskEvent.create(TaskEventKind.Active, task)); + let problemMatchers = await this._resolveMatchers(resolver, task.configurationProperties.problemMatchers); + let startStopProblemMatcher = new StartStopProblemCollector(problemMatchers, this._markerService, this._modelService, ProblemHandlingStrategy.Clean, this._fileService); + this._terminalStatusManager.addTerminal(task, terminal, startStopProblemMatcher); const onData = terminal.onLineData((line) => { startStopProblemMatcher.processLine(line); }); @@ -939,16 +940,16 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { const exitCode = typeof terminalLaunchResult === 'number' ? terminalLaunchResult : terminalLaunchResult?.code; onExit.dispose(); let key = task.getMapKey(); - this.removeFromActiveTasks(task); - this.fireTaskEvent(TaskEvent.create(TaskEventKind.Changed)); + this._removeFromActiveTasks(task); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.Changed)); if (terminalLaunchResult !== undefined) { // Only keep a reference to the terminal if it is not being disposed. switch (task.command.presentation!.panel) { case PanelKind.Dedicated: - this.sameTaskTerminals[key] = terminal!.instanceId.toString(); + this._sameTaskTerminals[key] = terminal!.instanceId.toString(); break; case PanelKind.Shared: - this.idleTaskTerminals.set(key, terminal!.instanceId.toString(), Touch.AsOld); + this._idleTaskTerminals.set(key, terminal!.instanceId.toString(), Touch.AsOld); break; } } @@ -956,12 +957,12 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { let revealProblems = task.command.presentation!.revealProblems; let revealProblemPanel = terminal && (revealProblems === RevealProblemKind.OnProblem) && (startStopProblemMatcher.numberOfMatches > 0); if (revealProblemPanel) { - this.viewsService.openView(Markers.MARKERS_VIEW_ID); + this._viewsService.openView(Markers.MARKERS_VIEW_ID); } else if (terminal && (reveal === RevealKind.Silent) && ((exitCode !== 0) || (startStopProblemMatcher.numberOfMatches > 0) && startStopProblemMatcher.maxMarkerSeverity && (startStopProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error))) { try { - this.terminalService.setActiveInstance(terminal); - this.terminalGroupService.showPanel(false); + this._terminalService.setActiveInstance(terminal); + this._terminalGroupService.showPanel(false); } catch (e) { // If the terminal has already been disposed, then setting the active instance will fail. #99828 // There is nothing else to do here. @@ -974,16 +975,16 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { startStopProblemMatcher.dispose(); }, 100); if (!processStartedSignaled && terminal) { - this.fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal.processId!)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal.processId!)); processStartedSignaled = true; } - this.fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessEnded, task, exitCode ?? undefined)); - if (this.busyTasks[mapKey]) { - delete this.busyTasks[mapKey]; + this._fireTaskEvent(TaskEvent.create(TaskEventKind.ProcessEnded, task, exitCode ?? undefined)); + if (this._busyTasks[mapKey]) { + delete this._busyTasks[mapKey]; } - this.fireTaskEvent(TaskEvent.create(TaskEventKind.Inactive, task)); - this.fireTaskEvent(TaskEvent.create(TaskEventKind.End, task)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.Inactive, task)); + this._fireTaskEvent(TaskEvent.create(TaskEventKind.End, task)); resolve({ exitCode: exitCode ?? undefined }); }); }); @@ -991,26 +992,26 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { let showProblemPanel = task.command.presentation && (task.command.presentation.revealProblems === RevealProblemKind.Always); if (showProblemPanel) { - this.viewsService.openView(Markers.MARKERS_VIEW_ID); + this._viewsService.openView(Markers.MARKERS_VIEW_ID); } else if (task.command.presentation && (task.command.presentation.reveal === RevealKind.Always)) { - this.terminalService.setActiveInstance(terminal); - this.terminalGroupService.showPanel(task.command.presentation.focus); + this._terminalService.setActiveInstance(terminal); + this._terminalGroupService.showPanel(task.command.presentation.focus); } - this.activeTasks[task.getMapKey()] = { terminal, task, promise }; - this.fireTaskEvent(TaskEvent.create(TaskEventKind.Changed)); + this._activeTasks[task.getMapKey()] = { terminal, task, promise }; + this._fireTaskEvent(TaskEvent.create(TaskEventKind.Changed)); return promise; } - private createTerminalName(task: CustomTask | ContributedTask): string { - const needsFolderQualification = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; + private _createTerminalName(task: CustomTask | ContributedTask): string { + const needsFolderQualification = this._contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; return needsFolderQualification ? task.getQualifiedLabel() : (task.configurationProperties.name || ''); } - private async createShellLaunchConfig(task: CustomTask | ContributedTask, workspaceFolder: IWorkspaceFolder | undefined, variableResolver: VariableResolver, platform: Platform.Platform, options: CommandOptions, command: CommandString, args: CommandString[], waitOnExit: boolean | string): Promise { + private async _createShellLaunchConfig(task: CustomTask | ContributedTask, workspaceFolder: IWorkspaceFolder | undefined, variableResolver: VariableResolver, platform: Platform.Platform, options: CommandOptions, command: CommandString, args: CommandString[], waitOnExit: boolean | string): Promise { let shellLaunchConfig: IShellLaunchConfig; let isShellCommand = task.command.runtime === RuntimeType.Shell; - let needsFolderQualification = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; - let terminalName = this.createTerminalName(task); + let needsFolderQualification = this._contextService.getWorkbenchState() === WorkbenchState.WORKSPACE; + let terminalName = this._createTerminalName(task); const type = 'Task'; let originalCommand = task.command.name; if (isShellCommand) { @@ -1021,10 +1022,10 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { case Platform.Platform.Linux: default: os = Platform.OperatingSystem.Linux; break; } - const defaultProfile = await this.terminalProfileResolverService.getDefaultProfile({ + const defaultProfile = await this._terminalProfileResolverService.getDefaultProfile({ allowAutomationShell: true, os, - remoteAuthority: this.environmentService.remoteAuthority + remoteAuthority: this._environmentService.remoteAuthority }); shellLaunchConfig = { name: terminalName, @@ -1044,11 +1045,11 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (shellOptions.executable !== shellLaunchConfig.executable) { shellLaunchConfig.args = undefined; } - shellLaunchConfig.executable = await this.resolveVariable(variableResolver, shellOptions.executable); + shellLaunchConfig.executable = await this._resolveVariable(variableResolver, shellOptions.executable); shellSpecified = true; } if (shellOptions.args) { - shellLaunchConfig.args = await this.resolveVariables(variableResolver, shellOptions.args.slice()); + shellLaunchConfig.args = await this._resolveVariables(variableResolver, shellOptions.args.slice()); } } if (shellLaunchConfig.args === undefined) { @@ -1056,13 +1057,13 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } let shellArgs = Array.isArray(shellLaunchConfig.args!) ? shellLaunchConfig.args!.slice(0) : [shellLaunchConfig.args!]; let toAdd: string[] = []; - let basename = path.posix.basename((await this.pathService.fileURI(shellLaunchConfig.executable!)).path).toLowerCase(); - let commandLine = this.buildShellCommandLine(platform, basename, shellOptions, command, originalCommand, args); + let basename = path.posix.basename((await this._pathService.fileURI(shellLaunchConfig.executable!)).path).toLowerCase(); + let commandLine = this._buildShellCommandLine(platform, basename, shellOptions, command, originalCommand, args); let windowsShellArgs: boolean = false; if (platform === Platform.Platform.Windows) { windowsShellArgs = true; // If we don't have a cwd, then the terminal uses the home dir. - const userHome = await this.pathService.userHome(); + const userHome = await this._pathService.userHome(); if (basename === 'cmd.exe' && ((options.cwd && isUNC(options.cwd)) || (!options.cwd && isUNC(userHome.fsPath)))) { return undefined; } @@ -1089,7 +1090,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { // Under Mac remove -l to not start it as a login shell. if (platform === Platform.Platform.Mac) { // Background on -l on osx https://github.com/microsoft/vscode/issues/107563 - const osxShellArgs = this.configurationService.inspect(TerminalSettingId.ShellArgsMacOs); + const osxShellArgs = this._configurationService.inspect(TerminalSettingId.ShellArgsMacOs); if ((osxShellArgs.user === undefined) && (osxShellArgs.userLocal === undefined) && (osxShellArgs.userLocalValue === undefined) && (osxShellArgs.userRemote === undefined) && (osxShellArgs.userRemoteValue === undefined) && (osxShellArgs.userValue === undefined) && (osxShellArgs.workspace === undefined) @@ -1104,7 +1105,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { toAdd.push('-c'); } } - const combinedShellArgs = this.addAllArgument(toAdd, shellArgs); + const combinedShellArgs = this._addAllArgument(toAdd, shellArgs); combinedShellArgs.push(commandLine); shellLaunchConfig.args = windowsShellArgs ? combinedShellArgs.join(' ') : combinedShellArgs; if (task.command.presentation && task.command.presentation.echo) { @@ -1117,7 +1118,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } else { let commandExecutable = (task.command.runtime !== RuntimeType.CustomExecution) ? CommandString.value(command) : undefined; let executable = !isShellCommand - ? await this.resolveVariable(variableResolver, await this.resolveVariable(variableResolver, '${' + TerminalTaskSystem.ProcessVarName + '}')) + ? await this._resolveVariable(variableResolver, await this._resolveVariable(variableResolver, '${' + TerminalTaskSystem.ProcessVarName + '}')) : commandExecutable; // When we have a process task there is no need to quote arguments. So we go ahead and take the string value. @@ -1154,7 +1155,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } } // This must be normalized to the OS - shellLaunchConfig.cwd = isUNC(cwd) ? cwd : resources.toLocalResource(URI.from({ scheme: Schemas.file, path: cwd }), this.environmentService.remoteAuthority, this.pathService.defaultUriScheme); + shellLaunchConfig.cwd = isUNC(cwd) ? cwd : resources.toLocalResource(URI.from({ scheme: Schemas.file, path: cwd }), this._environmentService.remoteAuthority, this._pathService.defaultUriScheme); } if (options.env) { if (shellLaunchConfig.env) { @@ -1168,7 +1169,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { return shellLaunchConfig; } - private addAllArgument(shellCommandArgs: string[], configuredShellArgs: string[]): string[] { + private _addAllArgument(shellCommandArgs: string[], configuredShellArgs: string[]): string[] { const combinedShellArgs: string[] = Objects.deepClone(configuredShellArgs); shellCommandArgs.forEach(element => { const shouldAddShellCommandArg = configuredShellArgs.every((arg, index) => { @@ -1186,31 +1187,31 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { return combinedShellArgs; } - private async doCreateTerminal(group: string | undefined, launchConfigs: IShellLaunchConfig): Promise { + private async _doCreateTerminal(group: string | undefined, launchConfigs: IShellLaunchConfig): Promise { if (group) { // Try to find an existing terminal to split. // Even if an existing terminal is found, the split can fail if the terminal width is too small. - for (const terminal of values(this.terminals)) { + for (const terminal of values(this._terminals)) { if (terminal.group === group) { - this.logService.trace(`Found terminal to split for group ${group}`); + this._logService.trace(`Found terminal to split for group ${group}`); const originalInstance = terminal.terminal; - const result = await this.terminalService.createTerminal({ location: { parentTerminal: originalInstance }, config: launchConfigs }); + const result = await this._terminalService.createTerminal({ location: { parentTerminal: originalInstance }, config: launchConfigs }); if (result) { return result; } } } - this.logService.trace(`No terminal found to split for group ${group}`); + this._logService.trace(`No terminal found to split for group ${group}`); } // Either no group is used, no terminal with the group exists or splitting an existing terminal failed. - const createdTerminal = await this.terminalService.createTerminal({ location: TerminalLocation.Panel, config: launchConfigs }); - this.logService.trace('Created a new task terminal'); + const createdTerminal = await this._terminalService.createTerminal({ location: TerminalLocation.Panel, config: launchConfigs }); + this._logService.trace('Created a new task terminal'); return createdTerminal; } - private async createTerminal(task: CustomTask | ContributedTask, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder | undefined): Promise<[ITerminalInstance | undefined, TaskError | undefined]> { + private async _createTerminal(task: CustomTask | ContributedTask, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder | undefined): Promise<[ITerminalInstance | undefined, TaskError | undefined]> { let platform = resolver.taskSystemInfo ? resolver.taskSystemInfo.platform : Platform.platform; - let options = await this.resolveOptions(resolver, task.command.options); + let options = await this._resolveOptions(resolver, task.command.options); const presentationOptions = task.command.presentation; let waitOnExit: boolean | string = false; @@ -1237,19 +1238,19 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { let launchConfigs: IShellLaunchConfig | undefined; if (task.command.runtime === RuntimeType.CustomExecution) { - this.currentTask.shellLaunchConfig = launchConfigs = { - customPtyImplementation: (id, cols, rows) => new TerminalProcessExtHostProxy(id, cols, rows, this.terminalService), + this._currentTask.shellLaunchConfig = launchConfigs = { + customPtyImplementation: (id, cols, rows) => new TerminalProcessExtHostProxy(id, cols, rows, this._terminalService), waitOnExit, - name: this.createTerminalName(task), + name: this._createTerminalName(task), initialText: task.command.presentation && task.command.presentation.echo ? `\x1b[1m> Executing task: ${task._label} <\x1b[0m\n` : undefined, isFeatureTerminal: true }; } else { - let resolvedResult: { command: CommandString; args: CommandString[] } = await this.resolveCommandAndArgs(resolver, task.command); + let resolvedResult: { command: CommandString; args: CommandString[] } = await this._resolveCommandAndArgs(resolver, task.command); command = resolvedResult.command; args = resolvedResult.args; - this.currentTask.shellLaunchConfig = launchConfigs = await this.createShellLaunchConfig(task, workspaceFolder, resolver, platform, options, command, args, waitOnExit); + this._currentTask.shellLaunchConfig = launchConfigs = await this._createShellLaunchConfig(task, workspaceFolder, resolver, platform, options, command, args, waitOnExit); if (launchConfigs === undefined) { return [undefined, new TaskError(Severity.Error, nls.localize('TerminalTaskSystem', 'Can\'t execute a shell command on an UNC drive using cmd.exe.'), TaskErrors.UnknownError)]; } @@ -1262,28 +1263,28 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { let taskKey = task.getMapKey(); let terminalToReuse: ITerminalData | undefined; if (prefersSameTerminal) { - let terminalId = this.sameTaskTerminals[taskKey]; + let terminalId = this._sameTaskTerminals[taskKey]; if (terminalId) { - terminalToReuse = this.terminals[terminalId]; - delete this.sameTaskTerminals[taskKey]; + terminalToReuse = this._terminals[terminalId]; + delete this._sameTaskTerminals[taskKey]; } } else if (allowsSharedTerminal) { // Always allow to reuse the terminal previously used by the same task. - let terminalId = this.idleTaskTerminals.remove(taskKey); + let terminalId = this._idleTaskTerminals.remove(taskKey); if (!terminalId) { // There is no idle terminal which was used by the same task. // Search for any idle terminal used previously by a task of the same group // (or, if the task has no group, a terminal used by a task without group). - for (const taskId of this.idleTaskTerminals.keys()) { - const idleTerminalId = this.idleTaskTerminals.get(taskId)!; - if (idleTerminalId && this.terminals[idleTerminalId] && this.terminals[idleTerminalId].group === group) { - terminalId = this.idleTaskTerminals.remove(taskId); + for (const taskId of this._idleTaskTerminals.keys()) { + const idleTerminalId = this._idleTaskTerminals.get(taskId)!; + if (idleTerminalId && this._terminals[idleTerminalId] && this._terminals[idleTerminalId].group === group) { + terminalId = this._idleTaskTerminals.remove(taskId); break; } } } if (terminalId) { - terminalToReuse = this.terminals[terminalId]; + terminalToReuse = this._terminals[terminalId]; } } if (terminalToReuse) { @@ -1297,38 +1298,38 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (task.command.presentation && task.command.presentation.clear) { terminalToReuse.terminal.clearBuffer(); } - this.terminals[terminalToReuse.terminal.instanceId.toString()].lastTask = taskKey; + this._terminals[terminalToReuse.terminal.instanceId.toString()].lastTask = taskKey; return [terminalToReuse.terminal, undefined]; } - this.terminalCreationQueue = this.terminalCreationQueue.then(() => this.doCreateTerminal(group, launchConfigs!)); - const result: ITerminalInstance = (await this.terminalCreationQueue)!; + this._terminalCreationQueue = this._terminalCreationQueue.then(() => this._doCreateTerminal(group, launchConfigs!)); + const result: ITerminalInstance = (await this._terminalCreationQueue)!; const terminalKey = result.instanceId.toString(); result.onDisposed((terminal) => { - let terminalData = this.terminals[terminalKey]; + let terminalData = this._terminals[terminalKey]; if (terminalData) { - delete this.terminals[terminalKey]; - delete this.sameTaskTerminals[terminalData.lastTask]; - this.idleTaskTerminals.delete(terminalData.lastTask); + delete this._terminals[terminalKey]; + delete this._sameTaskTerminals[terminalData.lastTask]; + this._idleTaskTerminals.delete(terminalData.lastTask); // Delete the task now as a work around for cases when the onExit isn't fired. // This can happen if the terminal wasn't shutdown with an "immediate" flag and is expected. // For correct terminal re-use, the task needs to be deleted immediately. // Note that this shouldn't be a problem anymore since user initiated terminal kills are now immediate. const mapKey = task.getMapKey(); - this.removeFromActiveTasks(task); - if (this.busyTasks[mapKey]) { - delete this.busyTasks[mapKey]; + this._removeFromActiveTasks(task); + if (this._busyTasks[mapKey]) { + delete this._busyTasks[mapKey]; } } }); - this.terminals[terminalKey] = { terminal: result, lastTask: taskKey, group }; + this._terminals[terminalKey] = { terminal: result, lastTask: taskKey, group }; return [result, undefined]; } - private buildShellCommandLine(platform: Platform.Platform, shellExecutable: string, shellOptions: IShellConfiguration | undefined, command: CommandString, originalCommand: CommandString | undefined, args: CommandString[]): string { + private _buildShellCommandLine(platform: Platform.Platform, shellExecutable: string, shellOptions: IShellConfiguration | undefined, command: CommandString, originalCommand: CommandString | undefined, args: CommandString[]): string { let basename = path.parse(shellExecutable).name.toLowerCase(); - let shellQuoteOptions = this.getQuotingOptions(basename, shellOptions, platform); + let shellQuoteOptions = this._getQuotingOptions(basename, shellOptions, platform); function needsQuotes(value: string): boolean { if (value.length >= 2) { @@ -1425,18 +1426,18 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { return commandLine; } - private getQuotingOptions(shellBasename: string, shellOptions: IShellConfiguration | undefined, platform: Platform.Platform): IShellQuotingOptions { + private _getQuotingOptions(shellBasename: string, shellOptions: IShellConfiguration | undefined, platform: Platform.Platform): IShellQuotingOptions { if (shellOptions && shellOptions.quoting) { return shellOptions.quoting; } - return TerminalTaskSystem.shellQuotes[shellBasename] || TerminalTaskSystem.osShellQuotes[Platform.PlatformToString(platform)]; + return TerminalTaskSystem._shellQuotes[shellBasename] || TerminalTaskSystem._osShellQuotes[Platform.PlatformToString(platform)]; } - private collectTaskVariables(variables: Set, task: CustomTask | ContributedTask): void { + private _collectTaskVariables(variables: Set, task: CustomTask | ContributedTask): void { if (task.command && task.command.name) { - this.collectCommandVariables(variables, task.command, task); + this._collectCommandVariables(variables, task.command, task); } - this.collectMatcherVariables(variables, task.configurationProperties.problemMatchers); + this._collectMatcherVariables(variables, task.configurationProperties.problemMatchers); if (task.command.runtime === RuntimeType.CustomExecution && (CustomTask.is(task) || ContributedTask.is(task))) { let definition: any; @@ -1447,23 +1448,23 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { delete definition._key; delete definition.type; } - this.collectDefinitionVariables(variables, definition); + this._collectDefinitionVariables(variables, definition); } } - private collectDefinitionVariables(variables: Set, definition: any): void { + private _collectDefinitionVariables(variables: Set, definition: any): void { if (Types.isString(definition)) { - this.collectVariables(variables, definition); + this._collectVariables(variables, definition); } else if (Types.isArray(definition)) { - definition.forEach((element: any) => this.collectDefinitionVariables(variables, element)); + definition.forEach((element: any) => this._collectDefinitionVariables(variables, element)); } else if (Types.isObject(definition)) { for (const key in definition) { - this.collectDefinitionVariables(variables, definition[key]); + this._collectDefinitionVariables(variables, definition[key]); } } } - private collectCommandVariables(variables: Set, command: ICommandConfiguration, task: CustomTask | ContributedTask): void { + private _collectCommandVariables(variables: Set, command: ICommandConfiguration, task: CustomTask | ContributedTask): void { // The custom execution should have everything it needs already as it provided // the callback. if (command.runtime === RuntimeType.CustomExecution) { @@ -1473,9 +1474,9 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (command.name === undefined) { throw new Error('Command name should never be undefined here.'); } - this.collectVariables(variables, command.name); + this._collectVariables(variables, command.name); if (command.args) { - command.args.forEach(arg => this.collectVariables(variables, arg)); + command.args.forEach(arg => this._collectVariables(variables, arg)); } // Try to get a scope. const scope = (task._source).scope; @@ -1485,29 +1486,29 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (command.options) { let options = command.options; if (options.cwd) { - this.collectVariables(variables, options.cwd); + this._collectVariables(variables, options.cwd); } const optionsEnv = options.env; if (optionsEnv) { Object.keys(optionsEnv).forEach((key) => { let value: any = optionsEnv[key]; if (Types.isString(value)) { - this.collectVariables(variables, value); + this._collectVariables(variables, value); } }); } if (options.shell) { if (options.shell.executable) { - this.collectVariables(variables, options.shell.executable); + this._collectVariables(variables, options.shell.executable); } if (options.shell.args) { - options.shell.args.forEach(arg => this.collectVariables(variables, arg)); + options.shell.args.forEach(arg => this._collectVariables(variables, arg)); } } } } - private collectMatcherVariables(variables: Set, values: Array | undefined): void { + private _collectMatcherVariables(variables: Set, values: Array | undefined): void { if (values === undefined || values === null || values.length === 0) { return; } @@ -1523,12 +1524,12 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { matcher = value; } if (matcher && matcher.filePrefix) { - this.collectVariables(variables, matcher.filePrefix); + this._collectVariables(variables, matcher.filePrefix); } }); } - private collectVariables(variables: Set, value: string | CommandString): void { + private _collectVariables(variables: Set, value: string | CommandString): void { let string: string = Types.isString(value) ? value : value.value; let r = /\$\{(.*?)\}/g; let matches: RegExpExecArray | null; @@ -1540,21 +1541,21 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } while (matches); } - private async resolveCommandAndArgs(resolver: VariableResolver, commandConfig: ICommandConfiguration): Promise<{ command: CommandString; args: CommandString[] }> { + private async _resolveCommandAndArgs(resolver: VariableResolver, commandConfig: ICommandConfiguration): Promise<{ command: CommandString; args: CommandString[] }> { // First we need to use the command args: let args: CommandString[] = commandConfig.args ? commandConfig.args.slice() : []; - args = await this.resolveVariables(resolver, args); - let command: CommandString = await this.resolveVariable(resolver, commandConfig.name); + args = await this._resolveVariables(resolver, args); + let command: CommandString = await this._resolveVariable(resolver, commandConfig.name); return { command, args }; } - private async resolveVariables(resolver: VariableResolver, value: string[]): Promise; - private async resolveVariables(resolver: VariableResolver, value: CommandString[]): Promise; - private async resolveVariables(resolver: VariableResolver, value: CommandString[]): Promise { - return Promise.all(value.map(s => this.resolveVariable(resolver, s))); + private async _resolveVariables(resolver: VariableResolver, value: string[]): Promise; + private async _resolveVariables(resolver: VariableResolver, value: CommandString[]): Promise; + private async _resolveVariables(resolver: VariableResolver, value: CommandString[]): Promise { + return Promise.all(value.map(s => this._resolveVariable(resolver, s))); } - private async resolveMatchers(resolver: VariableResolver, values: Array | undefined): Promise { + private async _resolveMatchers(resolver: VariableResolver, values: Array | undefined): Promise { if (values === undefined || values === null || values.length === 0) { return []; } @@ -1571,7 +1572,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { matcher = value; } if (!matcher) { - this.appendOutput(nls.localize('unknownProblemMatcher', 'Problem matcher {0} can\'t be resolved. The matcher will be ignored')); + this._appendOutput(nls.localize('unknownProblemMatcher', 'Problem matcher {0} can\'t be resolved. The matcher will be ignored')); continue; } let taskSystemInfo: ITaskSystemInfo | undefined = resolver.taskSystemInfo; @@ -1585,7 +1586,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { copy.uriProvider = taskSystemInfo.uriProvider; } if (hasFilePrefix) { - copy.filePrefix = await this.resolveVariable(resolver, copy.filePrefix); + copy.filePrefix = await this._resolveVariable(resolver, copy.filePrefix); } result.push(copy); } @@ -1593,9 +1594,9 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { return result; } - private async resolveVariable(resolver: VariableResolver, value: string | undefined): Promise; - private async resolveVariable(resolver: VariableResolver, value: CommandString | undefined): Promise; - private async resolveVariable(resolver: VariableResolver, value: CommandString | undefined): Promise { + private async _resolveVariable(resolver: VariableResolver, value: string | undefined): Promise; + private async _resolveVariable(resolver: VariableResolver, value: CommandString | undefined): Promise; + private async _resolveVariable(resolver: VariableResolver, value: CommandString | undefined): Promise { // TODO@Dirk Task.getWorkspaceFolder should return a WorkspaceFolder that is defined in workspace.ts if (Types.isString(value)) { return resolver.resolve(value); @@ -1609,25 +1610,25 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { } } - private async resolveOptions(resolver: VariableResolver, options: CommandOptions | undefined): Promise { + private async _resolveOptions(resolver: VariableResolver, options: CommandOptions | undefined): Promise { if (options === undefined || options === null) { let cwd: string | undefined; try { - cwd = await this.resolveVariable(resolver, '${workspaceFolder}'); + cwd = await this._resolveVariable(resolver, '${workspaceFolder}'); } catch (e) { // No workspace } return { cwd }; } let result: CommandOptions = Types.isString(options.cwd) - ? { cwd: await this.resolveVariable(resolver, options.cwd) } - : { cwd: await this.resolveVariable(resolver, '${workspaceFolder}') }; + ? { cwd: await this._resolveVariable(resolver, options.cwd) } + : { cwd: await this._resolveVariable(resolver, '${workspaceFolder}') }; if (options.env) { result.env = Object.create(null); for (const key of Object.keys(options.env)) { let value: any = options.env![key]; if (Types.isString(value)) { - result.env![key] = await this.resolveVariable(resolver, value); + result.env![key] = await this._resolveVariable(resolver, value); } else { result.env![key] = value.toString(); } @@ -1636,7 +1637,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { return result; } - private static WellKnowCommands: IStringDictionary = { + static WellKnownCommands: IStringDictionary = { 'ant': true, 'cmake': true, 'eslint': true, @@ -1663,14 +1664,14 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { if (index !== -1) { result = result.substring(index + 1); } - if (TerminalTaskSystem.WellKnowCommands[result]) { + if (TerminalTaskSystem.WellKnownCommands[result]) { return result; } return 'other'; } - private appendOutput(output: string): void { - const outputChannel = this.outputService.getChannel(this.outputChannelId); + private _appendOutput(output: string): void { + const outputChannel = this._outputService.getChannel(this._outputChannelId); if (outputChannel) { outputChannel.append(output); } diff --git a/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts b/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts index 52844d4b3ce..80165aeb915 100644 --- a/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts +++ b/src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts @@ -119,11 +119,11 @@ export class TaskService extends AbstractTaskService { this._register(lifecycleService.onBeforeShutdown(event => event.veto(this.beforeShutdown(), 'veto.tasks'))); } - protected getTaskSystem(): ITaskSystem { + protected _getTaskSystem(): ITaskSystem { if (this._taskSystem) { return this._taskSystem; } - this._taskSystem = this.createTerminalTaskSystem(); + this._taskSystem = this._createTerminalTaskSystem(); this._taskSystemListener = this._taskSystem!.onDidStateChange((event) => { if (this._taskSystem) { this._taskRunningState.set(this._taskSystem.isActiveSync()); @@ -133,8 +133,8 @@ export class TaskService extends AbstractTaskService { return this._taskSystem; } - protected computeLegacyConfiguration(workspaceFolder: IWorkspaceFolder): Promise { - let { config, hasParseErrors } = this.getConfiguration(workspaceFolder); + protected _computeLegacyConfiguration(workspaceFolder: IWorkspaceFolder): Promise { + let { config, hasParseErrors } = this._getConfiguration(workspaceFolder); if (hasParseErrors) { return Promise.resolve({ workspaceFolder: workspaceFolder, hasErrors: true, config: undefined }); } @@ -145,7 +145,7 @@ export class TaskService extends AbstractTaskService { } } - protected versionAndEngineCompatible(filter?: ITaskFilter): boolean { + protected _versionAndEngineCompatible(filter?: ITaskFilter): boolean { let range = filter && filter.version ? filter.version : undefined; let engine = this.executionEngine; @@ -169,7 +169,7 @@ export class TaskService extends AbstractTaskService { if (this._taskSystem.canAutoTerminate()) { terminatePromise = Promise.resolve({ confirmed: true }); } else { - terminatePromise = this.dialogService.confirm({ + terminatePromise = this._dialogService.confirm({ message: nls.localize('TaskSystem.runningTask', 'There is a task running. Do you want to terminate it?'), primaryButton: nls.localize({ key: 'TaskSystem.terminateTask', comment: ['&& denotes a mnemonic'] }, "&&Terminate Task"), type: 'question' @@ -191,10 +191,10 @@ export class TaskService extends AbstractTaskService { } if (success) { this._taskSystem = undefined; - this.disposeTaskSystemListeners(); + this._disposeTaskSystemListeners(); return false; // no veto } else if (code && code === TerminateResponseCode.ProcessNotFound) { - return this.dialogService.confirm({ + return this._dialogService.confirm({ message: nls.localize('TaskSystem.noProcess', 'The launched task doesn\'t exist anymore. If the task spawned background processes exiting VS Code might result in orphaned processes. To avoid this start the last background process with a wait flag.'), primaryButton: nls.localize({ key: 'TaskSystem.exitAnyways', comment: ['&& denotes a mnemonic'] }, "&&Exit Anyways"), type: 'info' From 2196474722524ea13028d6ab09f559c3b9c23ad4 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 9 Jun 2022 13:19:06 -0700 Subject: [PATCH 21/32] Correctly resolve the icon asap when defaultProfile is null When the defaultProfile is null we don't actually know what the default profile is until the process has been created, this is because it needs a round trip to the pty host. This change fixes the _icon prop updating and icon changed event firing. Fixes #151639 --- src/vs/platform/terminal/node/terminalProfiles.ts | 3 ++- .../contrib/terminal/browser/terminalInstance.ts | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/vs/platform/terminal/node/terminalProfiles.ts b/src/vs/platform/terminal/node/terminalProfiles.ts index 2c44f2358a6..6e54ef9a381 100644 --- a/src/vs/platform/terminal/node/terminalProfiles.ts +++ b/src/vs/platform/terminal/node/terminalProfiles.ts @@ -183,9 +183,10 @@ async function transformToTerminalProfiles( validatedProfile.color = profile.color; resultProfiles.push(validatedProfile); } else { - logService?.trace('profile not validated', profileName, originalPaths); + logService?.debug('Terminal profile not validated', profileName, originalPaths); } } + logService?.debug('Validated terminal profiles', resultProfiles); return resultProfiles; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 0825cf86165..81c9f44d983 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -385,7 +385,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { }); this._fixedRows = _shellLaunchConfig.attachPersistentProcess?.fixedDimensions?.rows; this._fixedCols = _shellLaunchConfig.attachPersistentProcess?.fixedDimensions?.cols; - this._icon = _shellLaunchConfig.attachPersistentProcess?.icon || _shellLaunchConfig.icon; // the resource is already set when it's been moved from another window this._resource = resource || getTerminalUri(this._workspaceContextService.getWorkspace().id, this.instanceId, this.title); @@ -431,10 +430,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Resolve just the icon ahead of time so that it shows up immediately in the tabs. This is // disabled in remote because this needs to be sync and the OS may differ on the remote // which would result in the wrong profile being selected and the wrong icon being - // permanently attached to the terminal. + // permanently attached to the terminal. This also doesn't work when the default profile + // setting is set to null, that's handled after the process is created. if (!this.shellLaunchConfig.executable && !workbenchEnvironmentService.remoteAuthority) { this._terminalProfileResolverService.resolveIcon(this._shellLaunchConfig, OS); } + this._icon = _shellLaunchConfig.attachPersistentProcess?.icon || _shellLaunchConfig.icon; // When a custom pty is used set the name immediately so it gets passed over to the exthost // and is available when Pseudoterminal.open fires. @@ -1554,8 +1555,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this.xterm?.raw.resize(this._cols || Constants.DefaultCols, this._rows || Constants.DefaultRows); } - const hadIcon = !!this.shellLaunchConfig.icon; - + const originalIcon = this.shellLaunchConfig.icon; await this._processManager.createProcess(this._shellLaunchConfig, this._cols || Constants.DefaultCols, this._rows || Constants.DefaultRows, this._accessibilityService.isScreenReaderOptimized()).then(error => { if (error) { this._onProcessExit(error, error.code === ShellIntegrationExitCode); @@ -1564,7 +1564,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (this.xterm?.shellIntegration) { this.capabilities.add(this.xterm?.shellIntegration.capabilities); } - if (!hadIcon && this.shellLaunchConfig.icon || this.shellLaunchConfig.color) { + if (originalIcon !== this.shellLaunchConfig.icon || this.shellLaunchConfig.color) { + this._icon = this._shellLaunchConfig.attachPersistentProcess?.icon || this._shellLaunchConfig.icon; this._onIconChanged.fire(this); } } From f7e12a3a928aa69fc1991a00298ff62291207864 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 9 Jun 2022 15:04:28 -0700 Subject: [PATCH 22/32] Use optional method calls in more places (#151634) This replaces code like: ```ts if (foo.bar) { foo.bar(cat); } ``` with: ```ts foo.bar?.(cat) ``` Which is more concise but has the same meaning --- extensions/git/src/commands.ts | 4 +- extensions/git/src/git.ts | 4 +- .../server/src/jsonServer.ts | 4 +- src/vs/base/browser/dom.ts | 4 +- .../browser/ui/contextview/contextview.ts | 4 +- src/vs/base/browser/ui/grid/gridview.ts | 8 +--- src/vs/base/browser/ui/list/listView.ts | 20 +++------ src/vs/base/browser/ui/list/listWidget.ts | 16 ++----- src/vs/base/browser/ui/splitview/splitview.ts | 4 +- src/vs/base/browser/ui/tree/abstractTree.ts | 20 +++------ src/vs/base/browser/ui/tree/asyncDataTree.ts | 20 +++------ src/vs/base/browser/ui/tree/dataTree.ts | 4 +- src/vs/base/browser/ui/tree/indexTreeModel.ts | 4 +- src/vs/base/browser/ui/tree/objectTree.ts | 8 +--- src/vs/base/common/async.ts | 16 ++----- src/vs/base/common/event.ts | 4 +- src/vs/base/common/worker/simpleWorker.ts | 4 +- .../electron-sandbox/contextmenu.ts | 8 +--- src/vs/base/parts/ipc/common/ipc.ts | 4 +- src/vs/base/parts/ipc/node/ipc.cp.ts | 4 +- .../parts/quickinput/browser/quickInput.ts | 4 +- src/vs/base/parts/storage/node/storage.ts | 8 +--- src/vs/base/test/common/troubleshooting.ts | 8 +--- .../browser/view/viewUserInputEvents.ts | 44 +++++-------------- .../editor/browser/widget/codeEditorWidget.ts | 4 +- .../editor/contrib/find/browser/findWidget.ts | 4 +- .../folding/browser/indentRangeProvider.ts | 4 +- .../folding/browser/syntaxRangeProvider.ts | 4 +- .../browser/inlineCompletionsModel.ts | 4 +- .../rename/browser/renameInputField.ts | 8 +--- .../browser/bannerController.ts | 4 +- .../contextview/browser/contextMenuHandler.ts | 4 +- .../contextview/browser/contextMenuService.ts | 4 +- .../platform/menubar/electron-main/menubar.ts | 4 +- .../remoteAuthorityResolverService.ts | 4 +- .../workbench/api/browser/mainThreadSearch.ts | 4 +- .../workbench/api/common/extHostQuickOpen.ts | 4 +- .../workbench/api/common/extHostWorkspace.ts | 4 +- .../api/node/extensionHostProcess.ts | 4 +- .../api/test/common/testRPCProtocol.ts | 4 +- src/vs/workbench/browser/dnd.ts | 4 +- .../bulkEdit/browser/preview/bulkEditPane.ts | 4 +- .../contrib/comments/browser/commentReply.ts | 4 +- .../debug/common/abstractDebugAdapter.ts | 8 +--- .../browser/extensionsWorkbenchService.ts | 4 +- .../browser/view/cellParts/cellToolbars.ts | 4 +- .../viewParts/notebookEditorToolbar.ts | 4 +- .../preferences/browser/settingsTree.ts | 20 +++------ .../contrib/search/common/searchModel.ts | 4 +- .../browser/walkThroughPart.ts | 8 +--- .../electron-sandbox/contextmenuService.ts | 4 +- .../services/extensions/common/rpcProtocol.ts | 4 +- .../services/search/common/searchService.ts | 4 +- .../textfile/common/textEditorService.ts | 4 +- 54 files changed, 94 insertions(+), 282 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index dd557053e8b..2ff8969ed0b 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -3129,9 +3129,7 @@ export class CommandCenter { if (result) { const resultFn = choices.get(result); - if (resultFn) { - resultFn(); - } + resultFn?.(); } }); }; diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index f87cefbd653..7590d0e023e 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -556,9 +556,7 @@ export class Git { private async _exec(args: string[], options: SpawnOptions = {}): Promise> { const child = this.spawn(args, options); - if (options.onSpawn) { - options.onSpawn(child); - } + options.onSpawn?.(child); if (options.input) { child.stdin!.end(options.input, 'utf8'); diff --git a/extensions/json-language-features/server/src/jsonServer.ts b/extensions/json-language-features/server/src/jsonServer.ts index 9594d242f51..2e89694c912 100644 --- a/extensions/json-language-features/server/src/jsonServer.ts +++ b/extensions/json-language-features/server/src/jsonServer.ts @@ -251,9 +251,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) // The settings have changed. Is send on server activation as well. connection.onDidChangeConfiguration((change) => { let settings = change.settings; - if (runtime.configureHttpRequests) { - runtime.configureHttpRequests(settings?.http?.proxy, !!settings.http?.proxyStrictSSL); - } + runtime.configureHttpRequests?.(settings?.http?.proxy, !!settings.http?.proxyStrictSSL); jsonConfigurationSettings = settings.json?.schemas; validateEnabled = !!settings.json?.validate?.enable; updateConfiguration(); diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index a59a09e21f1..3fd1496dc08 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -1733,9 +1733,7 @@ export class DragAndDropObserver extends Disposable { this._register(addDisposableListener(this.element, EventType.DRAG_OVER, (e: DragEvent) => { e.preventDefault(); // needed so that the drop event fires (https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome) - if (this.callbacks.onDragOver) { - this.callbacks.onDragOver(e, e.timeStamp - this.dragStartTime); - } + this.callbacks.onDragOver?.(e, e.timeStamp - this.dragStartTime); })); this._register(addDisposableListener(this.element, EventType.DRAG_LEAVE, (e: DragEvent) => { diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index 1aa24bde272..e464ffdd554 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -220,9 +220,7 @@ export class ContextView extends Disposable { this.doLayout(); // Focus - if (this.delegate.focus) { - this.delegate.focus(); - } + this.delegate.focus?.(); } getViewElement(): HTMLElement { diff --git a/src/vs/base/browser/ui/grid/gridview.ts b/src/vs/base/browser/ui/grid/gridview.ts index dca11631c87..e121bcc10c8 100644 --- a/src/vs/base/browser/ui/grid/gridview.ts +++ b/src/vs/base/browser/ui/grid/gridview.ts @@ -857,9 +857,7 @@ class LeafNode implements ISplitView, IDisposable { set boundarySashes(boundarySashes: IRelativeBoundarySashes) { this._boundarySashes = boundarySashes; - if (this.view.setBoundarySashes) { - this.view.setBoundarySashes(toAbsoluteBoundarySashes(boundarySashes, this.orientation)); - } + this.view.setBoundarySashes?.(toAbsoluteBoundarySashes(boundarySashes, this.orientation)); } layout(size: number, offset: number, ctx: ILayoutContext | undefined): void { @@ -897,9 +895,7 @@ class LeafNode implements ISplitView, IDisposable { } setVisible(visible: boolean): void { - if (this.view.setVisible) { - this.view.setVisible(visible); - } + this.view.setVisible?.(visible); } dispose(): void { diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 52d2b94841b..eece9fc3bcb 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -1032,9 +1032,7 @@ export class ListView implements ISpliceable, IDisposable { this.currentDragData = new ElementsDragAndDropData(elements); StaticDND.CurrentDragAndDropData = new ExternalElementsDragAndDropData(elements); - if (this.dnd.onDragStart) { - this.dnd.onDragStart(this.currentDragData, event); - } + this.dnd.onDragStart?.(this.currentDragData, event); } private onDragOver(event: IListDragEvent): boolean { @@ -1169,9 +1167,7 @@ export class ListView implements ISpliceable, IDisposable { this.currentDragData = undefined; StaticDND.CurrentDragAndDropData = undefined; - if (this.dnd.onDragEnd) { - this.dnd.onDragEnd(event); - } + this.dnd.onDragEnd?.(event); } private clearDragOverFeedback(): void { @@ -1379,16 +1375,12 @@ export class ListView implements ISpliceable, IDisposable { if (renderer) { renderer.renderElement(item.element, index, row.templateData, undefined); - if (renderer.disposeElement) { - renderer.disposeElement(item.element, index, row.templateData, undefined); - } + renderer.disposeElement?.(item.element, index, row.templateData, undefined); } item.size = row.domNode.offsetHeight; - if (this.virtualDelegate.setDynamicHeight) { - this.virtualDelegate.setDynamicHeight(item.element, item.size); - } + this.virtualDelegate.setDynamicHeight?.(item.element, item.size); item.lastDynamicHeightWidth = this.renderWidth; this.rowsContainer.removeChild(row.domNode); @@ -1429,9 +1421,7 @@ export class ListView implements ISpliceable, IDisposable { if (item.row) { const renderer = this.renderers.get(item.row.templateId); if (renderer) { - if (renderer.disposeElement) { - renderer.disposeElement(item.element, -1, item.row.templateData, undefined); - } + renderer.disposeElement?.(item.element, -1, item.row.templateData, undefined); renderer.disposeTemplate(item.row.templateData); } } diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 0bfef7f8ae7..4b6f146a51e 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -1109,9 +1109,7 @@ class PipelineRenderer implements IListRenderer { let i = 0; for (const renderer of this.renderers) { - if (renderer.disposeElement) { - renderer.disposeElement(element, index, templateData[i], height); - } + renderer.disposeElement?.(element, index, templateData[i], height); i += 1; } @@ -1182,9 +1180,7 @@ class ListViewDragAndDrop implements IListViewDragAndDrop { } onDragStart(data: IDragAndDropData, originalEvent: DragEvent): void { - if (this.dnd.onDragStart) { - this.dnd.onDragStart(data, originalEvent); - } + this.dnd.onDragStart?.(data, originalEvent); } onDragOver(data: IDragAndDropData, targetElement: T, targetIndex: number, originalEvent: DragEvent): boolean | IListDragOverReaction { @@ -1196,9 +1192,7 @@ class ListViewDragAndDrop implements IListViewDragAndDrop { } onDragEnd(originalEvent: DragEvent): void { - if (this.dnd.onDragEnd) { - this.dnd.onDragEnd(originalEvent); - } + this.dnd.onDragEnd?.(originalEvent); } drop(data: IDragAndDropData, targetElement: T, targetIndex: number, originalEvent: DragEvent): void { @@ -1328,9 +1322,7 @@ export class List implements ISpliceable, IThemable, IDisposable { if (this.accessibilityProvider) { baseRenderers.push(new AccessibiltyRenderer(this.accessibilityProvider)); - if (this.accessibilityProvider.onDidChangeActiveDescendant) { - this.accessibilityProvider.onDidChangeActiveDescendant(this.onDidChangeActiveDescendant, this, this.disposables); - } + this.accessibilityProvider.onDidChangeActiveDescendant?.(this.onDidChangeActiveDescendant, this, this.disposables); } renderers = renderers.map(r => new PipelineRenderer(r.templateId, [...baseRenderers, r])); diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index a692d06373f..fa6e7570cab 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -231,9 +231,7 @@ abstract class ViewItem { this.container.classList.toggle('visible', visible); - if (this.view.setVisible) { - this.view.setVisible(visible); - } + this.view.setVisible?.(visible); } get minimumSize(): number { return this.visible ? this.view.minimumSize : 0; } diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index a1470dca72f..db84a4be8eb 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -70,9 +70,7 @@ class TreeNodeListDragAndDrop implements IListDragAndDrop< } onDragStart(data: IDragAndDropData, originalEvent: DragEvent): void { - if (this.dnd.onDragStart) { - this.dnd.onDragStart(asTreeDragAndDropData(data), originalEvent); - } + this.dnd.onDragStart?.(asTreeDragAndDropData(data), originalEvent); } onDragOver(data: IDragAndDropData, targetNode: ITreeNode | undefined, targetIndex: number | undefined, originalEvent: DragEvent, raw = true): boolean | IListDragOverReaction { @@ -137,9 +135,7 @@ class TreeNodeListDragAndDrop implements IListDragAndDrop< } onDragEnd(originalEvent: DragEvent): void { - if (this.dnd.onDragEnd) { - this.dnd.onDragEnd(originalEvent); - } + this.dnd.onDragEnd?.(originalEvent); } } @@ -220,9 +216,7 @@ export class ComposedTreeDelegate implements IListV } setDynamicHeight(element: N, height: number): void { - if (this.delegate.setDynamicHeight) { - this.delegate.setDynamicHeight(element.element, height); - } + this.delegate.setDynamicHeight?.(element.element, height); } } @@ -350,9 +344,7 @@ class TreeRenderer implements IListRenderer Event.map(onDidChangeCollapseState, e => e.node)(this.onDidChangeNodeTwistieState, this, this.disposables); - if (renderer.onDidChangeTwistieState) { - renderer.onDidChangeTwistieState(this.onDidChangeTwistieState, this, this.disposables); - } + renderer.onDidChangeTwistieState?.(this.onDidChangeTwistieState, this, this.disposables); } updateOptions(options: ITreeRendererOptions = {}): void { @@ -414,9 +406,7 @@ class TreeRenderer implements IListRenderer disposeElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData, height: number | undefined): void { templateData.indentGuidesDisposable.dispose(); - if (this.renderer.disposeElement) { - this.renderer.disposeElement(node, index, templateData.templateData, height); - } + this.renderer.disposeElement?.(node, index, templateData.templateData, height); if (typeof height === 'number') { this.renderedNodes.delete(node); diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 5f1b89e1e03..fbd7ad55081 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -119,9 +119,7 @@ class AsyncDataTreeRenderer implements IT } disposeElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void { - if (this.renderer.disposeElement) { - this.renderer.disposeElement(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height); - } + this.renderer.disposeElement?.(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height); } disposeTemplate(templateData: IDataTreeListTemplateData): void { @@ -196,9 +194,7 @@ class AsyncDataTreeNodeListDragAndDrop implements IListDragAndDrop | undefined, targetIndex: number | undefined, originalEvent: DragEvent, raw = true): boolean | IListDragOverReaction { @@ -210,9 +206,7 @@ class AsyncDataTreeNodeListDragAndDrop implements IListDragAndDrop i } disposeElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void { - if (this.renderer.disposeElement) { - this.renderer.disposeElement(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height); - } + this.renderer.disposeElement?.(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height); } disposeCompressedElements(node: ITreeNode>, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void { - if (this.renderer.disposeCompressedElements) { - this.renderer.disposeCompressedElements(this.compressibleNodeMapperProvider().map(node) as ITreeNode, TFilterData>, index, templateData.templateData, height); - } + this.renderer.disposeCompressedElements?.(this.compressibleNodeMapperProvider().map(node) as ITreeNode, TFilterData>, index, templateData.templateData, height); } disposeTemplate(templateData: IDataTreeListTemplateData): void { diff --git a/src/vs/base/browser/ui/tree/dataTree.ts b/src/vs/base/browser/ui/tree/dataTree.ts index afb6fa662fe..4dfe854ec04 100644 --- a/src/vs/base/browser/ui/tree/dataTree.ts +++ b/src/vs/base/browser/ui/tree/dataTree.ts @@ -140,9 +140,7 @@ export class DataTree extends AbstractTree) => { diff --git a/src/vs/base/browser/ui/tree/indexTreeModel.ts b/src/vs/base/browser/ui/tree/indexTreeModel.ts index 44c0d42819b..a7f024af3df 100644 --- a/src/vs/base/browser/ui/tree/indexTreeModel.ts +++ b/src/vs/base/browser/ui/tree/indexTreeModel.ts @@ -554,9 +554,7 @@ export class IndexTreeModel, TFilterData = voi node.renderNodeCount = renderNodeCount; } - if (onDidCreateNode) { - onDidCreateNode(node); - } + onDidCreateNode?.(node); return node; } diff --git a/src/vs/base/browser/ui/tree/objectTree.ts b/src/vs/base/browser/ui/tree/objectTree.ts index 847cb86d2fe..bd4aa34b2c7 100644 --- a/src/vs/base/browser/ui/tree/objectTree.ts +++ b/src/vs/base/browser/ui/tree/objectTree.ts @@ -140,13 +140,9 @@ class CompressibleRenderer, TFilterData, TTemplateDat disposeElement(node: ITreeNode, index: number, templateData: CompressibleTemplateData, height: number | undefined): void { if (templateData.compressedTreeNode) { - if (this.renderer.disposeCompressedElements) { - this.renderer.disposeCompressedElements(templateData.compressedTreeNode, index, templateData.data, height); - } + this.renderer.disposeCompressedElements?.(templateData.compressedTreeNode, index, templateData.data, height); } else { - if (this.renderer.disposeElement) { - this.renderer.disposeElement(node, index, templateData.data, height); - } + this.renderer.disposeElement?.(node, index, templateData.data, height); } } diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 031b10f3e9f..e45c78ae5e3 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -354,9 +354,7 @@ export class Delayer implements IDisposable { this.cancelTimeout(); if (this.completionPromise) { - if (this.doReject) { - this.doReject(new CancellationError()); - } + this.doReject?.(new CancellationError()); this.completionPromise = null; } } @@ -885,9 +883,7 @@ export class RunOnceScheduler { } protected doRun(): void { - if (this.runner) { - this.runner(); - } + this.runner?.(); } } @@ -960,9 +956,7 @@ export class ProcessTimeRunOnceScheduler { // time elapsed clearInterval(this.intervalToken); this.intervalToken = -1; - if (this.runner) { - this.runner(); - } + this.runner?.(); } } @@ -985,9 +979,7 @@ export class RunOnceWorker extends RunOnceScheduler { const units = this.units; this.units = []; - if (this.runner) { - this.runner(units); - } + this.runner?.(units); } override dispose(): void { diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index e9536b9b89b..ee30f5eceb2 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -690,9 +690,7 @@ export class Emitter { } const result = listener.subscription.set(() => { - if (removeMonitor) { - removeMonitor(); - } + removeMonitor?.(); if (!this._disposed) { removeListener(); if (this._options && this._options.onLastListenerRemove) { diff --git a/src/vs/base/common/worker/simpleWorker.ts b/src/vs/base/common/worker/simpleWorker.ts index 2617e68abfc..580298b30e1 100644 --- a/src/vs/base/common/worker/simpleWorker.ts +++ b/src/vs/base/common/worker/simpleWorker.ts @@ -283,9 +283,7 @@ export class SimpleWorkerClient extends Disp (err: any) => { // in Firefox, web workers fail lazily :( // we will reject the proxy - if (lazyProxyReject) { - lazyProxyReject(err); - } + lazyProxyReject?.(err); } )); diff --git a/src/vs/base/parts/contextmenu/electron-sandbox/contextmenu.ts b/src/vs/base/parts/contextmenu/electron-sandbox/contextmenu.ts index 7c058d45990..74ca18173c0 100644 --- a/src/vs/base/parts/contextmenu/electron-sandbox/contextmenu.ts +++ b/src/vs/base/parts/contextmenu/electron-sandbox/contextmenu.ts @@ -15,9 +15,7 @@ export function popup(items: IContextMenuItem[], options?: IPopupOptions, onHide const onClickChannel = `vscode:onContextMenu${contextMenuId}`; const onClickChannelHandler = (event: unknown, itemId: number, context: IContextMenuEvent) => { const item = processedItems[itemId]; - if (item.click) { - item.click(context); - } + item.click?.(context); }; ipcRenderer.once(onClickChannel, onClickChannelHandler); @@ -28,9 +26,7 @@ export function popup(items: IContextMenuItem[], options?: IPopupOptions, onHide ipcRenderer.removeListener(onClickChannel, onClickChannelHandler); - if (onHide) { - onHide(); - } + onHide?.(); }); ipcRenderer.send(CONTEXT_MENU_CHANNEL, contextMenuId, items.map(item => createItem(item, processedItems)), onClickChannel, options); diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index 7f607bd1360..80c87a772c5 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -707,9 +707,7 @@ export class ChannelClient implements IChannelClient, IDisposable { const handler = this.handlers.get(response.id); - if (handler) { - handler(response); - } + handler?.(response); } @memoize diff --git a/src/vs/base/parts/ipc/node/ipc.cp.ts b/src/vs/base/parts/ipc/node/ipc.cp.ts index bc8c91530aa..fa6d8073ab7 100644 --- a/src/vs/base/parts/ipc/node/ipc.cp.ts +++ b/src/vs/base/parts/ipc/node/ipc.cp.ts @@ -26,9 +26,7 @@ export class Server extends IPCServer { super({ send: r => { try { - if (process.send) { - process.send((r.buffer).toString('base64')); - } + process.send?.((r.buffer).toString('base64')); } catch (e) { /* not much to do */ } }, onMessage: Event.fromNodeEventEmitter(process, 'message', msg => VSBuffer.wrap(Buffer.from(msg, 'base64'))) diff --git a/src/vs/base/parts/quickinput/browser/quickInput.ts b/src/vs/base/parts/quickinput/browser/quickInput.ts index e7099f2655b..1a496080028 100644 --- a/src/vs/base/parts/quickinput/browser/quickInput.ts +++ b/src/vs/base/parts/quickinput/browser/quickInput.ts @@ -1406,9 +1406,7 @@ export class QuickInputController extends Disposable { return new Promise((doResolve, reject) => { let resolve = (result: R) => { resolve = doResolve; - if (options.onKeyMods) { - options.onKeyMods(input.keyMods); - } + options.onKeyMods?.(input.keyMods); doResolve(result); }; if (token.isCancellationRequested) { diff --git a/src/vs/base/parts/storage/node/storage.ts b/src/vs/base/parts/storage/node/storage.ts index e8bfec83a24..789481987b9 100644 --- a/src/vs/base/parts/storage/node/storage.ts +++ b/src/vs/base/parts/storage/node/storage.ts @@ -440,14 +440,10 @@ class SQLiteStorageDatabaseLogger { } trace(msg: string): void { - if (this.logTrace) { - this.logTrace(msg); - } + this.logTrace?.(msg); } error(error: string | Error): void { - if (this.logError) { - this.logError(error); - } + this.logError?.(error); } } diff --git a/src/vs/base/test/common/troubleshooting.ts b/src/vs/base/test/common/troubleshooting.ts index 84051e8a18a..7cfee55bd0b 100644 --- a/src/vs/base/test/common/troubleshooting.ts +++ b/src/vs/base/test/common/troubleshooting.ts @@ -47,13 +47,9 @@ export function endTrackingDisposables(): void { } export function beginLoggingFS(withStacks: boolean = false): void { - if ((self).beginLoggingFS) { - (self).beginLoggingFS(withStacks); - } + (self).beginLoggingFS?.(withStacks); } export function endLoggingFS(): void { - if ((self).endLoggingFS) { - (self).endLoggingFS(); - } + (self).endLoggingFS?.(); } diff --git a/src/vs/editor/browser/view/viewUserInputEvents.ts b/src/vs/editor/browser/view/viewUserInputEvents.ts index 64df9a0859f..5e7104b9969 100644 --- a/src/vs/editor/browser/view/viewUserInputEvents.ts +++ b/src/vs/editor/browser/view/viewUserInputEvents.ts @@ -33,69 +33,47 @@ export class ViewUserInputEvents { } public emitKeyDown(e: IKeyboardEvent): void { - if (this.onKeyDown) { - this.onKeyDown(e); - } + this.onKeyDown?.(e); } public emitKeyUp(e: IKeyboardEvent): void { - if (this.onKeyUp) { - this.onKeyUp(e); - } + this.onKeyUp?.(e); } public emitContextMenu(e: IEditorMouseEvent): void { - if (this.onContextMenu) { - this.onContextMenu(this._convertViewToModelMouseEvent(e)); - } + this.onContextMenu?.(this._convertViewToModelMouseEvent(e)); } public emitMouseMove(e: IEditorMouseEvent): void { - if (this.onMouseMove) { - this.onMouseMove(this._convertViewToModelMouseEvent(e)); - } + this.onMouseMove?.(this._convertViewToModelMouseEvent(e)); } public emitMouseLeave(e: IPartialEditorMouseEvent): void { - if (this.onMouseLeave) { - this.onMouseLeave(this._convertViewToModelMouseEvent(e)); - } + this.onMouseLeave?.(this._convertViewToModelMouseEvent(e)); } public emitMouseDown(e: IEditorMouseEvent): void { - if (this.onMouseDown) { - this.onMouseDown(this._convertViewToModelMouseEvent(e)); - } + this.onMouseDown?.(this._convertViewToModelMouseEvent(e)); } public emitMouseUp(e: IEditorMouseEvent): void { - if (this.onMouseUp) { - this.onMouseUp(this._convertViewToModelMouseEvent(e)); - } + this.onMouseUp?.(this._convertViewToModelMouseEvent(e)); } public emitMouseDrag(e: IEditorMouseEvent): void { - if (this.onMouseDrag) { - this.onMouseDrag(this._convertViewToModelMouseEvent(e)); - } + this.onMouseDrag?.(this._convertViewToModelMouseEvent(e)); } public emitMouseDrop(e: IPartialEditorMouseEvent): void { - if (this.onMouseDrop) { - this.onMouseDrop(this._convertViewToModelMouseEvent(e)); - } + this.onMouseDrop?.(this._convertViewToModelMouseEvent(e)); } public emitMouseDropCanceled(): void { - if (this.onMouseDropCanceled) { - this.onMouseDropCanceled(); - } + this.onMouseDropCanceled?.(); } public emitMouseWheel(e: IMouseWheelEvent): void { - if (this.onMouseWheel) { - this.onMouseWheel(e); - } + this.onMouseWheel?.(e); } private _convertViewToModelMouseEvent(e: IEditorMouseEvent): IEditorMouseEvent; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 991afab9ef8..ea567a7972c 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -2136,9 +2136,7 @@ class CodeEditorWidgetFocusTracker extends Disposable { } public refreshState(): void { - if (this._domFocusTracker.refreshState) { - this._domFocusTracker.refreshState(); - } + this._domFocusTracker.refreshState?.(); } } diff --git a/src/vs/editor/contrib/find/browser/findWidget.ts b/src/vs/editor/contrib/find/browser/findWidget.ts index 30a80942e2e..bfbb6921638 100644 --- a/src/vs/editor/contrib/find/browser/findWidget.ts +++ b/src/vs/editor/contrib/find/browser/findWidget.ts @@ -1348,9 +1348,7 @@ export class SimpleButton extends Widget { e.preventDefault(); return; } - if (this._opts.onKeyDown) { - this._opts.onKeyDown(e); - } + this._opts.onKeyDown?.(e); }); } diff --git a/src/vs/editor/contrib/folding/browser/indentRangeProvider.ts b/src/vs/editor/contrib/folding/browser/indentRangeProvider.ts index e918367846e..82e00b27484 100644 --- a/src/vs/editor/contrib/folding/browser/indentRangeProvider.ts +++ b/src/vs/editor/contrib/folding/browser/indentRangeProvider.ts @@ -74,9 +74,7 @@ export class RangesCollector { } return new FoldingRegions(startIndexes, endIndexes); } else { - if (this._notifyTooManyRegions) { - this._notifyTooManyRegions(this._foldingRangesLimit); - } + this._notifyTooManyRegions?.(this._foldingRangesLimit); let entries = 0; let maxIndent = this._indentOccurrences.length; for (let i = 0; i < this._indentOccurrences.length; i++) { diff --git a/src/vs/editor/contrib/folding/browser/syntaxRangeProvider.ts b/src/vs/editor/contrib/folding/browser/syntaxRangeProvider.ts index f1c58f87a14..cd98ace150b 100644 --- a/src/vs/editor/contrib/folding/browser/syntaxRangeProvider.ts +++ b/src/vs/editor/contrib/folding/browser/syntaxRangeProvider.ts @@ -121,9 +121,7 @@ export class RangesCollector { } return new FoldingRegions(startIndexes, endIndexes, this._types); } else { - if (this._notifyTooManyRegions) { - this._notifyTooManyRegions(this._foldingRangesLimit); - } + this._notifyTooManyRegions?.(this._foldingRangesLimit); let entries = 0; let maxLevel = this._nestingLevelCounts.length; for (let i = 0; i < this._nestingLevelCounts.length; i++) { diff --git a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts index e7870b9c77d..7e585ac9af0 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts @@ -243,9 +243,7 @@ export class InlineCompletionsSession extends BaseGhostTextWidgetModel { lastCompletionItem = currentCompletion.sourceInlineCompletion; const provider = currentCompletion.sourceProvider; - if (provider.handleItemDidShow) { - provider.handleItemDidShow(currentCompletion.sourceInlineCompletions, lastCompletionItem); - } + provider.handleItemDidShow?.(currentCompletion.sourceInlineCompletions, lastCompletionItem); } })); diff --git a/src/vs/editor/contrib/rename/browser/renameInputField.ts b/src/vs/editor/contrib/rename/browser/renameInputField.ts index af9ade477ac..64b88fb6f82 100644 --- a/src/vs/editor/contrib/rename/browser/renameInputField.ts +++ b/src/vs/editor/contrib/rename/browser/renameInputField.ts @@ -146,15 +146,11 @@ export class RenameInputField implements IContentWidget { private _currentCancelInput?: (focusEditor: boolean) => void; acceptInput(wantsPreview: boolean): void { - if (this._currentAcceptInput) { - this._currentAcceptInput(wantsPreview); - } + this._currentAcceptInput?.(wantsPreview); } cancelInput(focusEditor: boolean): void { - if (this._currentCancelInput) { - this._currentCancelInput(focusEditor); - } + this._currentCancelInput?.(focusEditor); } getInput(where: IRange, value: string, selectionStart: number, selectionEnd: number, supportPreview: boolean, token: CancellationToken): Promise { diff --git a/src/vs/editor/contrib/unicodeHighlighter/browser/bannerController.ts b/src/vs/editor/contrib/unicodeHighlighter/browser/bannerController.ts index 868a8024e59..d2542d01582 100644 --- a/src/vs/editor/contrib/unicodeHighlighter/browser/bannerController.ts +++ b/src/vs/editor/contrib/unicodeHighlighter/browser/bannerController.ts @@ -39,9 +39,7 @@ export class BannerController extends Disposable { ...item, onClose: () => { this.hide(); - if (item.onClose) { - item.onClose(); - } + item.onClose?.(); } }); this._editor.setBanner(this.banner.element, BANNER_ELEMENT_HEIGHT); diff --git a/src/vs/platform/contextview/browser/contextMenuHandler.ts b/src/vs/platform/contextview/browser/contextMenuHandler.ts index 6ad90b3af61..960971f9667 100644 --- a/src/vs/platform/contextview/browser/contextMenuHandler.ts +++ b/src/vs/platform/contextview/browser/contextMenuHandler.ts @@ -129,9 +129,7 @@ export class ContextMenuHandler { }, onHide: (didCancel?: boolean) => { - if (delegate.onHide) { - delegate.onHide(!!didCancel); - } + delegate.onHide?.(!!didCancel); if (this.block) { this.block.remove(); diff --git a/src/vs/platform/contextview/browser/contextMenuService.ts b/src/vs/platform/contextview/browser/contextMenuService.ts index 437b3ffd8ce..2d4ee16cb62 100644 --- a/src/vs/platform/contextview/browser/contextMenuService.ts +++ b/src/vs/platform/contextview/browser/contextMenuService.ts @@ -47,9 +47,7 @@ export class ContextMenuService extends Disposable implements IContextMenuServic this.contextMenuHandler.showContextMenu({ ...delegate, onHide: (didCancel) => { - if (delegate.onHide) { - delegate.onHide(didCancel); - } + delegate.onHide?.(didCancel); this._onDidHideContextMenu.fire(); } diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index 9fd8cca89ea..2b8f19da866 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -816,9 +816,7 @@ export class Menubar { const originalClick = options.click; options.click = (item, window, event) => { this.reportMenuActionTelemetry(commandId); - if (originalClick) { - originalClick(item, window, event); - } + originalClick?.(item, window, event); }; return options; diff --git a/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts b/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts index 36bca9adf94..f048d7153a9 100644 --- a/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts @@ -71,9 +71,7 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot const key = uri.toString(); if (!this._canonicalURIRequests.has(key)) { const request = new PendingPromise(uri); - if (this._canonicalURIProvider) { - this._canonicalURIProvider(request.input).then((uri) => request.resolve(uri), (err) => request.reject(err)); - } + this._canonicalURIProvider?.(request.input).then((uri) => request.resolve(uri), (err) => request.reject(err)); this._canonicalURIRequests.set(key, request); } return this._canonicalURIRequests.get(key)!.promise; diff --git a/src/vs/workbench/api/browser/mainThreadSearch.ts b/src/vs/workbench/api/browser/mainThreadSearch.ts index 45a9fb1d1a3..1ff5cdfb75c 100644 --- a/src/vs/workbench/api/browser/mainThreadSearch.ts +++ b/src/vs/workbench/api/browser/mainThreadSearch.ts @@ -94,9 +94,7 @@ class SearchOperation { this.matches.set(match.resource.toString(), match); } - if (this.progress) { - this.progress(match); - } + this.progress?.(match); } } diff --git a/src/vs/workbench/api/common/extHostQuickOpen.ts b/src/vs/workbench/api/common/extHostQuickOpen.ts index 1a2dda0396f..67c56f94474 100644 --- a/src/vs/workbench/api/common/extHostQuickOpen.ts +++ b/src/vs/workbench/api/common/extHostQuickOpen.ts @@ -136,9 +136,7 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx } $onItemSelected(handle: number): void { - if (this._onDidSelectItem) { - this._onDidSelectItem(handle); - } + this._onDidSelectItem?.(handle); } // ---- input diff --git a/src/vs/workbench/api/common/extHostWorkspace.ts b/src/vs/workbench/api/common/extHostWorkspace.ts index dda77ef065e..9d805271e48 100644 --- a/src/vs/workbench/api/common/extHostWorkspace.ts +++ b/src/vs/workbench/api/common/extHostWorkspace.ts @@ -546,9 +546,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac } $handleTextSearchResult(result: IRawFileMatch2, requestId: number): void { - if (this._activeSearchCallbacks[requestId]) { - this._activeSearchCallbacks[requestId](result); - } + this._activeSearchCallbacks[requestId]?.(result); } saveAll(includeUntitled?: boolean): Promise { diff --git a/src/vs/workbench/api/node/extensionHostProcess.ts b/src/vs/workbench/api/node/extensionHostProcess.ts index 54d0b9b3556..9f88fb6c32c 100644 --- a/src/vs/workbench/api/node/extensionHostProcess.ts +++ b/src/vs/workbench/api/node/extensionHostProcess.ts @@ -197,9 +197,7 @@ function _createExtHostProtocol(): Promise { // Now that we have managed to install a message listener, ask the other side to send us the socket const req: IExtHostReadyMessage = { type: 'VSCODE_EXTHOST_IPC_READY' }; - if (process.send) { - process.send(req); - } + process.send?.(req); }); } else { diff --git a/src/vs/workbench/api/test/common/testRPCProtocol.ts b/src/vs/workbench/api/test/common/testRPCProtocol.ts index 2947d378288..feeba9523f5 100644 --- a/src/vs/workbench/api/test/common/testRPCProtocol.ts +++ b/src/vs/workbench/api/test/common/testRPCProtocol.ts @@ -57,9 +57,7 @@ export class TestRPCProtocol implements IExtHostContext, IExtHostRpcService { private set _callCount(value: number) { this._callCountValue = value; if (this._callCountValue === 0) { - if (this._completeIdle) { - this._completeIdle(); - } + this._completeIdle?.(); this._idle = undefined; } } diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index 8cda2f318c7..3a186e54ab4 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -609,9 +609,7 @@ export class CompositeDragAndDropObserver extends Disposable { return; } - if (callbacks.onDragLeave) { - callbacks.onDragLeave({ eventData: e, dragAndDropData: data! }); - } + callbacks.onDragLeave?.({ eventData: e, dragAndDropData: data! }); }, onDrop: e => { if (callbacks.onDrop) { diff --git a/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts index c6af0ffa259..9438ae5a507 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts @@ -272,9 +272,7 @@ export class BulkEditPane extends ViewPane { } private _done(accept: boolean): void { - if (this._currentResolve) { - this._currentResolve(accept ? this._currentInput?.getWorkspaceEdit() : undefined); - } + this._currentResolve?.(accept ? this._currentInput?.getWorkspaceEdit() : undefined); this._currentInput = undefined; this._setState(State.Message); this._sessionDisposables.clear(); diff --git a/src/vs/workbench/contrib/comments/browser/commentReply.ts b/src/vs/workbench/contrib/comments/browser/commentReply.ts index 2c2c9e13537..9a42f9d308b 100644 --- a/src/vs/workbench/contrib/comments/browser/commentReply.ts +++ b/src/vs/workbench/contrib/comments/browser/commentReply.ts @@ -250,9 +250,7 @@ export class CommentReply extends Disposable { })); this._commentFormActions = new CommentFormActions(container, async (action: IAction) => { - if (this._actionRunDelegate) { - this._actionRunDelegate(); - } + this._actionRunDelegate?.(); action.run({ thread: this._commentThread, diff --git a/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts b/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts index 348aa5815b7..299a6ad3eb6 100644 --- a/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts +++ b/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts @@ -155,14 +155,10 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter { switch (message.type) { case 'event': - if (this.eventCallback) { - this.eventCallback(message); - } + this.eventCallback?.(message); break; case 'request': - if (this.requestCallback) { - this.requestCallback(message); - } + this.requestCallback?.(message); break; case 'response': { const response = message; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index 50b9b8c606e..363be55ed18 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -1519,9 +1519,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension this.progressService.withProgress({ location: ProgressLocation.Extensions }, () => new Promise(resolve => this._activityCallBack = resolve)); } } else { - if (this._activityCallBack) { - this._activityCallBack(); - } + this._activityCallBack?.(); this._activityCallBack = null; } } diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts index 45fc3cbb235..c84443b70ab 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts @@ -164,9 +164,7 @@ export class CellTitleToolbarPart extends CellPart { if (deferredUpdate && !visible) { this._register(disposableTimeout(() => { - if (deferredUpdate) { - deferredUpdate(); - } + deferredUpdate?.(); })); deferredUpdate = undefined; diff --git a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts index 243b4b96edc..1d1d38c2689 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar.ts @@ -405,9 +405,7 @@ export class NotebookEditorToolbar extends Disposable { if (deferredUpdate && !visible) { setTimeout(() => { - if (deferredUpdate) { - deferredUpdate(); - } + deferredUpdate?.(); }, 0); deferredUpdate = undefined; } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index b65d169f75c..c3893a2a036 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -1166,9 +1166,7 @@ export class SettingArrayRenderer extends AbstractSettingRenderer implements ITr common.toDispose.add( listWidget.onDidChangeList(e => { const newList = this.computeNewList(template, e); - if (template.onChange) { - template.onChange(newList); - } + template.onChange?.(newList); }) ); @@ -1349,9 +1347,7 @@ abstract class AbstractSettingObjectRenderer extends AbstractSettingRenderer imp template.objectDropdownWidget!.setValue(newItems); } - if (template.onChange) { - template.onChange(newValue); - } + template.onChange?.(newValue); } } @@ -1539,9 +1535,7 @@ abstract class AbstractSettingTextRenderer extends AbstractSettingRenderer imple })); common.toDispose.add( inputBox.onDidChange(e => { - if (template.onChange) { - template.onChange(e); - } + template.onChange?.(e); })); common.toDispose.add(inputBox); inputBox.inputElement.classList.add(AbstractSettingRenderer.CONTROL_CLASS); @@ -1652,9 +1646,7 @@ export class SettingEnumRenderer extends AbstractSettingRenderer implements ITre common.toDispose.add( selectBox.onDidSelect(e => { - if (template.onChange) { - template.onChange(e.index); - } + template.onChange?.(e.index); })); const enumDescriptionElement = common.containerElement.insertBefore($('.setting-item-enumDescription'), common.descriptionElement.nextSibling); @@ -1758,9 +1750,7 @@ export class SettingNumberRenderer extends AbstractSettingRenderer implements IT })); common.toDispose.add( inputBox.onDidChange(e => { - if (template.onChange) { - template.onChange(e); - } + template.onChange?.(e); })); common.toDispose.add(inputBox); inputBox.inputElement.classList.add(AbstractSettingRenderer.CONTROL_CLASS); diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index 8c56ab754f6..2fd8f4ab2c8 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -1077,9 +1077,7 @@ export class SearchModel extends Disposable { progressEmitter.fire(); this.onSearchProgress(p); - if (onProgress) { - onProgress(p); - } + onProgress?.(p); }); const dispose = () => tokenSource.dispose(); diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts index fc8d43ad75b..118d6086336 100644 --- a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts @@ -291,9 +291,7 @@ export class WalkThroughPart extends EditorPane { this.updateSizeClasses(); this.decorateContent(); this.contentDisposables.push(this.keybindingService.onDidUpdateKeybindings(() => this.decorateContent())); - if (input.onReady) { - input.onReady(this.content.firstElementChild as HTMLElement, store); - } + input.onReady?.(this.content.firstElementChild as HTMLElement, store); this.scrollbar.scanDomNode(); this.loadTextEditorViewState(input); this.updatedScrollPosition(); @@ -371,9 +369,7 @@ export class WalkThroughPart extends EditorPane { this.multiCursorModifier(); } })); - if (input.onReady) { - input.onReady(innerContent, store); - } + input.onReady?.(innerContent, store); this.scrollbar.scanDomNode(); this.loadTextEditorViewState(input); this.updatedScrollPosition(); diff --git a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts index b4c0e11cbeb..fe6eff44dd5 100644 --- a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts @@ -83,9 +83,7 @@ class NativeContextMenuService extends Disposable implements IContextMenuService const actions = delegate.getActions(); if (actions.length) { const onHide = once(() => { - if (delegate.onHide) { - delegate.onHide(false); - } + delegate.onHide?.(false); dom.ModifierKeyEmitter.getInstance().resetKeyStatus(); this._onDidHideContextMenu.fire(); diff --git a/src/vs/workbench/services/extensions/common/rpcProtocol.ts b/src/vs/workbench/services/extensions/common/rpcProtocol.ts index f44eae7e257..392b0c78da3 100644 --- a/src/vs/workbench/services/extensions/common/rpcProtocol.ts +++ b/src/vs/workbench/services/extensions/common/rpcProtocol.ts @@ -406,9 +406,7 @@ export class RPCProtocol extends Disposable implements IRPCProtocol { this._logger.logIncoming(msgLength, req, RequestInitiator.OtherSide, `receiveCancel`); } const callId = String(req); - if (this._cancelInvokedHandlers[callId]) { - this._cancelInvokedHandlers[callId](); - } + this._cancelInvokedHandlers[callId]?.(); } private _receiveReply(msgLength: number, req: number, value: any): void { diff --git a/src/vs/workbench/services/search/common/searchService.ts b/src/vs/workbench/services/search/common/searchService.ts index cf0aad3563a..62ec6f455ce 100644 --- a/src/vs/workbench/services/search/common/searchService.ts +++ b/src/vs/workbench/services/search/common/searchService.ts @@ -134,9 +134,7 @@ export class SearchService extends Disposable implements ISearchService { return; } - if (onProgress) { - onProgress(item); - } + onProgress?.(item); }; const exists = await Promise.all(query.folderQueries.map(query => this.fileService.exists(query.folder))); diff --git a/src/vs/workbench/services/textfile/common/textEditorService.ts b/src/vs/workbench/services/textfile/common/textEditorService.ts index 9e40eb88f5a..c8c9050875b 100644 --- a/src/vs/workbench/services/textfile/common/textEditorService.ts +++ b/src/vs/workbench/services/textfile/common/textEditorService.ts @@ -227,9 +227,7 @@ export class TextEditorService extends Disposable implements ITextEditorService // Return early if already cached let input = this.editorInputCache.get(resource); if (input) { - if (cachedFn) { - cachedFn(input); - } + cachedFn?.(input); return input; } From cb2d3caec18352c2e5a5b0fce40b900eb2cb7785 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Thu, 9 Jun 2022 15:06:47 -0700 Subject: [PATCH 23/32] Fix #151650 (#151651) * Use disabled foreground on extension description when disabled * Remove added line --- .../workbench/contrib/extensions/browser/media/extension.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/extensions/browser/media/extension.css b/src/vs/workbench/contrib/extensions/browser/media/extension.css index 28c231a1e7b..17da41a9707 100644 --- a/src/vs/workbench/contrib/extensions/browser/media/extension.css +++ b/src/vs/workbench/contrib/extensions/browser/media/extension.css @@ -215,6 +215,10 @@ min-width: 0; } +.monaco-list-row.disabled .extension-list-item .details .description { + color: var(--vscode-disabledForeground); +} + .extension-list-item .monaco-action-bar .action-label.icon { padding: 1px 2px; } From b331f811c1bde2a6d85cb80c8949767ffe5a00a7 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 9 Jun 2022 15:55:54 -0700 Subject: [PATCH 24/32] Add `thisArg` to `DataTransfer.forEach` (#151658) Fixes #151657 All of our other `forEach` functions take a `this` arg which is used when invoking the callback. This just aligns `DataTransfer.forEach` --- src/vs/workbench/api/common/extHostTypes.ts | 4 ++-- src/vscode-dts/vscode.d.ts | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index e9a1b02b9f6..59d96e58586 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2473,9 +2473,9 @@ export class DataTransfer { this.#items.set(mimeType, [value]); } - forEach(callbackfn: (value: DataTransferItem, key: string) => void): void { + forEach(callbackfn: (value: DataTransferItem, key: string) => void, thisArg?: unknown): void { for (const [mime, items] of this.#items) { - items.forEach(item => callbackfn(item, mime)); + items.forEach(item => callbackfn(item, mime), thisArg); } } } diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 88f7fdf67eb..730f0ad2014 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -10110,9 +10110,11 @@ declare module 'vscode' { /** * Allows iteration through the data transfer items. + * * @param callbackfn Callback for iteration through the data transfer items. + * @param thisArg The `this` context used when invoking the handler function. */ - forEach(callbackfn: (value: DataTransferItem, key: string) => void): void; + forEach(callbackfn: (value: DataTransferItem, key: string) => void, thisArg?: unknown): void; } /** From c289307c95a2ba61975a2f714dcf5bb84842f799 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 9 Jun 2022 15:59:27 -0700 Subject: [PATCH 25/32] Clean up DataTransferKind docs (#151656) --- .../vscode.proposed.dataTransferFiles.d.ts | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/vscode-dts/vscode.proposed.dataTransferFiles.d.ts b/src/vscode-dts/vscode.proposed.dataTransferFiles.d.ts index a202f9a9ed6..68df3c07f4a 100644 --- a/src/vscode-dts/vscode.proposed.dataTransferFiles.d.ts +++ b/src/vscode-dts/vscode.proposed.dataTransferFiles.d.ts @@ -7,15 +7,6 @@ declare module 'vscode' { // https://github.com/microsoft/vscode/issues/147481 - enum DataTransferItemKind { - String = 1, - File = 2, - } - - interface DataTransferItem { - readonly kind: DataTransferItemKind; - } - /** * A file associated with a {@linkcode DataTransferItem}. */ @@ -38,13 +29,42 @@ declare module 'vscode' { data(): Thenable; } + /** + * Identifies the kind of a {@link DataTransferItem}. May either be {@linkcode DataTransferItemKind.String String} or {@linkcode DataTransferItemKind.File File}. + */ + enum DataTransferItemKind { + + /** + * The {@link DataTransferItem} is a string. + * + * Use {@link DataTransferItem.asString} to get a string representation of this item or + * {@link DataTransferItem.value} to access the original value if them item was created + * by an extension. + */ + String = 1, + + /** + * The {@link DataTransferItem} is for a file. + * + * Use {@link DataTransferItem.asFile} to get the underlying file data. + */ + File = 2, + } + export interface DataTransferItem { + + /** + * The kind of the {@link DataTransferItem}. + */ + readonly kind: DataTransferItemKind; + /** * Try getting the file associated with this data transfer item. * * Note that the file object is only valid for the scope of the drag and drop operation. * - * @returns The file for the data transfer or `undefined` if the item is not a file. + * @returns The file for the data transfer or `undefined` if the item is either not a file or the + * file data cannot be accessed. */ asFile(): DataTransferFile | undefined; } From a49866733604d740de5221787288e65373bb9896 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 9 Jun 2022 17:04:35 -0700 Subject: [PATCH 26/32] Also enable copy/paste API for cut (#151660) For #30066 --- .../copyPaste/browser/copyPasteController.ts | 247 +++++++++--------- 1 file changed, 125 insertions(+), 122 deletions(-) diff --git a/src/vs/editor/contrib/copyPaste/browser/copyPasteController.ts b/src/vs/editor/contrib/copyPaste/browser/copyPasteController.ts index 2ad4c28a6eb..8710f815764 100644 --- a/src/vs/editor/contrib/copyPaste/browser/copyPasteController.ts +++ b/src/vs/editor/contrib/copyPaste/browser/copyPasteController.ts @@ -53,7 +53,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi private readonly _editor: ICodeEditor; - private _currentClipboardItem: undefined | { + private _currentClipboardItem?: { readonly handle: string; readonly dataTransferPromise: CancelablePromise; }; @@ -70,131 +70,134 @@ export class CopyPasteController extends Disposable implements IEditorContributi this._editor = editor; const container = editor.getContainerDomNode(); - - this._register(addDisposableListener(container, 'copy', (e: ClipboardEvent) => { - if (!e.clipboardData) { - return; - } - - const model = editor.getModel(); - const selections = this._editor.getSelections(); - if (!model || !selections?.length) { - return; - } - - if (!this.arePasteActionsEnabled(model)) { - return; - } - - const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model).filter(x => !!x.prepareDocumentPaste); - if (!providers.length) { - return; - } - - const dataTransfer = toVSDataTransfer(e.clipboardData); - - // Save off a handle pointing to data that VS Code maintains. - const handle = generateUuid(); - e.clipboardData.setData(vscodeClipboardMime, handle); - - const promise = createCancelablePromise(async token => { - const results = await Promise.all(providers.map(provider => { - return provider.prepareDocumentPaste!(model, selections, dataTransfer, token); - })); - - for (const result of results) { - result?.forEach((value, key) => { - dataTransfer.replace(key, value); - }); - } - - return dataTransfer; - }); - - this._currentClipboardItem?.dataTransferPromise.cancel(); - this._currentClipboardItem = { handle: handle, dataTransferPromise: promise }; - })); - - this._register(addDisposableListener(container, 'paste', async (e: ClipboardEvent) => { - const selections = this._editor.getSelections(); - if (!e.clipboardData || !selections?.length || !editor.hasModel()) { - return; - } - - const model = editor.getModel(); - if (!this.arePasteActionsEnabled(model)) { - return; - } - - const handle = e.clipboardData?.getData(vscodeClipboardMime); - if (typeof handle !== 'string') { - return; - } - - const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model); - if (!providers.length) { - return; - } - - e.preventDefault(); - e.stopImmediatePropagation(); - - const originalDocVersion = model.getVersionId(); - const tokenSource = new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection); - - try { - const dataTransfer = toVSDataTransfer(e.clipboardData); - - if (handle && this._currentClipboardItem?.handle === handle) { - const toMergeDataTransfer = await this._currentClipboardItem.dataTransferPromise; - toMergeDataTransfer.forEach((value, key) => { - dataTransfer.replace(key, value); - }); - } - - if (!dataTransfer.has(Mimes.uriList)) { - const resources = await this._clipboardService.readResources(); - if (resources.length) { - const value = resources.join('\n'); - dataTransfer.append(Mimes.uriList, createStringDataTransferItem(value)); - } - } - - dataTransfer.delete(vscodeClipboardMime); - - for (const provider of [...providers, defaultPasteEditProvider]) { - if (!provider.pasteMimeTypes.some(type => { - if (type.toLowerCase() === DataTransfers.FILES.toLowerCase()) { - return [...dataTransfer.values()].some(item => item.asFile()); - } - return dataTransfer.has(type); - })) { - continue; - } - - const edit = await provider.provideDocumentPasteEdits(model, selections, dataTransfer, tokenSource.token); - if (originalDocVersion !== model.getVersionId()) { - return; - } - - if (edit) { - performSnippetEdit(editor, typeof edit.insertText === 'string' ? SnippetParser.escape(edit.insertText) : edit.insertText.snippet, selections); - - if (edit.additionalEdit) { - await this._bulkEditService.apply(ResourceEdit.convert(edit.additionalEdit), { editor }); - } - return; - } - } - } finally { - tokenSource.dispose(); - } - }, true)); + this._register(addDisposableListener(container, 'copy', e => this.handleCopy(e))); + this._register(addDisposableListener(container, 'cut', e => this.handleCopy(e))); + this._register(addDisposableListener(container, 'paste', e => this.handlePaste(e), true)); } - public arePasteActionsEnabled(model: ITextModel): boolean { + private arePasteActionsEnabled(model: ITextModel): boolean { return this._configurationService.getValue('editor.experimental.pasteActions.enabled', { resource: model.uri }); } + + private handleCopy(e: ClipboardEvent) { + if (!e.clipboardData) { + return; + } + + const model = this._editor.getModel(); + const selections = this._editor.getSelections(); + if (!model || !selections?.length) { + return; + } + + if (!this.arePasteActionsEnabled(model)) { + return; + } + + const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model).filter(x => !!x.prepareDocumentPaste); + if (!providers.length) { + return; + } + + const dataTransfer = toVSDataTransfer(e.clipboardData); + + // Save off a handle pointing to data that VS Code maintains. + const handle = generateUuid(); + e.clipboardData.setData(vscodeClipboardMime, handle); + + const promise = createCancelablePromise(async token => { + const results = await Promise.all(providers.map(provider => { + return provider.prepareDocumentPaste!(model, selections, dataTransfer, token); + })); + + for (const result of results) { + result?.forEach((value, key) => { + dataTransfer.replace(key, value); + }); + } + + return dataTransfer; + }); + + this._currentClipboardItem?.dataTransferPromise.cancel(); + this._currentClipboardItem = { handle: handle, dataTransferPromise: promise }; + } + + private async handlePaste(e: ClipboardEvent) { + const selections = this._editor.getSelections(); + if (!e.clipboardData || !selections?.length || !this._editor.hasModel()) { + return; + } + + const model = this._editor.getModel(); + if (!this.arePasteActionsEnabled(model)) { + return; + } + + const handle = e.clipboardData?.getData(vscodeClipboardMime); + if (typeof handle !== 'string') { + return; + } + + const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model); + if (!providers.length) { + return; + } + + e.preventDefault(); + e.stopImmediatePropagation(); + + const originalDocVersion = model.getVersionId(); + const tokenSource = new EditorStateCancellationTokenSource(this._editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection); + + try { + const dataTransfer = toVSDataTransfer(e.clipboardData); + + if (handle && this._currentClipboardItem?.handle === handle) { + const toMergeDataTransfer = await this._currentClipboardItem.dataTransferPromise; + toMergeDataTransfer.forEach((value, key) => { + dataTransfer.replace(key, value); + }); + } + + if (!dataTransfer.has(Mimes.uriList)) { + const resources = await this._clipboardService.readResources(); + if (resources.length) { + const value = resources.join('\n'); + dataTransfer.append(Mimes.uriList, createStringDataTransferItem(value)); + } + } + + dataTransfer.delete(vscodeClipboardMime); + + for (const provider of [...providers, defaultPasteEditProvider]) { + if (!provider.pasteMimeTypes.some(type => { + if (type.toLowerCase() === DataTransfers.FILES.toLowerCase()) { + return [...dataTransfer.values()].some(item => item.asFile()); + } + return dataTransfer.has(type); + })) { + continue; + } + + const edit = await provider.provideDocumentPasteEdits(model, selections, dataTransfer, tokenSource.token); + if (originalDocVersion !== model.getVersionId()) { + return; + } + + if (edit) { + performSnippetEdit(this._editor, typeof edit.insertText === 'string' ? SnippetParser.escape(edit.insertText) : edit.insertText.snippet, selections); + + if (edit.additionalEdit) { + await this._bulkEditService.apply(ResourceEdit.convert(edit.additionalEdit), { editor: this._editor }); + } + return; + } + } + } finally { + tokenSource.dispose(); + } + } } From 160855dfb7f7855ad4174dc02e39972d6623826c Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 9 Jun 2022 16:15:26 -0800 Subject: [PATCH 27/32] safer dispose of placeholder (#151646) fix #151641 --- .../terminal/browser/xterm/decorationAddon.ts | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts index cc3510f39dc..2b346c110b9 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts @@ -117,12 +117,14 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { this.clearDecorations(); } + private _clearPlaceholder(): void { + this._placeholderDecoration?.dispose(); + this._placeholderDecoration = undefined; + } + public clearDecorations(): void { - if (this._placeholderDecoration) { - this._placeholderDecoration.marker.dispose(); - this._placeholderDecoration.dispose(); - this._placeholderDecoration = undefined; - } + this._placeholderDecoration?.marker.dispose(); + this._clearPlaceholder(); for (const value of this._decorations.values()) { value.decoration.dispose(); dispose(value.disposables); @@ -183,10 +185,7 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { } })); // Current command invalidated - this._commandDetectionListeners.push(capability.onCurrentCommandInvalidated(() => { - this._placeholderDecoration?.dispose(); - this._placeholderDecoration = undefined; - })); + this._commandDetectionListeners.push(capability.onCurrentCommandInvalidated(() => this._clearPlaceholder())); } activate(terminal: Terminal): void { @@ -202,7 +201,7 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { throw new Error(`cannot add a decoration for a command ${JSON.stringify(command)} with no marker`); } - this._placeholderDecoration?.dispose(); + this._clearPlaceholder(); let color = command.exitCode === undefined ? defaultColor : command.exitCode ? errorColor : successColor; if (color && typeof color !== 'string') { color = color.toString(); @@ -223,7 +222,6 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { } if (beforeCommandExecution && !this._placeholderDecoration) { this._placeholderDecoration = decoration; - this._placeholderDecoration.onDispose(() => this._placeholderDecoration = undefined); } else if (!this._decorations.get(decoration.marker.id)) { decoration.onDispose(() => this._decorations.delete(decoration.marker.id)); this._decorations.set(decoration.marker.id, From 4222eb73aa39739adbf12b6a54344b9a941be266 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 9 Jun 2022 16:15:43 -0800 Subject: [PATCH 28/32] allow excluding npm `install` script from the npm scripts view (#151647) fix #149924 --- extensions/npm/src/tasks.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/npm/src/tasks.ts b/extensions/npm/src/tasks.ts index accbe0f6bc9..ad9ef3c87ea 100644 --- a/extensions/npm/src/tasks.ts +++ b/extensions/npm/src/tasks.ts @@ -287,8 +287,9 @@ async function provideNpmScriptsForFolder(context: ExtensionContext, packageJson result.push({ task, location: new Location(packageJsonUri, nameRange) }); } - // always add npm install (without a problem matcher) - result.push({ task: await createTask(packageManager, INSTALL_SCRIPT, [INSTALL_SCRIPT], folder, packageJsonUri, 'install dependencies from package', []) }); + if (!workspace.getConfiguration('npm', folder).get('scriptExplorerExclude', []).find(e => e.includes('install'))) { + result.push({ task: await createTask(packageManager, INSTALL_SCRIPT, [INSTALL_SCRIPT], folder, packageJsonUri, 'install dependencies from package', []) }); + } return result; } From d5e7687940f7e149cec99865a7069de11cb3fdb9 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 9 Jun 2022 20:27:36 -0700 Subject: [PATCH 29/32] Fix updating outputs of another cell using a NotebookCellExecution (#151573) Fixes #151468 --- .../src/singlefolder-tests/notebook.test.ts | 74 +++++++++++++++++++ .../api/browser/mainThreadNotebookDto.ts | 1 + .../workbench/api/common/extHost.protocol.ts | 1 + .../api/common/extHostNotebookKernels.ts | 13 ++++ .../notebook/browser/notebookEditorWidget.ts | 4 +- .../notebookExecutionStateServiceImpl.ts | 2 +- .../common/notebookExecutionService.ts | 1 + 7 files changed, 93 insertions(+), 3 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index c4d4733578a..270d9ea9aa2 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -927,6 +927,80 @@ const apiTestContentProvider: vscode.NotebookContentProvider = { assert.strictEqual(executionWasCancelled, true); }); + + test('appendOutput to different cell', async function () { + const notebook = await openRandomNotebookDocument(); + const editor = await vscode.window.showNotebookDocument(notebook); + const cell0 = editor.notebook.cellAt(0); + await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); + const cell1 = editor.notebook.cellAt(1); + + const nextCellKernel = new class extends Kernel { + constructor() { + super('nextCellKernel', 'Append to cell kernel'); + } + + override async _runCell(cell: vscode.NotebookCell) { + const task = this.controller.createNotebookCellExecution(cell); + task.start(); + await task.appendOutput([new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text('my output') + ])], cell1); + await task.appendOutput([new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text('my output 2') + ])], cell1); + task.end(true); + } + }; + testDisposables.push(nextCellKernel.controller); + + await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { + await assertKernel(nextCellKernel, notebook); + await vscode.commands.executeCommand('notebook.cell.execute'); + await event; + assert.strictEqual(cell0.outputs.length, 0, 'should not change cell 0'); + assert.strictEqual(cell1.outputs.length, 2, 'should update cell 1'); + assert.strictEqual(cell1.outputs[0].items.length, 1); + assert.deepStrictEqual(new TextDecoder().decode(cell1.outputs[0].items[0].data), 'my output'); + }); + }); + + test('replaceOutput to different cell', async function () { + const notebook = await openRandomNotebookDocument(); + const editor = await vscode.window.showNotebookDocument(notebook); + const cell0 = editor.notebook.cellAt(0); + await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); + const cell1 = editor.notebook.cellAt(1); + + const nextCellKernel = new class extends Kernel { + constructor() { + super('nextCellKernel', 'Replace to cell kernel'); + } + + override async _runCell(cell: vscode.NotebookCell) { + const task = this.controller.createNotebookCellExecution(cell); + task.start(); + await task.replaceOutput([new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text('my output') + ])], cell1); + await task.replaceOutput([new vscode.NotebookCellOutput([ + vscode.NotebookCellOutputItem.text('my output 2') + ])], cell1); + task.end(true); + } + }; + testDisposables.push(nextCellKernel.controller); + + await withEvent(vscode.workspace.onDidChangeNotebookDocument, async (event) => { + await assertKernel(nextCellKernel, notebook); + await vscode.commands.executeCommand('notebook.cell.execute'); + await event; + assert.strictEqual(cell0.outputs.length, 0, 'should not change cell 0'); + assert.strictEqual(cell1.outputs.length, 1, 'should update cell 1'); + assert.strictEqual(cell1.outputs[0].items.length, 1); + assert.deepStrictEqual(new TextDecoder().decode(cell1.outputs[0].items[0].data), 'my output 2'); + }); + }); }); (vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('statusbar', () => { diff --git a/src/vs/workbench/api/browser/mainThreadNotebookDto.ts b/src/vs/workbench/api/browser/mainThreadNotebookDto.ts index 8f5d53fd444..9c7f5d67f0d 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebookDto.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookDto.ts @@ -96,6 +96,7 @@ export namespace NotebookDto { if (data.editType === CellExecutionUpdateType.Output) { return { editType: data.editType, + cellHandle: data.cellHandle, append: data.append, outputs: data.outputs.map(fromNotebookOutputDto) }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index b2205cc31cb..d156a5d2a03 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1000,6 +1000,7 @@ export interface INotebookProxyKernelDto { export interface ICellExecuteOutputEditDto { editType: CellExecutionUpdateType.Output; + cellHandle: number; append?: boolean; outputs: NotebookOutputDto[]; } diff --git a/src/vs/workbench/api/common/extHostNotebookKernels.ts b/src/vs/workbench/api/common/extHostNotebookKernels.ts index f99ead59ac7..356c29a7a76 100644 --- a/src/vs/workbench/api/common/extHostNotebookKernels.ts +++ b/src/vs/workbench/api/common/extHostNotebookKernels.ts @@ -441,6 +441,17 @@ class NotebookCellExecutionTask extends Disposable { } } + private cellIndexToHandle(cellOrCellIndex: vscode.NotebookCell | undefined): number { + let cell: ExtHostCell | undefined = this._cell; + if (cellOrCellIndex) { + cell = this._cell.notebook.getCellFromApiCell(cellOrCellIndex); + } + if (!cell) { + throw new Error('INVALID cell'); + } + return cell.handle; + } + private validateAndConvertOutputs(items: vscode.NotebookCellOutput[]): NotebookOutputDto[] { return items.map(output => { const newOutput = NotebookCellOutput.ensureUniqueMimeTypes(output.items, true); @@ -456,10 +467,12 @@ class NotebookCellExecutionTask extends Disposable { } private async updateOutputs(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell: vscode.NotebookCell | undefined, append: boolean): Promise { + const handle = this.cellIndexToHandle(cell); const outputDtos = this.validateAndConvertOutputs(asArray(outputs)); return this.updateSoon( { editType: CellExecutionUpdateType.Output, + cellHandle: handle, append, outputs: outputDtos }); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 7142fd20db2..a94b851c67b 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1459,11 +1459,11 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD } hasPendingChangeContentHeight = true; - DOM.scheduleAtNextAnimationFrame(() => { + this._localStore.add(DOM.scheduleAtNextAnimationFrame(() => { hasPendingChangeContentHeight = false; this._updateScrollHeight(); this._onDidChangeContentHeight.fire(this._list.getScrollHeight()); - }, 100); + }, 100)); })); this._localStore.add(this._list.onDidRemoveOutputs(outputs => { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookExecutionStateServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookExecutionStateServiceImpl.ts index 3b487ec7684..e32dbce7ba8 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookExecutionStateServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookExecutionStateServiceImpl.ts @@ -217,7 +217,7 @@ function updateToEdit(update: ICellExecuteUpdate, cellHandle: number): ICellEdit if (update.editType === CellExecutionUpdateType.Output) { return { editType: CellEditType.Output, - handle: cellHandle, + handle: update.cellHandle, append: update.append, outputs: update.outputs, }; diff --git a/src/vs/workbench/contrib/notebook/common/notebookExecutionService.ts b/src/vs/workbench/contrib/notebook/common/notebookExecutionService.ts index f95ed7b6e30..1a3b6ac9a94 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookExecutionService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookExecutionService.ts @@ -15,6 +15,7 @@ export enum CellExecutionUpdateType { export interface ICellExecuteOutputEdit { editType: CellExecutionUpdateType.Output; + cellHandle: number; append?: boolean; outputs: IOutputDto[]; } From ab6ba241145bb81c8bc0f323453bbec45fd66109 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 9 Jun 2022 20:30:44 -0700 Subject: [PATCH 30/32] Shorter label for "go to running cell" button (#151674) Fixes #141486 --- .../contrib/notebook/browser/controller/executeActions.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts index 58227467a66..3e54598b92b 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/executeActions.ts @@ -544,6 +544,8 @@ registerAction2(class RevealRunningCellAction extends NotebookAction { super({ id: REVEAL_RUNNING_CELL, title: localize('revealRunningCell', "Go To Running Cell"), + tooltip: localize('revealRunningCell', "Go To Running Cell"), + shortTitle: localize('revealRunningCellShort', "Go To"), precondition: NOTEBOOK_HAS_RUNNING_CELL, menu: [ { @@ -587,7 +589,7 @@ registerAction2(class RevealRunningCellAction extends NotebookAction { if (executingCells[0]) { const cell = context.notebookEditor.getCellByHandle(executingCells[0].cellHandle); if (cell) { - context.notebookEditor.revealInCenter(cell); + context.notebookEditor.focusNotebookCell(cell, 'container'); } } } From 14676ca4816daea9008b32c9f5a70b9c99e99674 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 10 Jun 2022 08:30:07 +0200 Subject: [PATCH 31/32] ci - always publish log files (#151686) --- build/azure-pipelines/darwin/product-build-darwin-test.yml | 2 +- build/azure-pipelines/linux/product-build-linux-client.yml | 2 +- build/azure-pipelines/win32/product-build-win32.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/azure-pipelines/darwin/product-build-darwin-test.yml b/build/azure-pipelines/darwin/product-build-darwin-test.yml index 98d61becadd..cc4464178f4 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-test.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-test.yml @@ -318,7 +318,7 @@ steps: targetPath: .build/logs displayName: "Publish Log Files" continueOnError: true - condition: failed() + condition: succeededOrFailed() - task: PublishTestResults@2 displayName: Publish Tests Results diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index 8f3b4aad146..98eb2c6a9d4 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -387,7 +387,7 @@ steps: targetPath: .build/logs displayName: "Publish Log Files" continueOnError: true - condition: and(failed(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + condition: and(succeededOrFailed(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - task: PublishTestResults@2 displayName: Publish Tests Results diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 7501869b57d..7fd6ad92186 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -339,7 +339,7 @@ steps: targetPath: .build\logs displayName: "Publish Log Files" continueOnError: true - condition: and(failed(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) + condition: and(succeededOrFailed(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - task: PublishTestResults@2 displayName: Publish Tests Results From 6bd8a2a78a4544a6fb99ca7fcf0f19f5fe13d5c8 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Fri, 10 Jun 2022 08:35:59 +0200 Subject: [PATCH 32/32] Problems table - add tooltip for each cell (#151602) Fix #150981 --- .../contrib/markers/browser/markersTable.ts | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/markers/browser/markersTable.ts b/src/vs/workbench/contrib/markers/browser/markersTable.ts index f5b09444ceb..b0c5efc74d0 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTable.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTable.ts @@ -45,12 +45,14 @@ interface IMarkerCodeColumnTemplateData { } interface IMarkerFileColumnTemplateData { + readonly columnElement: HTMLElement; readonly fileLabel: HighlightedLabel; readonly positionLabel: HighlightedLabel; } interface IMarkerHighlightedLabelColumnTemplateData { + readonly columnElement: HTMLElement; readonly highlightedLabel: HighlightedLabel; } @@ -86,6 +88,7 @@ class MarkerSeverityColumnRenderer implements ITableRenderer