textfiles.ts 9.4 KB
Newer Older
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
import { TPromise } from 'vs/base/common/winjs.base';
8
import URI from 'vs/base/common/uri';
M
Matt Bierner 已提交
9
import { Event } from 'vs/base/common/event';
J
Johannes Rieken 已提交
10
import { IDisposable } from 'vs/base/common/lifecycle';
11
import { IEncodingSupport, ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor';
12
import { IBaseStat, IResolveContentOptions, ITextSnapshot } from 'vs/platform/files/common/files';
J
Johannes Rieken 已提交
13
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
J
Joao Moreno 已提交
14
import { ITextEditorModel } from 'vs/editor/common/services/resolverService';
15
import { ITextBufferFactory } from 'vs/editor/common/model';
I
isidor 已提交
16
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
17 18 19 20 21 22 23 24 25

/**
 * The save error handler can be installed on the text text file editor model to install code that executes when save errors occur.
 */
export interface ISaveErrorHandler {

	/**
	 * Called whenever a save fails.
	 */
B
Benjamin Pasero 已提交
26
	onSaveError(error: Error, model: ITextFileEditorModel): void;
27 28 29 30 31 32 33
}

export interface ISaveParticipant {

	/**
	 * Participate in a save of a model. Allows to change the model before it is being saved to disk.
	 */
B
Benjamin Pasero 已提交
34
	participate(model: ITextFileEditorModel, env: { reason: SaveReason }): void;
35 36 37 38 39 40 41 42 43
}

/**
 * States the text text file editor model can be in.
 */
export enum ModelState {
	SAVED,
	DIRTY,
	PENDING_SAVE,
44 45 46 47 48

	/**
	 * A model is in conflict mode when changes cannot be saved because the
	 * underlying file has changed. Models in conflict mode are always dirty.
	 */
49
	CONFLICT,
50 51 52 53 54 55 56 57 58 59

	/**
	 * A model is in orphan state when the underlying file has been deleted.
	 */
	ORPHAN,

	/**
	 * Any error that happens during a save that is not causing the CONFLICT state.
	 * Models in error mode are always diry.
	 */
60 61 62 63 64 65 66 67 68
	ERROR
}

export enum StateChange {
	DIRTY,
	SAVING,
	SAVE_ERROR,
	SAVED,
	REVERTED,
69
	ENCODING,
70 71
	CONTENT_CHANGE,
	ORPHANED_CHANGE
72 73 74 75 76 77 78 79 80 81 82
}

export class TextFileModelChangeEvent {
	private _resource: URI;
	private _kind: StateChange;

	constructor(model: ITextFileEditorModel, kind: StateChange) {
		this._resource = model.getResource();
		this._kind = kind;
	}

B
Benjamin Pasero 已提交
83
	get resource(): URI {
84 85 86
		return this._resource;
	}

B
Benjamin Pasero 已提交
87
	get kind(): StateChange {
88 89 90 91 92
		return this._kind;
	}
}

export const TEXT_FILE_SERVICE_ID = 'textFileService';
I
isidor 已提交
93
export const AutoSaveContext = new RawContextKey<string>('config.files.autoSave', undefined);
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132

export interface ITextFileOperationResult {
	results: IResult[];
}

export interface IResult {
	source: URI;
	target?: URI;
	success?: boolean;
}

export interface IAutoSaveConfiguration {
	autoSaveDelay: number;
	autoSaveFocusChange: boolean;
	autoSaveApplicationChange: boolean;
}

export enum AutoSaveMode {
	OFF,
	AFTER_SHORT_DELAY,
	AFTER_LONG_DELAY,
	ON_FOCUS_CHANGE,
	ON_WINDOW_CHANGE
}

export enum SaveReason {
	EXPLICIT = 1,
	AUTO = 2,
	FOCUS_CHANGE = 3,
	WINDOW_CHANGE = 4
}

export const ITextFileService = createDecorator<ITextFileService>(TEXT_FILE_SERVICE_ID);

export interface IRawTextContent extends IBaseStat {

	/**
	 * The line grouped content of a text file.
	 */
133
	value: ITextBufferFactory;
134 135 136 137 138 139 140

	/**
	 * The encoding of the content if known.
	 */
	encoding: string;
}

141
export interface IModelLoadOrCreateOptions {
142 143 144 145 146


	/**
	 * The encoding to use when resolving the model text content.
	 */
147
	encoding?: string;
148 149

	/**
150 151 152 153 154 155
	 * If the model was already loaded before, allows to trigger
	 * a reload of it to fetch the latest contents:
	 * - async: loadOrCreate() will return immediately and trigger
	 * a reload that will run in the background.
	 * - sync: loadOrCreate() will only return resolved when the
	 * model has finished reloading.
156
	 */
157 158 159
	reload?: {
		async: boolean
	};
160 161 162 163 164

	/**
	 * Allow to load a model even if we think it is a binary file.
	 */
	allowBinary?: boolean;
165 166
}

167 168
export interface ITextFileEditorModelManager {

169
	onModelDisposed: Event<URI>;
170
	onModelContentChanged: Event<TextFileModelChangeEvent>;
171 172
	onModelEncodingChanged: Event<TextFileModelChangeEvent>;

173 174 175 176
	onModelDirty: Event<TextFileModelChangeEvent>;
	onModelSaveError: Event<TextFileModelChangeEvent>;
	onModelSaved: Event<TextFileModelChangeEvent>;
	onModelReverted: Event<TextFileModelChangeEvent>;
177
	onModelOrphanedChanged: Event<TextFileModelChangeEvent>;
178 179 180 181 182

	onModelsDirty: Event<TextFileModelChangeEvent[]>;
	onModelsSaveError: Event<TextFileModelChangeEvent[]>;
	onModelsSaved: Event<TextFileModelChangeEvent[]>;
	onModelsReverted: Event<TextFileModelChangeEvent[]>;
183 184 185 186 187

	get(resource: URI): ITextFileEditorModel;

	getAll(resource?: URI): ITextFileEditorModel[];

B
Benjamin Pasero 已提交
188
	loadOrCreate(resource: URI, options?: IModelLoadOrCreateOptions): TPromise<ITextFileEditorModel>;
189 190

	disposeModel(model: ITextFileEditorModel): void;
191 192
}

193
export interface ISaveOptions {
194
	force?: boolean;
195 196 197
	reason?: SaveReason;
	overwriteReadonly?: boolean;
	overwriteEncoding?: boolean;
198
	skipSaveParticipants?: boolean;
199
	writeElevated?: boolean;
200 201
}

202 203 204 205 206 207 208 209 210 211 212 213 214
export interface ILoadOptions {

	/**
	 * Go to disk bypassing any cache of the model if any.
	 */
	forceReadFromDisk?: boolean;

	/**
	 * Allow to load a model even if we think it is a binary file.
	 */
	allowBinary?: boolean;
}

215 216
export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport {

217
	onDidContentChange: Event<StateChange>;
218 219
	onDidStateChange: Event<StateChange>;

220 221
	getVersionId(): number;

222 223
	getResource(): URI;

224
	hasState(state: ModelState): boolean;
225

226 227
	getETag(): string;

228 229
	updatePreferredEncoding(encoding: string): void;

230
	save(options?: ISaveOptions): TPromise<void>;
231

232
	load(options?: ILoadOptions): TPromise<ITextFileEditorModel>;
B
Benjamin Pasero 已提交
233

234
	revert(soft?: boolean): TPromise<void>;
235

236 237
	createSnapshot(): ITextSnapshot;

238 239
	isDirty(): boolean;

240 241
	isResolved(): boolean;

242 243
	isReadonly(): boolean;

244 245 246
	isDisposed(): boolean;
}

247 248 249 250 251 252 253

export interface IWillMoveEvent {
	oldResource: URI;
	newResource: URI;
	waitUntil(p: TPromise<any>): void;
}

254 255
export interface ITextFileService extends IDisposable {
	_serviceBrand: any;
B
Benjamin Pasero 已提交
256 257 258 259

	readonly onAutoSaveConfigurationChange: Event<IAutoSaveConfiguration>;
	readonly onFilesAssociationChange: Event<void>;

260 261
	onWillMove: Event<IWillMoveEvent>;

B
Benjamin Pasero 已提交
262
	readonly isHotExitEnabled: boolean;
263 264 265 266

	/**
	 * Access to the manager of text file editor models providing further methods to work with them.
	 */
B
Benjamin Pasero 已提交
267
	readonly models: ITextFileEditorModelManager;
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293

	/**
	 * Resolve the contents of a file identified by the resource.
	 */
	resolveTextContent(resource: URI, options?: IResolveContentOptions): TPromise<IRawTextContent>;

	/**
	 * A resource is dirty if it has unsaved changes or is an untitled file not yet saved.
	 *
	 * @param resource the resource to check for being dirty. If it is not specified, will check for
	 * all dirty resources.
	 */
	isDirty(resource?: URI): boolean;

	/**
	 * Returns all resources that are currently dirty matching the provided resources or all dirty resources.
	 *
	 * @param resources the resources to check for being dirty. If it is not specified, will check for
	 * all dirty resources.
	 */
	getDirty(resources?: URI[]): URI[];

	/**
	 * Saves the resource.
	 *
	 * @param resource the resource to save
294
	 * @param options optional save options
295
	 * @return true if the resource was saved.
296 297 298 299
	 */
	save(resource: URI, options?: ISaveOptions): TPromise<boolean>;

	/**
300
	 * Saves the provided resource asking the user for a file name or using the provided one.
301 302
	 *
	 * @param resource the resource to save as.
303 304
	 * @param targetResource the optional target to save to.
	 * @param options optional save options
305
	 * @return true if the file was saved.
306
	 */
307
	saveAs(resource: URI, targetResource?: URI, options?: ISaveOptions): TPromise<URI>;
308 309 310 311 312 313 314

	/**
	 * Saves the set of resources and returns a promise with the operation result.
	 *
	 * @param resources can be null to save all.
	 * @param includeUntitled to save all resources and optionally exclude untitled ones.
	 */
315 316
	saveAll(includeUntitled?: boolean, options?: ISaveOptions): TPromise<ITextFileOperationResult>;
	saveAll(resources: URI[], options?: ISaveOptions): TPromise<ITextFileOperationResult>;
317 318 319 320 321 322 323

	/**
	 * Reverts the provided resource.
	 *
	 * @param resource the resource of the file to revert.
	 * @param force to force revert even when the file is not dirty
	 */
324
	revert(resource: URI, options?: IRevertOptions): TPromise<boolean>;
325 326 327 328

	/**
	 * Reverts all the provided resources and returns a promise with the operation result.
	 */
329
	revertAll(resources?: URI[], options?: IRevertOptions): TPromise<ITextFileOperationResult>;
330

B
Benjamin Pasero 已提交
331 332 333
	/**
	 * Delete a file. If the file is dirty, it will get reverted and then deleted from disk.
	 */
334
	delete(resource: URI, options?: { useTrash?: boolean, recursive?: boolean }): TPromise<void>;
B
Benjamin Pasero 已提交
335 336 337 338 339 340

	/**
	 * Move a file. If the file is dirty, its contents will be preserved and restored.
	 */
	move(source: URI, target: URI, overwrite?: boolean): TPromise<void>;

341 342 343 344 345 346
	/**
	 * Brings up the confirm dialog to either save, don't save or cancel.
	 *
	 * @param resources the resources of the files to ask for confirmation or null if
	 * confirming for all dirty resources.
	 */
347
	confirmSave(resources?: URI[]): TPromise<ConfirmResult>;
348 349 350 351 352 353 354 355 356 357

	/**
	 * Convinient fast access to the current auto save mode.
	 */
	getAutoSaveMode(): AutoSaveMode;

	/**
	 * Convinient fast access to the raw configured auto save settings.
	 */
	getAutoSaveConfiguration(): IAutoSaveConfiguration;
I
isidor 已提交
358
}