Skip to content

Commit 305fbc1

Browse files
author
Benjamin Pasero
committed
editors - untitled with associated resource do not emit dirty change properly
1 parent a6d692e commit 305fbc1

3 files changed

Lines changed: 49 additions & 20 deletions

File tree

src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -280,16 +280,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
280280
const newModel = model = this.instantiationService.createInstance(TextFileEditorModel, resource, options ? options.encoding : undefined, options ? options.mode : undefined);
281281
modelPromise = model.load(options);
282282

283-
// Install model listeners
284-
const modelListeners = new DisposableStore();
285-
modelListeners.add(model.onDidLoad(reason => this._onDidLoad.fire({ model: newModel, reason })));
286-
modelListeners.add(model.onDidChangeDirty(() => this._onDidChangeDirty.fire(newModel)));
287-
modelListeners.add(model.onDidSaveError(() => this._onDidSaveError.fire(newModel)));
288-
modelListeners.add(model.onDidSave(reason => this._onDidSave.fire({ model: newModel, reason })));
289-
modelListeners.add(model.onDidRevert(() => this._onDidRevert.fire(newModel)));
290-
modelListeners.add(model.onDidChangeEncoding(() => this._onDidChangeEncoding.fire(newModel)));
291-
292-
this.mapResourceToModelListeners.set(resource, modelListeners);
283+
this.registerModel(newModel);
293284
}
294285

295286
// Store pending loads to avoid race conditions
@@ -298,9 +289,15 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
298289
// Make known to manager (if not already known)
299290
this.add(resource, model);
300291

301-
// Signal as event if we created the model
292+
// Emit some events if we created the model
302293
if (didCreateModel) {
303294
this._onDidCreate.fire(model);
295+
296+
// If the model is dirty right from the beginning,
297+
// make sure to emit this as an event
298+
if (model.isDirty()) {
299+
this._onDidChangeDirty.fire(model);
300+
}
304301
}
305302

306303
try {
@@ -335,6 +332,21 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
335332
}
336333
}
337334

335+
private registerModel(model: TextFileEditorModel): void {
336+
337+
// Install model listeners
338+
const modelListeners = new DisposableStore();
339+
modelListeners.add(model.onDidLoad(reason => this._onDidLoad.fire({ model, reason })));
340+
modelListeners.add(model.onDidChangeDirty(() => this._onDidChangeDirty.fire(model)));
341+
modelListeners.add(model.onDidSaveError(() => this._onDidSaveError.fire(model)));
342+
modelListeners.add(model.onDidSave(reason => this._onDidSave.fire({ model: model, reason })));
343+
modelListeners.add(model.onDidRevert(() => this._onDidRevert.fire(model)));
344+
modelListeners.add(model.onDidChangeEncoding(() => this._onDidChangeEncoding.fire(model)));
345+
346+
// Keep for disposal
347+
this.mapResourceToModelListeners.set(model.resource, modelListeners);
348+
}
349+
338350
add(resource: URI, model: TextFileEditorModel): void {
339351
const knownModel = this.mapResourceToModel.get(resource);
340352
if (knownModel === model) {

src/vs/workbench/services/untitled/common/untitledTextEditorService.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,13 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
219219
}
220220

221221
private registerModel(model: UntitledTextEditorModel): void {
222-
const modelDisposables = new DisposableStore();
223-
modelDisposables.add(model.onDidChangeDirty(() => this._onDidChangeDirty.fire(model)));
224-
modelDisposables.add(model.onDidChangeName(() => this._onDidChangeLabel.fire(model)));
225-
modelDisposables.add(model.onDidChangeEncoding(() => this._onDidChangeEncoding.fire(model)));
226-
modelDisposables.add(model.onDispose(() => this._onDidDispose.fire(model)));
222+
223+
// Install model listeners
224+
const modelListeners = new DisposableStore();
225+
modelListeners.add(model.onDidChangeDirty(() => this._onDidChangeDirty.fire(model)));
226+
modelListeners.add(model.onDidChangeName(() => this._onDidChangeLabel.fire(model)));
227+
modelListeners.add(model.onDidChangeEncoding(() => this._onDidChangeEncoding.fire(model)));
228+
modelListeners.add(model.onDispose(() => this._onDidDispose.fire(model)));
227229

228230
// Remove from cache on dispose
229231
Event.once(model.onDispose)(() => {
@@ -232,11 +234,17 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
232234
this.mapResourceToModel.delete(model.resource);
233235

234236
// Listeners
235-
modelDisposables.dispose();
237+
modelListeners.dispose();
236238
});
237239

238240
// Add to cache
239241
this.mapResourceToModel.set(model.resource, model);
242+
243+
// If the model is dirty right from the beginning,
244+
// make sure to emit this as an event
245+
if (model.isDirty()) {
246+
this._onDidChangeDirty.fire(model);
247+
}
240248
}
241249
}
242250

src/vs/workbench/services/untitled/test/browser/untitledTextEditor.test.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRe
1414
import { IIdentifiedSingleEditOperation } from 'vs/editor/common/model';
1515
import { Range } from 'vs/editor/common/core/range';
1616
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
17+
import { IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
1718

1819
suite('Untitled text editors', () => {
1920

@@ -120,15 +121,23 @@ suite('Untitled text editors', () => {
120121
const service = accessor.untitledTextEditorService;
121122
const file = URI.file(join('C:\\', '/foo/file.txt'));
122123

123-
const untitled = instantiationService.createInstance(UntitledTextEditorInput, service.create({ associatedResource: file }));
124+
let onDidChangeDirtyModel: IUntitledTextEditorModel | undefined = undefined;
125+
const listener = service.onDidChangeDirty(model => {
126+
onDidChangeDirtyModel = model;
127+
});
128+
129+
const model = service.create({ associatedResource: file });
130+
const untitled = instantiationService.createInstance(UntitledTextEditorInput, model);
124131
assert.ok(untitled.isDirty());
132+
assert.equal(model, onDidChangeDirtyModel);
125133

126-
const model = await untitled.resolve();
134+
const resolvedModel = await untitled.resolve();
127135

128-
assert.ok(model.hasAssociatedFilePath);
136+
assert.ok(resolvedModel.hasAssociatedFilePath);
129137
assert.equal(untitled.isDirty(), true);
130138

131139
untitled.dispose();
140+
listener.dispose();
132141
});
133142

134143
test('no longer dirty when content gets empty (not with associated resource)', async () => {

0 commit comments

Comments
 (0)