debt - align editor model closer to file working copy
This commit is contained in:
parent
7031abadea
commit
df6d78a169
|
@ -62,8 +62,8 @@ export class SimpleModel implements IResolvedTextEditorModel {
|
|||
return this._onWillDispose.event;
|
||||
}
|
||||
|
||||
public load(): Promise<SimpleModel> {
|
||||
return Promise.resolve(this);
|
||||
public resolve(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public get textEditorModel(): ITextModel {
|
||||
|
|
|
@ -14,9 +14,14 @@ export interface IEditorModel {
|
|||
readonly onWillDispose: Event<void>;
|
||||
|
||||
/**
|
||||
* Loads the model.
|
||||
* Resolves the model.
|
||||
*/
|
||||
load(): Promise<IEditorModel>;
|
||||
resolve(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Find out if the editor model was resolved or not.
|
||||
*/
|
||||
isResolved(): boolean;
|
||||
|
||||
/**
|
||||
* Find out if this model has been disposed.
|
||||
|
|
|
@ -868,8 +868,8 @@ export interface ITextEditorModel extends IEditorModel {
|
|||
|
||||
/**
|
||||
* The editor model is the heavyweight counterpart of editor input. Depending on the editor input, it
|
||||
* connects to the disk to retrieve content and may allow for saving it back or reverting it. Editor models
|
||||
* are typically cached for some while because they are expensive to construct.
|
||||
* resolves from a file system retrieve content and may allow for saving it back or reverting it.
|
||||
* Editor models are typically cached for some while because they are expensive to construct.
|
||||
*/
|
||||
export class EditorModel extends Disposable implements IEditorModel {
|
||||
|
||||
|
@ -877,19 +877,20 @@ export class EditorModel extends Disposable implements IEditorModel {
|
|||
readonly onWillDispose = this._onWillDispose.event;
|
||||
|
||||
private disposed = false;
|
||||
private resolved = false;
|
||||
|
||||
/**
|
||||
* Causes this model to load returning a promise when loading is completed.
|
||||
* Causes this model to resolve returning a promise when loading is completed.
|
||||
*/
|
||||
async load(): Promise<IEditorModel> {
|
||||
return this;
|
||||
async resolve(): Promise<void> {
|
||||
this.resolved = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this model was loaded or not.
|
||||
*/
|
||||
isResolved(): boolean {
|
||||
return true;
|
||||
return this.resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -56,7 +56,7 @@ export class BinaryEditorModel extends EditorModel {
|
|||
return this.etag;
|
||||
}
|
||||
|
||||
async load(): Promise<BinaryEditorModel> {
|
||||
async resolve(): Promise<void> {
|
||||
|
||||
// Make sure to resolve up to date stat for file resources
|
||||
if (this.fileService.canHandleResource(this.resource)) {
|
||||
|
@ -66,7 +66,5 @@ export class BinaryEditorModel extends EditorModel {
|
|||
this.size = stat.size;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,17 +25,15 @@ export class DiffEditorModel extends EditorModel {
|
|||
this._modifiedModel = modifiedModel;
|
||||
}
|
||||
|
||||
async load(): Promise<EditorModel> {
|
||||
async resolve(): Promise<void> {
|
||||
await Promise.all([
|
||||
this._originalModel?.load(),
|
||||
this._modifiedModel?.load()
|
||||
this._originalModel?.resolve(),
|
||||
this._modifiedModel?.resolve()
|
||||
]);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
isResolved(): boolean {
|
||||
return this.originalModel instanceof EditorModel && this.originalModel.isResolved() && this.modifiedModel instanceof EditorModel && this.modifiedModel.isResolved();
|
||||
return !!(this.originalModel?.isResolved() && this.modifiedModel?.isResolved());
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDiffEditorModel } from 'vs/editor/common/editorCommon';
|
||||
import { EditorModel } from 'vs/workbench/common/editor';
|
||||
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
|
||||
import { DiffEditorModel } from 'vs/workbench/common/editor/diffEditorModel';
|
||||
|
||||
|
@ -32,12 +31,10 @@ export class TextDiffEditorModel extends DiffEditorModel {
|
|||
this.updateTextDiffEditorModel();
|
||||
}
|
||||
|
||||
async load(): Promise<EditorModel> {
|
||||
await super.load();
|
||||
async resolve(): Promise<void> {
|
||||
await super.resolve();
|
||||
|
||||
this.updateTextDiffEditorModel();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private updateTextDiffEditorModel(): void {
|
||||
|
|
|
@ -78,7 +78,7 @@ suite('BackupRestorer', () => {
|
|||
const resource = editor.resource;
|
||||
if (isEqual(resource, untitledFile1)) {
|
||||
const model = await accessor.textFileService.untitled.resolve({ untitledResource: resource });
|
||||
if (model.textEditorModel.getValue() !== 'untitled-1') {
|
||||
if (model.textEditorModel?.getValue() !== 'untitled-1') {
|
||||
const backupContents = await backupFileService.getBackupContents(untitledFile1);
|
||||
assert.fail(`Unable to restore backup for resource ${untitledFile1.toString()}. Backup contents: ${backupContents}`);
|
||||
}
|
||||
|
@ -86,21 +86,23 @@ suite('BackupRestorer', () => {
|
|||
counter++;
|
||||
} else if (isEqual(resource, untitledFile2)) {
|
||||
const model = await accessor.textFileService.untitled.resolve({ untitledResource: resource });
|
||||
if (model.textEditorModel.getValue() !== 'untitled-2') {
|
||||
if (model.textEditorModel?.getValue() !== 'untitled-2') {
|
||||
const backupContents = await backupFileService.getBackupContents(untitledFile2);
|
||||
assert.fail(`Unable to restore backup for resource ${untitledFile2.toString()}. Backup contents: ${backupContents}`);
|
||||
}
|
||||
model.dispose();
|
||||
counter++;
|
||||
} else if (isEqual(resource, fooFile)) {
|
||||
const model = await accessor.textFileService.files.get(fooFile!)?.load();
|
||||
const model = accessor.textFileService.files.get(fooFile);
|
||||
await model?.resolve();
|
||||
if (model?.textEditorModel?.getValue() !== 'fooFile') {
|
||||
const backupContents = await backupFileService.getBackupContents(fooFile);
|
||||
assert.fail(`Unable to restore backup for resource ${fooFile.toString()}. Backup contents: ${backupContents}`);
|
||||
}
|
||||
counter++;
|
||||
} else {
|
||||
const model = await accessor.textFileService.files.get(barFile!)?.load();
|
||||
const model = accessor.textFileService.files.get(barFile);
|
||||
await model?.resolve();
|
||||
if (model?.textEditorModel?.getValue() !== 'barFile') {
|
||||
const backupContents = await backupFileService.getBackupContents(barFile);
|
||||
assert.fail(`Unable to restore backup for resource ${barFile.toString()}. Backup contents: ${backupContents}`);
|
||||
|
|
|
@ -79,7 +79,7 @@ suite('BackupTracker (browser)', function () {
|
|||
const untitledModel = await untitledEditor.resolve();
|
||||
|
||||
if (!untitled?.contents) {
|
||||
untitledModel.textEditorModel.setValue('Super Good');
|
||||
untitledModel.textEditorModel?.setValue('Super Good');
|
||||
}
|
||||
|
||||
await backupFileService.joinBackupResource();
|
||||
|
|
|
@ -214,7 +214,7 @@ flakySuite('BackupTracker (native)', function () {
|
|||
accessor.fileDialogService.setConfirmResult(ConfirmResult.CANCEL);
|
||||
accessor.filesConfigurationService.onFilesConfigurationChange({ files: { hotExit: 'off' } });
|
||||
|
||||
await model?.load();
|
||||
await model?.resolve();
|
||||
model?.textEditorModel?.setValue('foo');
|
||||
assert.strictEqual(accessor.workingCopyService.dirtyCount, 1);
|
||||
|
||||
|
@ -235,7 +235,7 @@ flakySuite('BackupTracker (native)', function () {
|
|||
|
||||
const model = accessor.textFileService.files.get(resource);
|
||||
|
||||
await model?.load();
|
||||
await model?.resolve();
|
||||
model?.textEditorModel?.setValue('foo');
|
||||
assert.strictEqual(accessor.workingCopyService.dirtyCount, 1);
|
||||
|
||||
|
@ -261,7 +261,7 @@ flakySuite('BackupTracker (native)', function () {
|
|||
accessor.fileDialogService.setConfirmResult(ConfirmResult.DONT_SAVE);
|
||||
accessor.filesConfigurationService.onFilesConfigurationChange({ files: { hotExit: 'off' } });
|
||||
|
||||
await model?.load();
|
||||
await model?.resolve();
|
||||
model?.textEditorModel?.setValue('foo');
|
||||
assert.strictEqual(accessor.workingCopyService.dirtyCount, 1);
|
||||
const event = new BeforeShutdownEventImpl();
|
||||
|
@ -285,7 +285,7 @@ flakySuite('BackupTracker (native)', function () {
|
|||
accessor.fileDialogService.setConfirmResult(ConfirmResult.SAVE);
|
||||
accessor.filesConfigurationService.onFilesConfigurationChange({ files: { hotExit: 'off' } });
|
||||
|
||||
await model?.load();
|
||||
await model?.resolve();
|
||||
model?.textEditorModel?.setValue('foo');
|
||||
assert.strictEqual(accessor.workingCopyService.dirtyCount, 1);
|
||||
const event = new BeforeShutdownEventImpl();
|
||||
|
@ -425,7 +425,7 @@ flakySuite('BackupTracker (native)', function () {
|
|||
// Set cancel to force a veto if hot exit does not trigger
|
||||
accessor.fileDialogService.setConfirmResult(ConfirmResult.CANCEL);
|
||||
|
||||
await model?.load();
|
||||
await model?.resolve();
|
||||
model?.textEditorModel?.setValue('foo');
|
||||
assert.strictEqual(accessor.workingCopyService.dirtyCount, 1);
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ suite('Save Participants', function () {
|
|||
test('insert final new line', async function () {
|
||||
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel;
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
const configService = new TestConfigurationService();
|
||||
configService.setUserConfiguration('files', { 'insertFinalNewline': true });
|
||||
const participant = new FinalNewLineParticipant(configService, undefined!);
|
||||
|
@ -66,7 +66,7 @@ suite('Save Participants', function () {
|
|||
test('trim final new lines', async function () {
|
||||
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel;
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
const configService = new TestConfigurationService();
|
||||
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
|
||||
const participant = new TrimFinalNewLinesParticipant(configService, undefined!);
|
||||
|
@ -101,7 +101,7 @@ suite('Save Participants', function () {
|
|||
test('trim final new lines bug#39750', async function () {
|
||||
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel;
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
const configService = new TestConfigurationService();
|
||||
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
|
||||
const participant = new TrimFinalNewLinesParticipant(configService, undefined!);
|
||||
|
@ -128,7 +128,7 @@ suite('Save Participants', function () {
|
|||
test('trim final new lines bug#46075', async function () {
|
||||
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel;
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
const configService = new TestConfigurationService();
|
||||
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
|
||||
const participant = new TrimFinalNewLinesParticipant(configService, undefined!);
|
||||
|
@ -155,7 +155,7 @@ suite('Save Participants', function () {
|
|||
test('trim whitespace', async function () {
|
||||
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel;
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
const configService = new TestConfigurationService();
|
||||
configService.setUserConfiguration('files', { 'trimTrailingWhitespace': true });
|
||||
const participant = new TrimWhitespaceParticipant(configService, undefined!);
|
||||
|
|
|
@ -9,7 +9,7 @@ import { EncodingMode, IFileEditorInput, Verbosity, GroupIdentifier, IMoveResult
|
|||
import { AbstractTextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput';
|
||||
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
|
||||
import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files';
|
||||
import { ITextFileService, TextFileEditorModelState, TextFileLoadReason, TextFileOperationError, TextFileOperationResult, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextFileService, TextFileEditorModelState, TextFileResolveReason, TextFileOperationError, TextFileOperationResult, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IReference, dispose, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
|
@ -291,7 +291,7 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements
|
|||
encoding: this.preferredEncoding,
|
||||
reload: { async: true }, // trigger a reload of the model if it exists already but do not wait to show the model
|
||||
allowBinary: this.forceOpenAs === ForceOpenAs.Text,
|
||||
reason: TextFileLoadReason.EDITOR
|
||||
reason: TextFileResolveReason.EDITOR
|
||||
});
|
||||
|
||||
// This is a bit ugly, because we first resolve the model and then resolve a model reference. the reason being that binary
|
||||
|
@ -328,7 +328,10 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements
|
|||
}
|
||||
|
||||
private async doResolveAsBinary(): Promise<BinaryEditorModel> {
|
||||
return this.instantiationService.createInstance(BinaryEditorModel, this.preferredResource, this.getName()).load();
|
||||
const model = this.instantiationService.createInstance(BinaryEditorModel, this.preferredResource, this.getName());
|
||||
await model.resolve();
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
isResolved(): boolean {
|
||||
|
|
|
@ -149,7 +149,7 @@ suite('Files - TextFileEditorTracker', () => {
|
|||
|
||||
assert.ok(!accessor.editorService.isOpen(untitledEditor));
|
||||
|
||||
model.textEditorModel.setValue('Super Good');
|
||||
model.textEditorModel?.setValue('Super Good');
|
||||
|
||||
await awaitEditorOpening(accessor.editorService);
|
||||
assert.ok(accessor.editorService.isOpen(untitledEditor));
|
||||
|
@ -169,12 +169,12 @@ suite('Files - TextFileEditorTracker', () => {
|
|||
accessor.hostService.setFocus(false);
|
||||
accessor.hostService.setFocus(true);
|
||||
|
||||
await awaitModelLoadEvent(accessor.textFileService, resource);
|
||||
await awaitModelResolveEvent(accessor.textFileService, resource);
|
||||
});
|
||||
|
||||
function awaitModelLoadEvent(textFileService: ITextFileService, resource: URI): Promise<void> {
|
||||
function awaitModelResolveEvent(textFileService: ITextFileService, resource: URI): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
const listener = textFileService.files.onDidLoad(e => {
|
||||
const listener = textFileService.files.onDidResolve(e => {
|
||||
if (isEqual(e.model.resource, resource)) {
|
||||
listener.dispose();
|
||||
resolve();
|
||||
|
|
|
@ -1033,7 +1033,7 @@ export class DefaultPreferencesEditor extends BaseTextEditor {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
return editorModel!.load();
|
||||
return editorModel!.resolve();
|
||||
})
|
||||
.then(editorModel => {
|
||||
if (token.isCancellationRequested) {
|
||||
|
|
|
@ -19,7 +19,7 @@ import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry';
|
|||
import { configurationTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { ITextFileService, ITextFileSaveEvent, ITextFileLoadEvent } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextFileService, ITextFileSaveEvent, ITextFileResolveEvent } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { extname, basename, isEqual, isEqualOrParent } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
@ -124,14 +124,14 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
|
|||
this._register(configurationTelemetry(telemetryService, configurationService));
|
||||
|
||||
// Files Telemetry
|
||||
this._register(textFileService.files.onDidLoad(e => this.onTextFileModelLoaded(e)));
|
||||
this._register(textFileService.files.onDidResolve(e => this.onTextFileModelResolved(e)));
|
||||
this._register(textFileService.files.onDidSave(e => this.onTextFileModelSaved(e)));
|
||||
|
||||
// Lifecycle
|
||||
this._register(lifecycleService.onShutdown(() => this.dispose()));
|
||||
}
|
||||
|
||||
private onTextFileModelLoaded(e: ITextFileLoadEvent): void {
|
||||
private onTextFileModelResolved(e: ITextFileResolveEvent): void {
|
||||
const settingsType = this.getTypeIfSettings(e.model.resource);
|
||||
if (settingsType) {
|
||||
type SettingsReadClassification = {
|
||||
|
|
|
@ -479,10 +479,6 @@ class SimpleDiffEditorModel extends EditorModel {
|
|||
super();
|
||||
}
|
||||
|
||||
async load(): Promise<this> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
super.dispose();
|
||||
this._original.dispose();
|
||||
|
|
|
@ -140,7 +140,7 @@ export class KeybindingsEditorModel extends EditorModel {
|
|||
return result;
|
||||
}
|
||||
|
||||
resolve(actionLabels: Map<string, string>): Promise<EditorModel> {
|
||||
async resolve(actionLabels = new Map<string, string>()): Promise<void> {
|
||||
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
|
||||
this._keybindingItemsSortedByPrecedence = [];
|
||||
|
@ -158,7 +158,6 @@ export class KeybindingsEditorModel extends EditorModel {
|
|||
this._keybindingItemsSortedByPrecedence.push(KeybindingsEditorModel.toKeybindingEntry(command, keybindingItem, workbenchActionsRegistry, actionLabels));
|
||||
}
|
||||
this._keybindingItems = this._keybindingItemsSortedByPrecedence.slice(0).sort((a, b) => KeybindingsEditorModel.compareKeybindingData(a, b));
|
||||
return Promise.resolve(this);
|
||||
}
|
||||
|
||||
private static getId(keybindingItem: IKeybindingItem): string {
|
||||
|
|
|
@ -326,7 +326,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
|
|||
sourceModelEncoding = sourceModelWithEncodingSupport.getEncoding();
|
||||
}
|
||||
|
||||
// Prefer an existing model if it is already loaded for the given target resource
|
||||
// Prefer an existing model if it is already resolved for the given target resource
|
||||
let targetExists: boolean = false;
|
||||
let targetModel = this.files.get(target);
|
||||
if (targetModel?.isResolved()) {
|
||||
|
@ -346,7 +346,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
|
|||
targetModel = await this.files.resolve(target, { encoding: sourceModelEncoding });
|
||||
} catch (error) {
|
||||
// if the target already exists and was not created by us, it is possible
|
||||
// that we cannot load the target as text model if it is binary or too
|
||||
// that we cannot resolve the target as text model if it is binary or too
|
||||
// large. in that case we have to delete the target file first and then
|
||||
// re-run the operation.
|
||||
if (targetExists) {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { localize } from 'vs/nls';
|
|||
import { Emitter } from 'vs/base/common/event';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { assertIsDefined, withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { ITextFileService, TextFileEditorModelState, ITextFileEditorModel, ITextFileStreamContent, ITextFileLoadOptions, IResolvedTextFileEditorModel, ITextFileSaveOptions, TextFileLoadReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextFileService, TextFileEditorModelState, ITextFileEditorModel, ITextFileStreamContent, ITextFileResolveOptions, IResolvedTextFileEditorModel, ITextFileSaveOptions, TextFileResolveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { EncodingMode, IRevertOptions, SaveReason } from 'vs/workbench/common/editor';
|
||||
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
|
||||
import { IBackupFileService, IResolvedBackup } from 'vs/workbench/services/backup/common/backup';
|
||||
|
@ -43,8 +43,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
private readonly _onDidChangeContent = this._register(new Emitter<void>());
|
||||
readonly onDidChangeContent = this._onDidChangeContent.event;
|
||||
|
||||
private readonly _onDidLoad = this._register(new Emitter<TextFileLoadReason>());
|
||||
readonly onDidLoad = this._onDidLoad.event;
|
||||
private readonly _onDidResolve = this._register(new Emitter<TextFileResolveReason>());
|
||||
readonly onDidResolve = this._onDidResolve.event;
|
||||
|
||||
private readonly _onDidChangeDirty = this._register(new Emitter<void>());
|
||||
readonly onDidChangeDirty = this._onDidChangeDirty.event;
|
||||
|
@ -221,7 +221,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
const softUndo = options?.soft;
|
||||
if (!softUndo) {
|
||||
try {
|
||||
await this.load({ forceReadFromFile: true });
|
||||
await this.resolve({ forceReadFromFile: true });
|
||||
} catch (error) {
|
||||
|
||||
// FileNotFound means the file got deleted meanwhile, so ignore it
|
||||
|
@ -246,52 +246,52 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
|
||||
//#endregion
|
||||
|
||||
//#region Load
|
||||
//#region Resolve
|
||||
|
||||
async load(options?: ITextFileLoadOptions): Promise<TextFileEditorModel> {
|
||||
this.logService.trace('[text file model] load() - enter', this.resource.toString(true));
|
||||
async resolve(options?: ITextFileResolveOptions): Promise<void> {
|
||||
this.logService.trace('[text file model] resolve() - enter', this.resource.toString(true));
|
||||
|
||||
// Return early if we are disposed
|
||||
if (this.isDisposed()) {
|
||||
this.logService.trace('[text file model] load() - exit - without loading because model is disposed', this.resource.toString(true));
|
||||
this.logService.trace('[text file model] resolve() - exit - without resolving because model is disposed', this.resource.toString(true));
|
||||
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
|
||||
// Unless there are explicit contents provided, it is important that we do not
|
||||
// load a model that is dirty or is in the process of saving to prevent data
|
||||
// resolve a model that is dirty or is in the process of saving to prevent data
|
||||
// loss.
|
||||
if (!options?.contents && (this.dirty || this.saveSequentializer.hasPending())) {
|
||||
this.logService.trace('[text file model] load() - exit - without loading because model is dirty or being saved', this.resource.toString(true));
|
||||
this.logService.trace('[text file model] resolve() - exit - without resolving because model is dirty or being saved', this.resource.toString(true));
|
||||
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
|
||||
return this.doLoad(options);
|
||||
return this.doResolve(options);
|
||||
}
|
||||
|
||||
private async doLoad(options?: ITextFileLoadOptions): Promise<TextFileEditorModel> {
|
||||
private async doResolve(options?: ITextFileResolveOptions): Promise<void> {
|
||||
|
||||
// First check if we have contents to use for the model
|
||||
if (options?.contents) {
|
||||
return this.loadFromBuffer(options.contents, options);
|
||||
return this.resolveFromBuffer(options.contents, options);
|
||||
}
|
||||
|
||||
// Second, check if we have a backup to load from (only for new models)
|
||||
// Second, check if we have a backup to resolve from (only for new models)
|
||||
const isNewModel = !this.isResolved();
|
||||
if (isNewModel) {
|
||||
const loadedFromBackup = await this.loadFromBackup(options);
|
||||
if (loadedFromBackup) {
|
||||
return loadedFromBackup;
|
||||
const resolvedFromBackup = await this.resolveFromBackup(options);
|
||||
if (resolvedFromBackup) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, load from file resource
|
||||
return this.loadFromFile(options);
|
||||
// Finally, resolve from file resource
|
||||
return this.resolveFromFile(options);
|
||||
}
|
||||
|
||||
private async loadFromBuffer(buffer: ITextBufferFactory, options?: ITextFileLoadOptions): Promise<TextFileEditorModel> {
|
||||
this.logService.trace('[text file model] loadFromBuffer()', this.resource.toString(true));
|
||||
private async resolveFromBuffer(buffer: ITextBufferFactory, options?: ITextFileResolveOptions): Promise<void> {
|
||||
this.logService.trace('[text file model] resolveFromBuffer()', this.resource.toString(true));
|
||||
|
||||
// Try to resolve metdata from disk
|
||||
let mtime: number;
|
||||
|
@ -321,8 +321,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
|
||||
const preferredEncoding = await this.textFileService.encoding.getPreferredWriteEncoding(this.resource, this.preferredEncoding);
|
||||
|
||||
// Load with buffer
|
||||
this.loadFromContent({
|
||||
// Resolve with buffer
|
||||
this.resolveFromContent({
|
||||
resource: this.resource,
|
||||
name: this.name,
|
||||
mtime,
|
||||
|
@ -331,12 +331,10 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
etag,
|
||||
value: buffer,
|
||||
encoding: preferredEncoding.encoding
|
||||
}, true /* dirty (loaded from buffer) */, options);
|
||||
|
||||
return this;
|
||||
}, true /* dirty (resolved from buffer) */, options);
|
||||
}
|
||||
|
||||
private async loadFromBackup(options?: ITextFileLoadOptions): Promise<TextFileEditorModel | undefined> {
|
||||
private async resolveFromBackup(options?: ITextFileResolveOptions): Promise<boolean> {
|
||||
|
||||
// Resolve backup if any
|
||||
const backup = await this.backupFileService.resolve<IBackupMetaData>(this.resource);
|
||||
|
@ -350,25 +348,27 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
// Abort if someone else managed to resolve the model by now
|
||||
let isNewModel = !this.isResolved();
|
||||
if (!isNewModel) {
|
||||
this.logService.trace('[text file model] loadFromBackup() - exit - without loading because previously new model got created meanwhile', this.resource.toString(true));
|
||||
this.logService.trace('[text file model] resolveFromBackup() - exit - without resolving because previously new model got created meanwhile', this.resource.toString(true));
|
||||
|
||||
return this; // imply that loading has happened in another operation
|
||||
return true; // imply that resolving has happened in another operation
|
||||
}
|
||||
|
||||
// Try to load from backup if we have any
|
||||
// Try to resolve from backup if we have any
|
||||
if (backup) {
|
||||
return this.doLoadFromBackup(backup, encoding, options);
|
||||
this.doResolveFromBackup(backup, encoding, options);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise signal back that loading did not happen
|
||||
return undefined;
|
||||
// Otherwise signal back that resolving did not happen
|
||||
return false;
|
||||
}
|
||||
|
||||
private doLoadFromBackup(backup: IResolvedBackup<IBackupMetaData>, encoding: string, options?: ITextFileLoadOptions): TextFileEditorModel {
|
||||
this.logService.trace('[text file model] doLoadFromBackup()', this.resource.toString(true));
|
||||
private doResolveFromBackup(backup: IResolvedBackup<IBackupMetaData>, encoding: string, options?: ITextFileResolveOptions): void {
|
||||
this.logService.trace('[text file model] doResolveFromBackup()', this.resource.toString(true));
|
||||
|
||||
// Load with backup
|
||||
this.loadFromContent({
|
||||
// Resolve with backup
|
||||
this.resolveFromContent({
|
||||
resource: this.resource,
|
||||
name: this.name,
|
||||
mtime: backup.meta ? backup.meta.mtime : Date.now(),
|
||||
|
@ -377,18 +377,16 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
etag: backup.meta ? backup.meta.etag : ETAG_DISABLED, // etag disabled if unknown!
|
||||
value: backup.value,
|
||||
encoding
|
||||
}, true /* dirty (loaded from backup) */, options);
|
||||
}, true /* dirty (resolved from backup) */, options);
|
||||
|
||||
// Restore orphaned flag based on state
|
||||
if (backup.meta && backup.meta.orphaned) {
|
||||
this.setOrphaned(true);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private async loadFromFile(options?: ITextFileLoadOptions): Promise<TextFileEditorModel> {
|
||||
this.logService.trace('[text file model] loadFromFile()', this.resource.toString(true));
|
||||
private async resolveFromFile(options?: ITextFileResolveOptions): Promise<void> {
|
||||
this.logService.trace('[text file model] resolveFromFile()', this.resource.toString(true));
|
||||
|
||||
const forceReadFromFile = options?.forceReadFromFile;
|
||||
const allowBinary = this.isResolved() /* always allow if we resolved previously */ || options?.allowBinary;
|
||||
|
@ -409,18 +407,18 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
try {
|
||||
const content = await this.textFileService.readStream(this.resource, { acceptTextOnly: !allowBinary, etag, encoding: this.preferredEncoding });
|
||||
|
||||
// Clear orphaned state when loading was successful
|
||||
// Clear orphaned state when resolving was successful
|
||||
this.setOrphaned(false);
|
||||
|
||||
// Return early if the model content has changed
|
||||
// meanwhile to prevent loosing any changes
|
||||
if (currentVersionId !== this.versionId) {
|
||||
this.logService.trace('[text file model] loadFromFile() - exit - without loading because model content changed', this.resource.toString(true));
|
||||
this.logService.trace('[text file model] resolveFromFile() - exit - without resolving because model content changed', this.resource.toString(true));
|
||||
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
|
||||
return this.loadFromContent(content, false /* not dirty (loaded from file) */, options);
|
||||
return this.resolveFromContent(content, false /* not dirty (resolved from file) */, options);
|
||||
} catch (error) {
|
||||
const result = error.fileOperationResult;
|
||||
|
||||
|
@ -430,15 +428,15 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
// NotModified status is expected and can be handled gracefully
|
||||
// if we are resolved
|
||||
if (this.isResolved() && result === FileOperationResult.FILE_NOT_MODIFIED_SINCE) {
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
|
||||
// Unless we are forced to read from the file, Ignore when a model has been resolved once
|
||||
// and the file was deleted meanwhile. Since we already have the model loaded, we can return
|
||||
// and the file was deleted meanwhile. Since we already have the model resolved, we can return
|
||||
// to this state and update the orphaned flag to indicate that this model has no version on
|
||||
// disk anymore.
|
||||
if (this.isResolved() && result === FileOperationResult.FILE_NOT_FOUND && !forceReadFromFile) {
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise bubble up the error
|
||||
|
@ -446,14 +444,14 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
}
|
||||
}
|
||||
|
||||
private loadFromContent(content: ITextFileStreamContent, dirty: boolean, options?: ITextFileLoadOptions): TextFileEditorModel {
|
||||
this.logService.trace('[text file model] loadFromContent() - enter', this.resource.toString(true));
|
||||
private resolveFromContent(content: ITextFileStreamContent, dirty: boolean, options?: ITextFileResolveOptions): void {
|
||||
this.logService.trace('[text file model] resolveFromContent() - enter', this.resource.toString(true));
|
||||
|
||||
// Return early if we are disposed
|
||||
if (this.isDisposed()) {
|
||||
this.logService.trace('[text file model] loadFromContent() - exit - because model is disposed', this.resource.toString(true));
|
||||
this.logService.trace('[text file model] resolveFromContent() - exit - because model is disposed', this.resource.toString(true));
|
||||
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
|
||||
// Update our resolved disk stat model
|
||||
|
@ -498,9 +496,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
this.setDirty(!!dirty);
|
||||
|
||||
// Emit as event
|
||||
this._onDidLoad.fire(options?.reason ?? TextFileLoadReason.OTHER);
|
||||
|
||||
return this;
|
||||
this._onDidResolve.fire(options?.reason ?? TextFileResolveReason.OTHER);
|
||||
}
|
||||
|
||||
private doCreateTextModel(resource: URI, value: ITextBufferFactory): void {
|
||||
|
@ -550,7 +546,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
}
|
||||
|
||||
// We mark check for a dirty-state change upon model content change, unless:
|
||||
// - explicitly instructed to ignore it (e.g. from model.load())
|
||||
// - explicitly instructed to ignore it (e.g. from model.resolve())
|
||||
// - the model is readonly (in that case we never assume the change was done by the user)
|
||||
if (!this.ignoreDirtyOnModelContentChange && !this.isReadonly()) {
|
||||
|
||||
|
@ -884,7 +880,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
}
|
||||
|
||||
// Subsequent resolve - make sure that we only assign it if the mtime is equal or has advanced.
|
||||
// This prevents race conditions from loading and saving. If a save comes in late after a revert
|
||||
// This prevents race conditions from resolving and saving. If a save comes in late after a revert
|
||||
// was called, the mtime could be out of sync.
|
||||
else if (this.lastResolvedFileStat.mtime <= newFileStat.mtime) {
|
||||
this.lastResolvedFileStat = newFileStat;
|
||||
|
@ -950,7 +946,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
}
|
||||
}
|
||||
|
||||
// Decode: Load with encoding
|
||||
// Decode: Resolve with encoding
|
||||
else {
|
||||
if (this.isDirty()) {
|
||||
this.notificationService.info(localize('saveFileFirst', "The file is dirty. Please save it first before reopening it with another encoding."));
|
||||
|
@ -960,8 +956,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
|
||||
this.updatePreferredEncoding(encoding);
|
||||
|
||||
// Load
|
||||
this.load({
|
||||
this.resolve({
|
||||
forceReadFromFile: true // because encoding has changed
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import { Event, Emitter } from 'vs/base/common/event';
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||
import { dispose, IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ITextFileEditorModel, ITextFileEditorModelManager, ITextFileEditorModelLoadOrCreateOptions, ITextFileLoadEvent, ITextFileSaveEvent, ITextFileSaveParticipant } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextFileEditorModel, ITextFileEditorModelManager, ITextFileEditorModelResolveOrCreateOptions, ITextFileResolveEvent, ITextFileSaveEvent, ITextFileSaveParticipant } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
|
@ -32,8 +32,8 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
private readonly _onDidCreate = this._register(new Emitter<TextFileEditorModel>());
|
||||
readonly onDidCreate = this._onDidCreate.event;
|
||||
|
||||
private readonly _onDidLoad = this._register(new Emitter<ITextFileLoadEvent>());
|
||||
readonly onDidLoad = this._onDidLoad.event;
|
||||
private readonly _onDidResolve = this._register(new Emitter<ITextFileResolveEvent>());
|
||||
readonly onDidResolve = this._onDidResolve.event;
|
||||
|
||||
private readonly _onDidChangeDirty = this._register(new Emitter<TextFileEditorModel>());
|
||||
readonly onDidChangeDirty = this._onDidChangeDirty.event;
|
||||
|
@ -53,9 +53,9 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
private readonly mapResourceToModel = new ResourceMap<TextFileEditorModel>();
|
||||
private readonly mapResourceToModelListeners = new ResourceMap<IDisposable>();
|
||||
private readonly mapResourceToDisposeListener = new ResourceMap<IDisposable>();
|
||||
private readonly mapResourceToPendingModelLoaders = new ResourceMap<Promise<TextFileEditorModel>>();
|
||||
private readonly mapResourceToPendingModelResolvers = new ResourceMap<Promise<void>>();
|
||||
|
||||
private readonly modelLoadQueue = this._register(new ResourceQueue());
|
||||
private readonly modelResolveQueue = this._register(new ResourceQueue());
|
||||
|
||||
saveErrorHandler = (() => {
|
||||
const notificationService = this.notificationService;
|
||||
|
@ -104,25 +104,25 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
continue; // require a resolved, saved model to continue
|
||||
}
|
||||
|
||||
// Trigger a model load for any update or add event that impacts
|
||||
// Trigger a model resolve for any update or add event that impacts
|
||||
// the model. We also consider the added event because it could
|
||||
// be that a file was added and updated right after.
|
||||
if (e.contains(model.resource, FileChangeType.UPDATED, FileChangeType.ADDED)) {
|
||||
this.queueModelLoad(model);
|
||||
this.queueModelResolve(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private queueModelLoad(model: TextFileEditorModel): void {
|
||||
private queueModelResolve(model: TextFileEditorModel): void {
|
||||
|
||||
// Load model to update (use a queue to prevent accumulation of loads
|
||||
// when the load actually takes long. At most we only want the queue
|
||||
// to have a size of 2 (1 running load and 1 queued load).
|
||||
const queue = this.modelLoadQueue.queueFor(model.resource);
|
||||
// Resolve model to update (use a queue to prevent accumulation of resolves
|
||||
// when the resolve actually takes long. At most we only want the queue
|
||||
// to have a size of 2 (1 running resolve and 1 queued resolve).
|
||||
const queue = this.modelResolveQueue.queueFor(model.resource);
|
||||
if (queue.size <= 1) {
|
||||
queue.queue(async () => {
|
||||
try {
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
}
|
||||
}
|
||||
|
||||
// remember each source model to load again after move is done
|
||||
// remember each source model to resolve again after move is done
|
||||
// with optional content to restore if it was dirty
|
||||
for (const sourceModel of sourceModels) {
|
||||
const sourceModelResource = sourceModel.resource;
|
||||
|
@ -219,7 +219,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
})());
|
||||
break;
|
||||
|
||||
// Move/Copy: restore models that were loaded before the operation took place
|
||||
// Move/Copy: restore models that were resolved before the operation took place
|
||||
case FileOperation.MOVE:
|
||||
case FileOperation.COPY:
|
||||
e.waitUntil((async () => {
|
||||
|
@ -255,17 +255,17 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
return this.mapResourceToModel.get(resource);
|
||||
}
|
||||
|
||||
async resolve(resource: URI, options?: ITextFileEditorModelLoadOrCreateOptions): Promise<TextFileEditorModel> {
|
||||
async resolve(resource: URI, options?: ITextFileEditorModelResolveOrCreateOptions): Promise<TextFileEditorModel> {
|
||||
|
||||
// Await a pending model load first before proceeding
|
||||
// to ensure that we never load a model more than once
|
||||
// Await a pending model resolve first before proceeding
|
||||
// to ensure that we never resolve a model more than once
|
||||
// in parallel
|
||||
const pendingResolve = this.joinPendingResolve(resource);
|
||||
if (pendingResolve) {
|
||||
await pendingResolve;
|
||||
}
|
||||
|
||||
let modelPromise: Promise<TextFileEditorModel>;
|
||||
let modelPromise: Promise<void>;
|
||||
let model = this.get(resource);
|
||||
let didCreateModel = false;
|
||||
|
||||
|
@ -274,7 +274,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
|
||||
// Always reload if contents are provided
|
||||
if (options?.contents) {
|
||||
modelPromise = model.load(options);
|
||||
modelPromise = model.resolve(options);
|
||||
}
|
||||
|
||||
// Reload async or sync based on options
|
||||
|
@ -282,19 +282,19 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
|
||||
// async reload: trigger a reload but return immediately
|
||||
if (options.reload.async) {
|
||||
modelPromise = Promise.resolve(model);
|
||||
model.load(options);
|
||||
modelPromise = Promise.resolve();
|
||||
model.resolve(options);
|
||||
}
|
||||
|
||||
// sync reload: do not return until model reloaded
|
||||
else {
|
||||
modelPromise = model.load(options);
|
||||
modelPromise = model.resolve(options);
|
||||
}
|
||||
}
|
||||
|
||||
// Do not reload
|
||||
else {
|
||||
modelPromise = Promise.resolve(model);
|
||||
modelPromise = Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,13 +303,13 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
didCreateModel = true;
|
||||
|
||||
const newModel = model = this.instantiationService.createInstance(TextFileEditorModel, resource, options ? options.encoding : undefined, options ? options.mode : undefined);
|
||||
modelPromise = model.load(options);
|
||||
modelPromise = model.resolve(options);
|
||||
|
||||
this.registerModel(newModel);
|
||||
}
|
||||
|
||||
// Store pending loads to avoid race conditions
|
||||
this.mapResourceToPendingModelLoaders.set(resource, modelPromise);
|
||||
// Store pending resolves to avoid race conditions
|
||||
this.mapResourceToPendingModelResolvers.set(resource, modelPromise);
|
||||
|
||||
// Make known to manager (if not already known)
|
||||
this.add(resource, model);
|
||||
|
@ -326,23 +326,23 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
}
|
||||
|
||||
try {
|
||||
const resolvedModel = await modelPromise;
|
||||
await modelPromise;
|
||||
|
||||
// Remove from pending loads
|
||||
this.mapResourceToPendingModelLoaders.delete(resource);
|
||||
// Remove from pending resolves
|
||||
this.mapResourceToPendingModelResolvers.delete(resource);
|
||||
|
||||
// Apply mode if provided
|
||||
if (options?.mode) {
|
||||
resolvedModel.setMode(options.mode);
|
||||
model.setMode(options.mode);
|
||||
}
|
||||
|
||||
// Model can be dirty if a backup was restored, so we make sure to
|
||||
// have this event delivered if we created the model here
|
||||
if (didCreateModel && resolvedModel.isDirty()) {
|
||||
this._onDidChangeDirty.fire(resolvedModel);
|
||||
if (didCreateModel && model.isDirty()) {
|
||||
this._onDidChangeDirty.fire(model);
|
||||
}
|
||||
|
||||
return resolvedModel;
|
||||
return model;
|
||||
} catch (error) {
|
||||
|
||||
// Free resources of this invalid model
|
||||
|
@ -350,17 +350,17 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
model.dispose();
|
||||
}
|
||||
|
||||
// Remove from pending loads
|
||||
this.mapResourceToPendingModelLoaders.delete(resource);
|
||||
// Remove from pending resolves
|
||||
this.mapResourceToPendingModelResolvers.delete(resource);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private joinPendingResolve(resource: URI): Promise<void> | undefined {
|
||||
const pendingModelLoad = this.mapResourceToPendingModelLoaders.get(resource);
|
||||
if (pendingModelLoad) {
|
||||
return pendingModelLoad.then(undefined, error => {/* ignore any error here, it will bubble to the original requestor*/ });
|
||||
const pendingModelResolve = this.mapResourceToPendingModelResolvers.get(resource);
|
||||
if (pendingModelResolve) {
|
||||
return pendingModelResolve.then(undefined, error => {/* ignore any error here, it will bubble to the original requestor*/ });
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
@ -370,7 +370,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
|
||||
// Install model listeners
|
||||
const modelListeners = new DisposableStore();
|
||||
modelListeners.add(model.onDidLoad(reason => this._onDidLoad.fire({ model, reason })));
|
||||
modelListeners.add(model.onDidResolve(reason => this._onDidResolve.fire({ model, reason })));
|
||||
modelListeners.add(model.onDidChangeDirty(() => this._onDidChangeDirty.fire(model)));
|
||||
modelListeners.add(model.onDidSaveError(() => this._onDidSaveError.fire(model)));
|
||||
modelListeners.add(model.onDidSave(reason => this._onDidSave.fire({ model, reason })));
|
||||
|
@ -432,7 +432,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
|
||||
// model caches
|
||||
this.mapResourceToModel.clear();
|
||||
this.mapResourceToPendingModelLoaders.clear();
|
||||
this.mapResourceToPendingModelResolvers.clear();
|
||||
|
||||
// dispose the dispose listeners
|
||||
this.mapResourceToDisposeListener.forEach(listener => listener.dispose());
|
||||
|
@ -445,10 +445,10 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
|
||||
canDispose(model: TextFileEditorModel): true | Promise<true> {
|
||||
|
||||
// quick return if model already disposed or not dirty and not loading
|
||||
// quick return if model already disposed or not dirty and not resolving
|
||||
if (
|
||||
model.isDisposed() ||
|
||||
(!this.mapResourceToPendingModelLoaders.has(model.resource) && !model.isDirty())
|
||||
(!this.mapResourceToPendingModelResolvers.has(model.resource) && !model.isDirty())
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
@ -459,7 +459,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||
|
||||
private async doCanDispose(model: TextFileEditorModel): Promise<true> {
|
||||
|
||||
// if we have a pending model load, await it first and then try again
|
||||
// if we have a pending model resolve, await it first and then try again
|
||||
const pendingResolve = this.joinPendingResolve(model.resource);
|
||||
if (pendingResolve) {
|
||||
await pendingResolve;
|
||||
|
|
|
@ -214,7 +214,7 @@ export const enum TextFileEditorModelState {
|
|||
ERROR
|
||||
}
|
||||
|
||||
export const enum TextFileLoadReason {
|
||||
export const enum TextFileResolveReason {
|
||||
EDITOR = 1,
|
||||
REFERENCE = 2,
|
||||
OTHER = 3
|
||||
|
@ -244,12 +244,12 @@ export interface ITextFileStreamContent extends IBaseTextFileContent {
|
|||
value: ITextBufferFactory;
|
||||
}
|
||||
|
||||
export interface ITextFileEditorModelLoadOrCreateOptions {
|
||||
export interface ITextFileEditorModelResolveOrCreateOptions {
|
||||
|
||||
/**
|
||||
* Context why the model is being loaded or created.
|
||||
* Context why the model is being resolved or created.
|
||||
*/
|
||||
reason?: TextFileLoadReason;
|
||||
reason?: TextFileResolveReason;
|
||||
|
||||
/**
|
||||
* The language mode to use for the model text content.
|
||||
|
@ -269,7 +269,7 @@ export interface ITextFileEditorModelLoadOrCreateOptions {
|
|||
contents?: ITextBufferFactory;
|
||||
|
||||
/**
|
||||
* If the model was already loaded before, allows to trigger
|
||||
* If the model was already resolved before, allows to trigger
|
||||
* a reload of it to fetch the latest contents:
|
||||
* - async: resolve() will return immediately and trigger
|
||||
* a reload that will run in the background.
|
||||
|
@ -281,7 +281,7 @@ export interface ITextFileEditorModelLoadOrCreateOptions {
|
|||
};
|
||||
|
||||
/**
|
||||
* Allow to load a model even if we think it is a binary file.
|
||||
* Allow to resolve a model even if we think it is a binary file.
|
||||
*/
|
||||
allowBinary?: boolean;
|
||||
}
|
||||
|
@ -291,9 +291,9 @@ export interface ITextFileSaveEvent {
|
|||
reason: SaveReason;
|
||||
}
|
||||
|
||||
export interface ITextFileLoadEvent {
|
||||
export interface ITextFileResolveEvent {
|
||||
model: ITextFileEditorModel;
|
||||
reason: TextFileLoadReason;
|
||||
reason: TextFileResolveReason;
|
||||
}
|
||||
|
||||
export interface ITextFileSaveParticipant {
|
||||
|
@ -313,7 +313,7 @@ export interface ITextFileSaveParticipant {
|
|||
export interface ITextFileEditorModelManager {
|
||||
|
||||
readonly onDidCreate: Event<ITextFileEditorModel>;
|
||||
readonly onDidLoad: Event<ITextFileLoadEvent>;
|
||||
readonly onDidResolve: Event<ITextFileResolveEvent>;
|
||||
readonly onDidChangeDirty: Event<ITextFileEditorModel>;
|
||||
readonly onDidChangeEncoding: Event<ITextFileEditorModel>;
|
||||
readonly onDidSaveError: Event<ITextFileEditorModel>;
|
||||
|
@ -337,9 +337,9 @@ export interface ITextFileEditorModelManager {
|
|||
get(resource: URI): ITextFileEditorModel | undefined;
|
||||
|
||||
/**
|
||||
* Allows to load a text file model from disk.
|
||||
* Allows to resolve a text file model from disk.
|
||||
*/
|
||||
resolve(resource: URI, options?: ITextFileEditorModelLoadOrCreateOptions): Promise<ITextFileEditorModel>;
|
||||
resolve(resource: URI, options?: ITextFileEditorModelResolveOrCreateOptions): Promise<ITextFileEditorModel>;
|
||||
|
||||
/**
|
||||
* Adds a participant for saving text file models.
|
||||
|
@ -392,7 +392,7 @@ export interface ITextFileSaveAsOptions extends ITextFileSaveOptions {
|
|||
suggestedTarget?: URI;
|
||||
}
|
||||
|
||||
export interface ITextFileLoadOptions {
|
||||
export interface ITextFileResolveOptions {
|
||||
|
||||
/**
|
||||
* The contents to use for the model if known. If not
|
||||
|
@ -407,14 +407,14 @@ export interface ITextFileLoadOptions {
|
|||
forceReadFromFile?: boolean;
|
||||
|
||||
/**
|
||||
* Allow to load a model even if we think it is a binary file.
|
||||
* Allow to resolve a model even if we think it is a binary file.
|
||||
*/
|
||||
allowBinary?: boolean;
|
||||
|
||||
/**
|
||||
* Context why the model is being loaded.
|
||||
* Context why the model is being resolved.
|
||||
*/
|
||||
reason?: TextFileLoadReason;
|
||||
reason?: TextFileResolveReason;
|
||||
}
|
||||
|
||||
export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport, IModeSupport, IWorkingCopy {
|
||||
|
@ -432,7 +432,7 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport
|
|||
save(options?: ITextFileSaveOptions): Promise<boolean>;
|
||||
revert(options?: IRevertOptions): Promise<void>;
|
||||
|
||||
load(options?: ITextFileLoadOptions): Promise<ITextFileEditorModel>;
|
||||
resolve(options?: ITextFileResolveOptions): Promise<void>;
|
||||
|
||||
isDirty(): this is IResolvedTextFileEditorModel;
|
||||
|
||||
|
|
|
@ -43,12 +43,12 @@ suite('Files - TextFileEditorModel', () => {
|
|||
test('basic events', async function () {
|
||||
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
|
||||
let onDidLoadCounter = 0;
|
||||
model.onDidLoad(() => onDidLoadCounter++);
|
||||
let onDidResolveCounter = 0;
|
||||
model.onDidResolve(() => onDidResolveCounter++);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
|
||||
assert.strictEqual(onDidLoadCounter, 1);
|
||||
assert.strictEqual(onDidResolveCounter, 1);
|
||||
|
||||
let onDidChangeContentCounter = 0;
|
||||
model.onDidChangeContent(() => onDidChangeContentCounter++);
|
||||
|
@ -84,7 +84,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
test('save', async function () {
|
||||
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
|
||||
assert.strictEqual(accessor.workingCopyService.dirtyCount, 0);
|
||||
|
||||
|
@ -133,7 +133,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
test('save - touching also emits saved event', async function () {
|
||||
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
|
||||
let savedEvent = false;
|
||||
model.onDidSave(() => savedEvent = true);
|
||||
|
@ -157,7 +157,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
test('save - touching with error turns model dirty', async function () {
|
||||
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
|
||||
let saveErrorEvent = false;
|
||||
model.onDidSaveError(() => saveErrorEvent = true);
|
||||
|
@ -191,7 +191,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
test('save error (generic)', async function () {
|
||||
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
|
||||
model.updateTextEditorModel(createTextBufferFactory('bar'));
|
||||
|
||||
|
@ -221,7 +221,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
test('save error (conflict)', async function () {
|
||||
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
|
||||
model.updateTextEditorModel(createTextBufferFactory('bar'));
|
||||
|
||||
|
@ -274,7 +274,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
model.setEncoding('utf16', EncodingMode.Decode);
|
||||
|
||||
await timeout(0);
|
||||
assert.ok(model.isResolved()); // model got loaded due to decoding
|
||||
assert.ok(model.isResolved()); // model got resolved due to decoding
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
|
@ -286,7 +286,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
|
||||
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', mode);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
|
||||
assert.strictEqual(model.textEditorModel!.getModeId(), mode);
|
||||
|
||||
|
@ -297,47 +297,47 @@ suite('Files - TextFileEditorModel', () => {
|
|||
test('disposes when underlying model is destroyed', async function () {
|
||||
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
|
||||
model.textEditorModel!.dispose();
|
||||
assert.ok(model.isDisposed());
|
||||
});
|
||||
|
||||
test('Load does not trigger save', async function () {
|
||||
test('Resolve does not trigger save', async function () {
|
||||
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index.txt'), 'utf8', undefined);
|
||||
assert.ok(model.hasState(TextFileEditorModelState.SAVED));
|
||||
|
||||
model.onDidSave(() => assert.fail());
|
||||
model.onDidChangeDirty(() => assert.fail());
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
assert.ok(model.isResolved());
|
||||
model.dispose();
|
||||
assert.ok(!accessor.modelService.getModel(model.resource));
|
||||
});
|
||||
|
||||
test('Load returns dirty model as long as model is dirty', async function () {
|
||||
test('Resolve returns dirty model as long as model is dirty', async function () {
|
||||
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.updateTextEditorModel(createTextBufferFactory('foo'));
|
||||
assert.ok(model.isDirty());
|
||||
assert.ok(model.hasState(TextFileEditorModelState.DIRTY));
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
assert.ok(model.isDirty());
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('Load with contents', async function () {
|
||||
test('Resolve with contents', async function () {
|
||||
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
|
||||
await model.load({ contents: createTextBufferFactory('Hello World') });
|
||||
await model.resolve({ contents: createTextBufferFactory('Hello World') });
|
||||
|
||||
assert.strictEqual(model.textEditorModel?.getValue(), 'Hello World');
|
||||
assert.strictEqual(model.isDirty(), true);
|
||||
|
||||
await model.load({ contents: createTextBufferFactory('Hello Changes') });
|
||||
await model.resolve({ contents: createTextBufferFactory('Hello Changes') });
|
||||
|
||||
assert.strictEqual(model.textEditorModel?.getValue(), 'Hello Changes');
|
||||
assert.strictEqual(model.isDirty(), true);
|
||||
|
@ -365,7 +365,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
}
|
||||
});
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.updateTextEditorModel(createTextBufferFactory('foo'));
|
||||
assert.ok(model.isDirty());
|
||||
|
||||
|
@ -398,7 +398,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
}
|
||||
});
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.updateTextEditorModel(createTextBufferFactory('foo'));
|
||||
assert.ok(model.isDirty());
|
||||
|
||||
|
@ -419,7 +419,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
|
||||
test('Undo to saved state turns model non-dirty', async function () {
|
||||
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.updateTextEditorModel(createTextBufferFactory('Hello Text'));
|
||||
assert.ok(model.isDirty());
|
||||
|
||||
|
@ -427,12 +427,12 @@ suite('Files - TextFileEditorModel', () => {
|
|||
assert.ok(!model.isDirty());
|
||||
});
|
||||
|
||||
test('Load and undo turns model dirty', async function () {
|
||||
test('Resolve and undo turns model dirty', async function () {
|
||||
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
accessor.fileService.setContent('Hello Change');
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
await model.textEditorModel!.undo();
|
||||
assert.ok(model.isDirty());
|
||||
|
||||
|
@ -448,7 +448,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
model.setDirty(true);
|
||||
assert.ok(!model.isDirty()); // needs to be resolved
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.updateTextEditorModel(createTextBufferFactory('foo'));
|
||||
assert.ok(model.isDirty());
|
||||
|
||||
|
@ -491,7 +491,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
saveEvent = true;
|
||||
});
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.updateTextEditorModel(createTextBufferFactory('foo'));
|
||||
assert.ok(!model.isDirty());
|
||||
|
||||
|
@ -509,25 +509,25 @@ suite('Files - TextFileEditorModel', () => {
|
|||
test('File not modified error is handled gracefully', async function () {
|
||||
let model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
|
||||
const mtime = getLastModifiedTime(model);
|
||||
accessor.textFileService.setReadStreamErrorOnce(new FileOperationError('error', FileOperationResult.FILE_NOT_MODIFIED_SINCE));
|
||||
|
||||
model = await model.load() as TextFileEditorModel;
|
||||
await model.resolve();
|
||||
|
||||
assert.ok(model);
|
||||
assert.strictEqual(getLastModifiedTime(model), mtime);
|
||||
model.dispose();
|
||||
});
|
||||
|
||||
test('Load error is handled gracefully if model already exists', async function () {
|
||||
test('Resolve error is handled gracefully if model already exists', async function () {
|
||||
let model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
accessor.textFileService.setReadStreamErrorOnce(new FileOperationError('error', FileOperationResult.FILE_NOT_FOUND));
|
||||
|
||||
model = await model.load() as TextFileEditorModel;
|
||||
await model.resolve();
|
||||
assert.ok(model);
|
||||
model.dispose();
|
||||
});
|
||||
|
@ -583,7 +583,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
}
|
||||
});
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.updateTextEditorModel(createTextBufferFactory('foo'));
|
||||
assert.ok(model.isDirty());
|
||||
|
||||
|
@ -610,7 +610,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
}
|
||||
});
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.updateTextEditorModel(createTextBufferFactory('foo'));
|
||||
|
||||
await model.save({ skipSaveParticipants: true });
|
||||
|
@ -640,7 +640,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
}
|
||||
});
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.updateTextEditorModel(createTextBufferFactory('foo'));
|
||||
|
||||
const now = Date.now();
|
||||
|
@ -661,7 +661,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
}
|
||||
});
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.updateTextEditorModel(createTextBufferFactory('foo'));
|
||||
|
||||
await model.save();
|
||||
|
@ -685,7 +685,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
}
|
||||
});
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
|
||||
model.updateTextEditorModel(createTextBufferFactory('foo'));
|
||||
const p1 = model.save();
|
||||
|
@ -744,7 +744,7 @@ suite('Files - TextFileEditorModel', () => {
|
|||
}
|
||||
});
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.updateTextEditorModel(createTextBufferFactory('foo'));
|
||||
|
||||
savePromise = model.save();
|
||||
|
|
|
@ -186,16 +186,16 @@ suite('Files - TextFileEditorModelManager', () => {
|
|||
const resource1 = toResource.call(this, '/path/index.txt');
|
||||
const resource2 = toResource.call(this, '/path/other.txt');
|
||||
|
||||
let loadedCounter = 0;
|
||||
let resolvedCounter = 0;
|
||||
let gotDirtyCounter = 0;
|
||||
let gotNonDirtyCounter = 0;
|
||||
let revertedCounter = 0;
|
||||
let savedCounter = 0;
|
||||
let encodingCounter = 0;
|
||||
|
||||
manager.onDidLoad(({ model }) => {
|
||||
manager.onDidResolve(({ model }) => {
|
||||
if (model.resource.toString() === resource1.toString()) {
|
||||
loadedCounter++;
|
||||
resolvedCounter++;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -228,13 +228,13 @@ suite('Files - TextFileEditorModelManager', () => {
|
|||
});
|
||||
|
||||
const model1 = await manager.resolve(resource1, { encoding: 'utf8' });
|
||||
assert.strictEqual(loadedCounter, 1);
|
||||
assert.strictEqual(resolvedCounter, 1);
|
||||
|
||||
accessor.fileService.fireFileChanges(new FileChangesEvent([{ resource: resource1, type: FileChangeType.DELETED }], false));
|
||||
accessor.fileService.fireFileChanges(new FileChangesEvent([{ resource: resource1, type: FileChangeType.ADDED }], false));
|
||||
|
||||
const model2 = await manager.resolve(resource2, { encoding: 'utf8' });
|
||||
assert.strictEqual(loadedCounter, 2);
|
||||
assert.strictEqual(resolvedCounter, 2);
|
||||
|
||||
model1.updateTextEditorModel(createTextBufferFactory('changed'));
|
||||
model1.updatePreferredEncoding('utf16');
|
||||
|
|
|
@ -31,7 +31,7 @@ suite('Files - TextFileService', () => {
|
|||
model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined);
|
||||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(model.resource, model);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
|
||||
assert.ok(!accessor.textFileService.isDirty(model.resource));
|
||||
model.textEditorModel!.setValue('foo');
|
||||
|
@ -41,7 +41,7 @@ suite('Files - TextFileService', () => {
|
|||
const untitled = await accessor.textFileService.untitled.resolve();
|
||||
|
||||
assert.ok(!accessor.textFileService.isDirty(untitled.resource));
|
||||
untitled.textEditorModel.setValue('changed');
|
||||
untitled.textEditorModel?.setValue('changed');
|
||||
|
||||
assert.ok(accessor.textFileService.isDirty(untitled.resource));
|
||||
|
||||
|
@ -53,7 +53,7 @@ suite('Files - TextFileService', () => {
|
|||
model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined);
|
||||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(model.resource, model);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.textEditorModel!.setValue('foo');
|
||||
assert.ok(accessor.textFileService.isDirty(model.resource));
|
||||
|
||||
|
@ -66,7 +66,7 @@ suite('Files - TextFileService', () => {
|
|||
model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined);
|
||||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(model.resource, model);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.textEditorModel!.setValue('foo');
|
||||
assert.ok(accessor.textFileService.isDirty(model.resource));
|
||||
|
||||
|
@ -80,7 +80,7 @@ suite('Files - TextFileService', () => {
|
|||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(model.resource, model);
|
||||
accessor.fileDialogService.setPickFileToSave(model.resource);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model.textEditorModel!.setValue('foo');
|
||||
assert.ok(accessor.textFileService.isDirty(model.resource));
|
||||
|
||||
|
@ -94,7 +94,7 @@ suite('Files - TextFileService', () => {
|
|||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(model.resource, model);
|
||||
accessor.fileDialogService.setPickFileToSave(model.resource);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model!.textEditorModel!.setValue('foo');
|
||||
assert.ok(accessor.textFileService.isDirty(model.resource));
|
||||
|
||||
|
@ -106,7 +106,7 @@ suite('Files - TextFileService', () => {
|
|||
model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined);
|
||||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(model.resource, model);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model!.textEditorModel!.setValue('foo');
|
||||
assert.ok(accessor.textFileService.isDirty(model.resource));
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ suite('Files - NativeTextFileService', function () {
|
|||
test('shutdown joins on pending saves', async function () {
|
||||
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
|
||||
let pendingSaveAwaited = false;
|
||||
model.save().then(() => pendingSaveAwaited = true);
|
||||
|
|
|
@ -9,7 +9,7 @@ import { ITextModel } from 'vs/editor/common/model';
|
|||
import { IDisposable, toDisposable, IReference, ReferenceCollection, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel';
|
||||
import { ITextFileService, TextFileLoadReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextFileService, TextFileResolveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { ITextModelService, ITextModelContentProvider, ITextEditorModel, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||
|
@ -60,7 +60,7 @@ class ResourceModelCollection extends ReferenceCollection<Promise<ITextEditorMod
|
|||
|
||||
// File or remote file: go through text file service
|
||||
if (this.fileService.canHandleResource(resource)) {
|
||||
return this.textFileService.files.resolve(resource, { reason: TextFileLoadReason.REFERENCE });
|
||||
return this.textFileService.files.resolve(resource, { reason: TextFileResolveReason.REFERENCE });
|
||||
}
|
||||
|
||||
// Virtual documents
|
||||
|
|
|
@ -73,7 +73,7 @@ suite('Workbench - TextModelResolverService', () => {
|
|||
const textModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_resolver.txt'), 'utf8', undefined);
|
||||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(textModel.resource, textModel);
|
||||
|
||||
await textModel.load();
|
||||
await textModel.resolve();
|
||||
|
||||
const ref = await accessor.textModelResolverService.createModelReference(textModel.resource);
|
||||
|
||||
|
@ -97,14 +97,14 @@ suite('Workbench - TextModelResolverService', () => {
|
|||
const textModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_resolver.txt'), 'utf8', undefined);
|
||||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(textModel.resource, textModel);
|
||||
|
||||
const loadedModel = await textModel.load();
|
||||
await textModel.resolve();
|
||||
|
||||
loadedModel.updateTextEditorModel(createTextBufferFactory('make dirty'));
|
||||
textModel.updateTextEditorModel(createTextBufferFactory('make dirty'));
|
||||
|
||||
const ref = await accessor.textModelResolverService.createModelReference(textModel.resource);
|
||||
|
||||
let disposed = false;
|
||||
Event.once(loadedModel.onWillDispose)(() => {
|
||||
Event.once(textModel.onWillDispose)(() => {
|
||||
disposed = true;
|
||||
});
|
||||
|
||||
|
@ -112,7 +112,7 @@ suite('Workbench - TextModelResolverService', () => {
|
|||
await timeout(0);
|
||||
assert.strictEqual(disposed, false); // not disposed because model still dirty
|
||||
|
||||
loadedModel.revert();
|
||||
textModel.revert();
|
||||
|
||||
await timeout(0);
|
||||
assert.strictEqual(disposed, true); // now disposed because model got reverted
|
||||
|
@ -122,14 +122,14 @@ suite('Workbench - TextModelResolverService', () => {
|
|||
const textModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_resolver.txt'), 'utf8', undefined);
|
||||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(textModel.resource, textModel);
|
||||
|
||||
const loadedModel = await textModel.load();
|
||||
await textModel.resolve();
|
||||
|
||||
loadedModel.updateTextEditorModel(createTextBufferFactory('make dirty'));
|
||||
textModel.updateTextEditorModel(createTextBufferFactory('make dirty'));
|
||||
|
||||
const ref1 = await accessor.textModelResolverService.createModelReference(textModel.resource);
|
||||
|
||||
let disposed = false;
|
||||
Event.once(loadedModel.onWillDispose)(() => {
|
||||
Event.once(textModel.onWillDispose)(() => {
|
||||
disposed = true;
|
||||
});
|
||||
|
||||
|
@ -139,7 +139,7 @@ suite('Workbench - TextModelResolverService', () => {
|
|||
|
||||
const ref2 = await accessor.textModelResolverService.createModelReference(textModel.resource);
|
||||
|
||||
loadedModel.revert();
|
||||
textModel.revert();
|
||||
|
||||
await timeout(0);
|
||||
assert.strictEqual(disposed, false); // not disposed because we got another ref meanwhile
|
||||
|
|
|
@ -8,7 +8,6 @@ import { AbstractTextResourceEditorInput } from 'vs/workbench/common/editor/text
|
|||
import { IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
|
@ -22,7 +21,7 @@ export class UntitledTextEditorInput extends AbstractTextResourceEditorInput imp
|
|||
|
||||
static readonly ID: string = 'workbench.editors.untitledEditorInput';
|
||||
|
||||
private modelResolve: Promise<IUntitledTextEditorModel & IResolvedTextEditorModel> | undefined = undefined;
|
||||
private modelResolve: Promise<void> | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
public readonly model: IUntitledTextEditorModel,
|
||||
|
@ -110,16 +109,14 @@ export class UntitledTextEditorInput extends AbstractTextResourceEditorInput imp
|
|||
return this.model.getMode();
|
||||
}
|
||||
|
||||
resolve(): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel> {
|
||||
|
||||
// Join a model resolve if we have had one before
|
||||
if (this.modelResolve) {
|
||||
return this.modelResolve;
|
||||
async resolve(): Promise<IUntitledTextEditorModel> {
|
||||
if (!this.modelResolve) {
|
||||
this.modelResolve = this.model.resolve();
|
||||
}
|
||||
|
||||
this.modelResolve = this.model.load();
|
||||
await this.modelResolve;
|
||||
|
||||
return this.modelResolve;
|
||||
return this.model;
|
||||
}
|
||||
|
||||
matches(otherInput: unknown): boolean {
|
||||
|
|
|
@ -13,7 +13,7 @@ import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
|||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { ITextBufferFactory, ITextModel } from 'vs/editor/common/model';
|
||||
import { createTextBufferFactory } from 'vs/editor/common/model/textModel';
|
||||
import { IResolvedTextEditorModel, ITextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { ITextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { IWorkingCopyService, IWorkingCopy, WorkingCopyCapabilities, IWorkingCopyBackup } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||
|
@ -57,15 +57,15 @@ export interface IUntitledTextEditorModel extends ITextEditorModel, IModeSupport
|
|||
setEncoding(encoding: string): void;
|
||||
|
||||
/**
|
||||
* Load the untitled model.
|
||||
* Resolves the untitled model.
|
||||
*/
|
||||
load(): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel>;
|
||||
resolve(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Updates the value of the untitled model optionally allowing to ignore dirty.
|
||||
* The model must be resolved for this method to work.
|
||||
*/
|
||||
setValue(this: IResolvedTextEditorModel, value: string, ignoreDirty?: boolean): void;
|
||||
setValue(value: string, ignoreDirty?: boolean): void;
|
||||
}
|
||||
|
||||
export class UntitledTextEditorModel extends BaseTextEditorModel implements IUntitledTextEditorModel {
|
||||
|
@ -272,7 +272,7 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
|
|||
return { content: withNullAsUndefined(this.createSnapshot()) };
|
||||
}
|
||||
|
||||
async load(): Promise<UntitledTextEditorModel & IResolvedTextEditorModel> {
|
||||
async resolve(): Promise<void> {
|
||||
|
||||
// Check for backups
|
||||
const backup = await this.backupFileService.resolve(this.resource);
|
||||
|
@ -321,8 +321,6 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
|
|||
this._onDidChangeContent.fire();
|
||||
}
|
||||
}
|
||||
|
||||
return this as UntitledTextEditorModel & IResolvedTextEditorModel;
|
||||
}
|
||||
|
||||
private onModelContentChanged(textEditorModel: ITextModel, e: IModelContentChangedEvent): void {
|
||||
|
|
|
@ -13,7 +13,6 @@ import { ResourceMap } from 'vs/base/common/map';
|
|||
import { Schemas } from 'vs/base/common/network';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
|
||||
export const IUntitledTextEditorService = createDecorator<IUntitledTextEditorService>('untitledTextEditorService');
|
||||
|
||||
|
@ -110,9 +109,9 @@ export interface IUntitledTextEditorModelManager {
|
|||
* property is provided and the untitled editor exists, it will return that existing
|
||||
* instance instead of creating a new one.
|
||||
*/
|
||||
resolve(options?: INewUntitledTextEditorOptions): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel>;
|
||||
resolve(options?: INewUntitledTextEditorWithAssociatedResourceOptions): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel>;
|
||||
resolve(options?: IExistingUntitledTextEditorOptions): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel>;
|
||||
resolve(options?: INewUntitledTextEditorOptions): Promise<IUntitledTextEditorModel>;
|
||||
resolve(options?: INewUntitledTextEditorWithAssociatedResourceOptions): Promise<IUntitledTextEditorModel>;
|
||||
resolve(options?: IExistingUntitledTextEditorOptions): Promise<IUntitledTextEditorModel>;
|
||||
}
|
||||
|
||||
export interface IUntitledTextEditorService extends IUntitledTextEditorModelManager {
|
||||
|
@ -153,8 +152,11 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
|
|||
return this.get(resource)?.textEditorModel?.getValue();
|
||||
}
|
||||
|
||||
resolve(options?: IInternalUntitledTextEditorOptions): Promise<UntitledTextEditorModel & IResolvedTextEditorModel> {
|
||||
return this.doCreateOrGet(options).load();
|
||||
async resolve(options?: IInternalUntitledTextEditorOptions): Promise<UntitledTextEditorModel> {
|
||||
const model = this.doCreateOrGet(options);
|
||||
await model.resolve();
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
create(options?: IInternalUntitledTextEditorOptions): UntitledTextEditorModel {
|
||||
|
|
|
@ -62,7 +62,7 @@ suite('Untitled text editors', () => {
|
|||
|
||||
const resourcePromise = awaitDidChangeDirty(accessor.untitledTextEditorService);
|
||||
|
||||
model.textEditorModel.setValue('foo bar');
|
||||
model.textEditorModel?.setValue('foo bar');
|
||||
|
||||
const resource = await resourcePromise;
|
||||
|
||||
|
@ -147,10 +147,10 @@ suite('Untitled text editors', () => {
|
|||
|
||||
// dirty
|
||||
const model = await input.resolve();
|
||||
model.textEditorModel.setValue('foo bar');
|
||||
model.textEditorModel?.setValue('foo bar');
|
||||
assert.ok(model.isDirty());
|
||||
assert.ok(workingCopyService.isDirty(model.resource));
|
||||
model.textEditorModel.setValue('');
|
||||
model.textEditorModel?.setValue('');
|
||||
assert.ok(!model.isDirty());
|
||||
assert.ok(!workingCopyService.isDirty(model.resource));
|
||||
input.dispose();
|
||||
|
@ -196,9 +196,9 @@ suite('Untitled text editors', () => {
|
|||
|
||||
// dirty
|
||||
const model = await input.resolve();
|
||||
model.textEditorModel.setValue('foo bar');
|
||||
model.textEditorModel?.setValue('foo bar');
|
||||
assert.ok(model.isDirty());
|
||||
model.textEditorModel.setValue('');
|
||||
model.textEditorModel?.setValue('');
|
||||
assert.ok(model.isDirty());
|
||||
input.dispose();
|
||||
model.dispose();
|
||||
|
@ -345,7 +345,7 @@ suite('Untitled text editors', () => {
|
|||
|
||||
// label
|
||||
const model = await input.resolve();
|
||||
model.textEditorModel.setValue('Foo Bar');
|
||||
model.textEditorModel?.setValue('Foo Bar');
|
||||
assert.strictEqual(counter, 1);
|
||||
input.dispose();
|
||||
model.dispose();
|
||||
|
@ -391,16 +391,16 @@ suite('Untitled text editors', () => {
|
|||
const model = await input.resolve();
|
||||
model.onDidChangeContent(() => counter++);
|
||||
|
||||
model.textEditorModel.setValue('foo');
|
||||
model.textEditorModel?.setValue('foo');
|
||||
|
||||
assert.strictEqual(counter, 1, 'Dirty model should trigger event');
|
||||
model.textEditorModel.setValue('bar');
|
||||
model.textEditorModel?.setValue('bar');
|
||||
|
||||
assert.strictEqual(counter, 2, 'Content change when dirty should trigger event');
|
||||
model.textEditorModel.setValue('');
|
||||
model.textEditorModel?.setValue('');
|
||||
|
||||
assert.strictEqual(counter, 3, 'Manual revert should trigger event');
|
||||
model.textEditorModel.setValue('foo');
|
||||
model.textEditorModel?.setValue('foo');
|
||||
|
||||
assert.strictEqual(counter, 4, 'Dirty model should trigger event');
|
||||
|
||||
|
@ -417,7 +417,7 @@ suite('Untitled text editors', () => {
|
|||
const model = await input.resolve();
|
||||
model.onDidRevert(() => counter++);
|
||||
|
||||
model.textEditorModel.setValue('foo');
|
||||
model.textEditorModel?.setValue('foo');
|
||||
|
||||
await model.revert();
|
||||
|
||||
|
@ -434,43 +434,43 @@ suite('Untitled text editors', () => {
|
|||
let model = await input.resolve();
|
||||
model.onDidChangeName(() => counter++);
|
||||
|
||||
model.textEditorModel.setValue('foo');
|
||||
model.textEditorModel?.setValue('foo');
|
||||
assert.strictEqual(input.getName(), 'foo');
|
||||
assert.strictEqual(model.name, 'foo');
|
||||
|
||||
assert.strictEqual(counter, 1);
|
||||
model.textEditorModel.setValue('bar');
|
||||
model.textEditorModel?.setValue('bar');
|
||||
assert.strictEqual(input.getName(), 'bar');
|
||||
assert.strictEqual(model.name, 'bar');
|
||||
|
||||
assert.strictEqual(counter, 2);
|
||||
model.textEditorModel.setValue('');
|
||||
model.textEditorModel?.setValue('');
|
||||
assert.strictEqual(input.getName(), 'Untitled-1');
|
||||
assert.strictEqual(model.name, 'Untitled-1');
|
||||
|
||||
model.textEditorModel.setValue(' ');
|
||||
model.textEditorModel?.setValue(' ');
|
||||
assert.strictEqual(input.getName(), 'Untitled-1');
|
||||
assert.strictEqual(model.name, 'Untitled-1');
|
||||
|
||||
model.textEditorModel.setValue('([]}'); // require actual words
|
||||
model.textEditorModel?.setValue('([]}'); // require actual words
|
||||
assert.strictEqual(input.getName(), 'Untitled-1');
|
||||
assert.strictEqual(model.name, 'Untitled-1');
|
||||
|
||||
model.textEditorModel.setValue('([]}hello '); // require actual words
|
||||
model.textEditorModel?.setValue('([]}hello '); // require actual words
|
||||
assert.strictEqual(input.getName(), '([]}hello');
|
||||
assert.strictEqual(model.name, '([]}hello');
|
||||
|
||||
model.textEditorModel.setValue('12345678901234567890123456789012345678901234567890'); // trimmed at 40chars max
|
||||
model.textEditorModel?.setValue('12345678901234567890123456789012345678901234567890'); // trimmed at 40chars max
|
||||
assert.strictEqual(input.getName(), '1234567890123456789012345678901234567890');
|
||||
assert.strictEqual(model.name, '1234567890123456789012345678901234567890');
|
||||
|
||||
model.textEditorModel.setValue('123456789012345678901234567890123456789🌞'); // do not break grapehems (#111235)
|
||||
model.textEditorModel?.setValue('123456789012345678901234567890123456789🌞'); // do not break grapehems (#111235)
|
||||
assert.strictEqual(input.getName(), '123456789012345678901234567890123456789');
|
||||
assert.strictEqual(model.name, '123456789012345678901234567890123456789');
|
||||
|
||||
assert.strictEqual(counter, 6);
|
||||
|
||||
model.textEditorModel.setValue('Hello\nWorld');
|
||||
model.textEditorModel?.setValue('Hello\nWorld');
|
||||
assert.strictEqual(counter, 7);
|
||||
|
||||
function createSingleEditOp(text: string, positionLineNumber: number, positionColumn: number, selectionLineNumber: number = positionLineNumber, selectionColumn: number = positionColumn): IIdentifiedSingleEditOperation {
|
||||
|
@ -489,7 +489,7 @@ suite('Untitled text editors', () => {
|
|||
};
|
||||
}
|
||||
|
||||
model.textEditorModel.applyEdits([createSingleEditOp('hello', 2, 2)]);
|
||||
model.textEditorModel?.applyEdits([createSingleEditOp('hello', 2, 2)]);
|
||||
assert.strictEqual(counter, 7); // change was not on first line
|
||||
|
||||
input.dispose();
|
||||
|
@ -513,10 +513,10 @@ suite('Untitled text editors', () => {
|
|||
const model = await input.resolve();
|
||||
model.onDidChangeDirty(() => counter++);
|
||||
|
||||
model.textEditorModel.setValue('foo');
|
||||
model.textEditorModel?.setValue('foo');
|
||||
|
||||
assert.strictEqual(counter, 1, 'Dirty model should trigger event');
|
||||
model.textEditorModel.setValue('bar');
|
||||
model.textEditorModel?.setValue('bar');
|
||||
|
||||
assert.strictEqual(counter, 1, 'Another change does not fire event');
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ suite('WorkingCopyFileService', () => {
|
|||
let dirty = accessor.workingCopyFileService.getDirty(model1.resource);
|
||||
assert.strictEqual(dirty.length, 0);
|
||||
|
||||
await model1.load();
|
||||
await model1.resolve();
|
||||
model1.textEditorModel!.setValue('foo');
|
||||
|
||||
dirty = accessor.workingCopyFileService.getDirty(model1.resource);
|
||||
|
@ -157,7 +157,7 @@ suite('WorkingCopyFileService', () => {
|
|||
assert.strictEqual(dirty.length, 1);
|
||||
assert.strictEqual(dirty[0], model1);
|
||||
|
||||
await model2.load();
|
||||
await model2.resolve();
|
||||
model2.textEditorModel!.setValue('bar');
|
||||
|
||||
dirty = accessor.workingCopyFileService.getDirty(toResource.call(this, '/path'));
|
||||
|
@ -170,7 +170,7 @@ suite('WorkingCopyFileService', () => {
|
|||
test('registerWorkingCopyProvider', async function () {
|
||||
const model1 = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file-1.txt'), 'utf8', undefined);
|
||||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(model1.resource, model1);
|
||||
await model1.load();
|
||||
await model1.resolve();
|
||||
model1.textEditorModel!.setValue('foo');
|
||||
|
||||
const testWorkingCopy = new TestWorkingCopy(toResource.call(this, '/path/file-2.txt'), true);
|
||||
|
@ -327,11 +327,11 @@ suite('WorkingCopyFileService', () => {
|
|||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(sourceModel.resource, sourceModel);
|
||||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(targetModel.resource, targetModel);
|
||||
|
||||
await sourceModel.load();
|
||||
await sourceModel.resolve();
|
||||
sourceModel.textEditorModel!.setValue('foo' + i);
|
||||
assert.ok(accessor.textFileService.isDirty(sourceModel.resource));
|
||||
if (targetDirty) {
|
||||
await targetModel.load();
|
||||
await targetModel.resolve();
|
||||
targetModel.textEditorModel!.setValue('bar' + i);
|
||||
assert.ok(accessor.textFileService.isDirty(targetModel.resource));
|
||||
}
|
||||
|
@ -420,7 +420,7 @@ suite('WorkingCopyFileService', () => {
|
|||
const model = instantiationService.createInstance(TextFileEditorModel, resource, 'utf8', undefined);
|
||||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(model.resource, model);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model!.textEditorModel!.setValue('foo');
|
||||
assert.ok(accessor.workingCopyService.isDirty(model.resource));
|
||||
return model;
|
||||
|
@ -480,7 +480,7 @@ suite('WorkingCopyFileService', () => {
|
|||
const model = instantiationService.createInstance(TextFileEditorModel, resource, 'utf8', undefined);
|
||||
(<TestTextFileEditorModelManager>accessor.textFileService.files).add(model.resource, model);
|
||||
|
||||
await model.load();
|
||||
await model.resolve();
|
||||
model!.textEditorModel!.setValue('foo');
|
||||
assert.ok(accessor.workingCopyService.isDirty(model.resource));
|
||||
|
||||
|
|
|
@ -72,23 +72,21 @@ suite('Workbench editor model', () => {
|
|||
counter++;
|
||||
});
|
||||
|
||||
const resolvedModel = await model.load();
|
||||
assert(resolvedModel === model);
|
||||
assert.strictEqual(resolvedModel.isDisposed(), false);
|
||||
await model.resolve();
|
||||
assert.strictEqual(model.isDisposed(), false);
|
||||
assert.strictEqual(model.isResolved(), true);
|
||||
model.dispose();
|
||||
assert.strictEqual(counter, 1);
|
||||
assert.strictEqual(resolvedModel.isDisposed(), true);
|
||||
assert.strictEqual(model.isDisposed(), true);
|
||||
});
|
||||
|
||||
test('BaseTextEditorModel', async () => {
|
||||
let modelService = stubModelService(instantiationService);
|
||||
|
||||
const model = new MyTextEditorModel(modelService, modeService);
|
||||
const resolvedModel = await model.load() as MyTextEditorModel;
|
||||
await model.resolve();
|
||||
|
||||
assert(resolvedModel === model);
|
||||
resolvedModel.createTextEditorModel(createTextBufferFactory('foo'), null!, 'text/plain');
|
||||
model.createTextEditorModel(createTextBufferFactory('foo'), null!, 'text/plain');
|
||||
assert.strictEqual(model.isResolved(), true);
|
||||
model.dispose();
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue