diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 2e1d8b27ca6aeff64b101ac8943d8c3e266fd7bb..2c0b64453ec6934f4de5bd2bd52bb4ca1bc9bff8 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -368,15 +368,15 @@ export function always(promise: TPromise, f: Function): TPromise { * Runs the provided list of promise factories in sequential order. The returned * promise will complete to an array of results from each promise. */ -export function sequence(promiseFactory: ITask>[]): TPromise { +export function sequence(promiseFactories: ITask>[]): TPromise { const results: T[] = []; // reverse since we start with last element using pop() - promiseFactory = promiseFactory.reverse(); + promiseFactories = promiseFactories.reverse(); function next(): Promise { - if (promiseFactory.length) { - return promiseFactory.pop()(); + if (promiseFactories.length) { + return promiseFactories.pop()(); } return null; @@ -398,6 +398,29 @@ export function sequence(promiseFactory: ITask>[]): TPromise return TPromise.as(null).then(thenHandler); } +export function first(promiseFactories: ITask>[], shouldStop: (t: T) => boolean = t => !!t): TPromise { + promiseFactories = [...promiseFactories.reverse()]; + + const loop = () => { + if (promiseFactories.length === 0) { + return TPromise.as(null); + } + + const factory = promiseFactories.pop(); + const promise = factory(); + + return promise.then(result => { + if (shouldStop(result)) { + return TPromise.as(result); + } + + return loop(); + }); + }; + + return loop(); +} + export function once(fn: T): T { const _this = this; let didCall = false; diff --git a/src/vs/editor/common/services/bulkEdit.ts b/src/vs/editor/common/services/bulkEdit.ts index 5a93e61c2cdac3f740919f6bbdc4e496d2712cd0..605a0a4c0abfd7b144e96a27c1666d3905968a25 100644 --- a/src/vs/editor/common/services/bulkEdit.ts +++ b/src/vs/editor/common/services/bulkEdit.ts @@ -76,6 +76,7 @@ class EditTask implements IDisposable { constructor(model: IModel, modelReference: IDisposable) { this._endCursorSelection = null; this._model = model; + this._modelReference = modelReference; this._edits = []; } @@ -142,7 +143,11 @@ class EditTask implements IDisposable { } dispose() { - this._modelReference.dispose(); + if (this._model) { + this._modelReference.dispose(); + this._modelReference = null; + this._model = null; + } } } diff --git a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts index bc3dae035fdd60df8a8b28b4c88a10911049f692..d714c0dd10dd463e7b2361419d08f5e6e545e792 100644 --- a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts +++ b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts @@ -6,6 +6,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; +import { first } from 'vs/base/common/async'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IModel } from 'vs/editor/common/editorCommon'; import { IDisposable, toDisposable, IReference, ReferenceCollection, ImmortalReference } from 'vs/base/common/lifecycle'; @@ -83,14 +84,16 @@ class ResourceModelCollection extends ReferenceCollection () => p.provideTextContent(resource)); - if (!provider) { - return TPromise.wrapError(`No model with uri '${resource}' nor a resolver for the scheme '${resource.scheme}'.`); - } + return first(factories).then(uri => { + if (!uri) { + return TPromise.wrapError(`Could not resolve any model with uri '${resource}'.`); + } - return provider.provideTextContent(resource); + return uri; + }); } }