untitledEditorModel.ts 6.4 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

J
Johannes Rieken 已提交
7 8 9 10
import { IDisposable } from 'vs/base/common/lifecycle';
import { TPromise } from 'vs/base/common/winjs.base';
import { EditorModel, IEncodingSupport } from 'vs/workbench/common/editor';
import { StringEditorModel } from 'vs/workbench/common/editor/stringEditorModel';
E
Erich Gamma 已提交
11
import URI from 'vs/base/common/uri';
J
Johannes Rieken 已提交
12 13
import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
import { EndOfLinePreference } from 'vs/editor/common/editorCommon';
14
import { IFileService, IFilesConfiguration } from 'vs/platform/files/common/files';
J
Johannes Rieken 已提交
15 16 17 18 19
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IMode } from 'vs/editor/common/modes';
import Event, { Emitter } from 'vs/base/common/event';
20
import { IBackupService, IBackupFileService } from 'vs/workbench/services/backup/common/backup';
E
Erich Gamma 已提交
21 22

export class UntitledEditorModel extends StringEditorModel implements IEncodingSupport {
A
Alex Dima 已提交
23
	private textModelChangeListener: IDisposable;
24
	private configurationChangeListener: IDisposable;
E
Erich Gamma 已提交
25 26

	private dirty: boolean;
27
	private _onDidChangeDirty: Emitter<void>;
28
	private _onDidChangeEncoding: Emitter<void>;
29

E
Erich Gamma 已提交
30 31 32
	private configuredEncoding: string;
	private preferredEncoding: string;

33 34
	private hasAssociatedFilePath: boolean;

D
Daniel Imms 已提交
35 36
	private backupPromises: TPromise<void>[];

E
Erich Gamma 已提交
37 38
	constructor(
		value: string,
39
		modeId: string,
E
Erich Gamma 已提交
40 41 42 43
		resource: URI,
		hasAssociatedFilePath: boolean,
		@IModeService modeService: IModeService,
		@IModelService modelService: IModelService,
D
Daniel Imms 已提交
44
		@IFileService private fileService: IFileService,
45 46 47
		@IConfigurationService private configurationService: IConfigurationService,
		@IBackupService private backupService: IBackupService,
		@IBackupFileService private backupFileService: IBackupFileService
E
Erich Gamma 已提交
48
	) {
49
		super(value, modeId, resource, modeService, modelService);
E
Erich Gamma 已提交
50

51
		this.hasAssociatedFilePath = hasAssociatedFilePath;
52
		this.dirty = hasAssociatedFilePath || value !== ''; // untitled associated to file path are dirty right away
E
Erich Gamma 已提交
53

54
		this._onDidChangeDirty = new Emitter<void>();
55
		this._onDidChangeEncoding = new Emitter<void>();
56

D
Daniel Imms 已提交
57
		this.backupPromises = [];
E
Erich Gamma 已提交
58

D
Daniel Imms 已提交
59
		this.registerListeners();
60 61
	}

62 63 64 65
	public get onDidChangeDirty(): Event<void> {
		return this._onDidChangeDirty.event;
	}

66 67 68 69
	public get onDidChangeEncoding(): Event<void> {
		return this._onDidChangeEncoding.event;
	}

70 71 72
	protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): TPromise<IMode> {
		if (!modeId || modeId === PLAINTEXT_MODE_ID) {
			return modeService.getOrCreateModeByFilenameOrFirstLine(this.resource.fsPath, firstLineText); // lookup mode via resource path if the provided modeId is unspecific
73 74
		}

75
		return super.getOrCreateMode(modeService, modeId, firstLineText);
76 77
	}

E
Erich Gamma 已提交
78 79 80
	private registerListeners(): void {

		// Config Changes
81
		this.configurationChangeListener = this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(e.config));
E
Erich Gamma 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
	}

	private onConfigurationChange(configuration: IFilesConfiguration): void {
		this.configuredEncoding = configuration && configuration.files && configuration.files.encoding;
	}

	public getValue(): string {
		if (this.textEditorModel) {
			return this.textEditorModel.getValue(EndOfLinePreference.TextDefined, true /* Preserve BOM */);
		}

		return null;
	}

	public getModeId(): string {
		if (this.textEditorModel) {
			return this.textEditorModel.getModeId();
		}

		return null;
	}

	public getEncoding(): string {
		return this.preferredEncoding || this.configuredEncoding;
	}

	public setEncoding(encoding: string): void {
109
		const oldEncoding = this.getEncoding();
E
Erich Gamma 已提交
110 111 112 113
		this.preferredEncoding = encoding;

		// Emit if it changed
		if (oldEncoding !== this.preferredEncoding) {
114
			this._onDidChangeEncoding.fire();
E
Erich Gamma 已提交
115 116 117 118 119 120 121
		}
	}

	public isDirty(): boolean {
		return this.dirty;
	}

D
Daniel Imms 已提交
122 123 124 125
	public getResource(): URI {
		return this.resource;
	}

126 127 128
	public revert(): void {
		this.dirty = false;

129
		this._onDidChangeDirty.fire();
130 131
	}

E
Erich Gamma 已提交
132 133
	public load(): TPromise<EditorModel> {
		return super.load().then((model) => {
134
			const configuration = this.configurationService.getConfiguration<IFilesConfiguration>();
E
Erich Gamma 已提交
135

136 137
			// Encoding
			this.configuredEncoding = configuration && configuration.files && configuration.files.encoding;
E
Erich Gamma 已提交
138

139
			// Listen to content changes
B
Benjamin Pasero 已提交
140
			this.textModelChangeListener = this.textEditorModel.onDidChangeContent(e => this.onModelContentChanged());
E
Erich Gamma 已提交
141

142 143 144
			// Emit initial dirty event if we are
			if (this.dirty) {
				setTimeout(() => {
145
					this._onDidChangeDirty.fire();
146 147
				}, 0 /* prevent race condition between creating model and emitting dirty event */);
			}
E
Erich Gamma 已提交
148

149
			return model;
E
Erich Gamma 已提交
150 151 152
		});
	}

B
Benjamin Pasero 已提交
153
	private onModelContentChanged(): void {
154 155

		// mark the untitled editor as non-dirty once its content becomes empty and we do
B
Benjamin Pasero 已提交
156 157 158 159 160 161
		// not have an associated path set. we never want dirty indicator in that case.
		if (!this.hasAssociatedFilePath && this.textEditorModel.getLineCount() === 1 && this.textEditorModel.getLineContent(1) === '') {
			if (this.dirty) {
				this.dirty = false;
				this._onDidChangeDirty.fire();
			}
E
Erich Gamma 已提交
162
		}
163

B
Benjamin Pasero 已提交
164 165 166
		// turn dirty if we were not
		else if (!this.dirty) {
			this.dirty = true;
167
			this._onDidChangeDirty.fire();
D
Daniel Imms 已提交
168

169
		}
170

171 172
		// TODO: Move this to BackupModelService
		if (this.backupService.isHotExitEnabled) {
D
Daniel Imms 已提交
173
			if (this.dirty) {
174
				this.backupService.doBackup(this.resource, this.getValue());
D
Daniel Imms 已提交
175
			} else {
176
				this.backupFileService.discardAndDeregisterResource(this.resource);
D
Daniel Imms 已提交
177 178
			}
		}
E
Erich Gamma 已提交
179 180 181 182 183 184
	}

	public dispose(): void {
		super.dispose();

		if (this.textModelChangeListener) {
A
Alex Dima 已提交
185
			this.textModelChangeListener.dispose();
E
Erich Gamma 已提交
186 187 188
			this.textModelChangeListener = null;
		}

189 190 191
		if (this.configurationChangeListener) {
			this.configurationChangeListener.dispose();
			this.configurationChangeListener = null;
E
Erich Gamma 已提交
192
		}
193 194 195

		this._onDidChangeDirty.dispose();
		this._onDidChangeEncoding.dispose();
D
Daniel Imms 已提交
196 197 198

		this.cancelBackupPromises();

199 200
		// TODO: Can this be moved to BackupModelService?
		this.backupFileService.discardAndDeregisterResource(this.resource);
D
Daniel Imms 已提交
201 202 203 204 205 206
	}

	private cancelBackupPromises(): void {
		while (this.backupPromises.length) {
			this.backupPromises.pop().cancel();
		}
E
Erich Gamma 已提交
207 208
	}
}