textfiles.ts 10.9 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

6
import { URI } from 'vs/base/common/uri';
M
Matt Bierner 已提交
7
import { Event } from 'vs/base/common/event';
J
Johannes Rieken 已提交
8
import { IDisposable } from 'vs/base/common/lifecycle';
9
import { IEncodingSupport, ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor';
B
Benjamin Pasero 已提交
10
import { IReadTextFileOptions, ITextSnapshot, IBaseStatWithMetadata, IWriteTextFileOptions, IFileStatWithMetadata, IResourceEncodings } from 'vs/platform/files/common/files';
11
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
J
Joao Moreno 已提交
12
import { ITextEditorModel } from 'vs/editor/common/services/resolverService';
13
import { ITextBufferFactory, ITextModel } from 'vs/editor/common/model';
I
isidor 已提交
14
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
15

B
Benjamin Pasero 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
export const ITextFileService = createDecorator<ITextFileService>('textFileService');

export interface ITextFileService extends IDisposable {

	_serviceBrand: ServiceIdentifier<any>;

	readonly onWillMove: Event<IWillMoveEvent>;

	readonly onAutoSaveConfigurationChange: Event<IAutoSaveConfiguration>;

	readonly onFilesAssociationChange: Event<void>;

	readonly isHotExitEnabled: boolean;

	/**
	 * Access to the manager of text file editor models providing further methods to work with them.
	 */
	readonly models: ITextFileEditorModelManager;

	/**
	 * Helper to determine encoding for resources.
	 */
	readonly encoding: IResourceEncodings;

	/**
	 * 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
	 * @param options optional save options
	 * @return true if the resource was saved.
	 */
	save(resource: URI, options?: ISaveOptions): Promise<boolean>;

	/**
	 * Saves the provided resource asking the user for a file name or using the provided one.
	 *
	 * @param resource the resource to save as.
	 * @param targetResource the optional target to save to.
	 * @param options optional save options
	 * @return Path of the saved resource.
	 */
	saveAs(resource: URI, targetResource?: URI, options?: ISaveOptions): Promise<URI | undefined>;

	/**
	 * 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.
	 */
	saveAll(includeUntitled?: boolean, options?: ISaveOptions): Promise<ITextFileOperationResult>;
	saveAll(resources: URI[], options?: ISaveOptions): Promise<ITextFileOperationResult>;

	/**
	 * 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
	 */
	revert(resource: URI, options?: IRevertOptions): Promise<boolean>;

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

	/**
	 * Create a file. If the file exists it will be overwritten with the contents if
	 * the options enable to overwrite.
	 */
	create(resource: URI, contents?: string | ITextSnapshot, options?: { overwrite?: boolean }): Promise<IFileStatWithMetadata>;

	/**
	 * Read the contents of a file identified by the resource.
	 */
B
Benjamin Pasero 已提交
106
	read(resource: URI, options?: IReadTextFileOptions): Promise<ITextFileContent>;
B
Benjamin Pasero 已提交
107

108 109 110 111 112
	/**
	 * Read the contents of a file identified by the resource as stream.
	 */
	readStream(resource: URI, options?: IReadTextFileOptions): Promise<ITextFileStreamContent>;

B
Benjamin Pasero 已提交
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
	/**
	 * Update a file with given contents.
	 */
	write(resource: URI, value: string | ITextSnapshot, options?: IWriteTextFileOptions): Promise<IFileStatWithMetadata>;

	/**
	 * Delete a file. If the file is dirty, it will get reverted and then deleted from disk.
	 */
	delete(resource: URI, options?: { useTrash?: boolean, recursive?: boolean }): Promise<void>;

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

	/**
	 * 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.
	 */
	confirmSave(resources?: URI[]): Promise<ConfirmResult>;

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

	/**
	 * Convinient fast access to the raw configured auto save settings.
	 */
	getAutoSaveConfiguration(): IAutoSaveConfiguration;
}

147
/**
N
Nick Schonning 已提交
148
 * The save error handler can be installed on the text file editor model to install code that executes when save errors occur.
149 150 151 152 153 154
 */
export interface ISaveErrorHandler {

	/**
	 * Called whenever a save fails.
	 */
B
Benjamin Pasero 已提交
155
	onSaveError(error: Error, model: ITextFileEditorModel): void;
156 157 158 159 160 161 162
}

export interface ISaveParticipant {

	/**
	 * Participate in a save of a model. Allows to change the model before it is being saved to disk.
	 */
163
	participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise<void>;
164 165 166
}

/**
N
Nick Schonning 已提交
167
 * States the text file editor model can be in.
168
 */
169
export const enum ModelState {
B
Benjamin Pasero 已提交
170 171 172 173

	/**
	 * A model is saved.
	 */
174
	SAVED,
B
Benjamin Pasero 已提交
175 176 177 178

	/**
	 * A model is dirty.
	 */
179
	DIRTY,
B
Benjamin Pasero 已提交
180 181 182 183

	/**
	 * A model is transitioning from dirty to saved.
	 */
184
	PENDING_SAVE,
185 186 187 188 189

	/**
	 * A model is in conflict mode when changes cannot be saved because the
	 * underlying file has changed. Models in conflict mode are always dirty.
	 */
190
	CONFLICT,
191 192 193 194 195 196 197 198 199 200

	/**
	 * 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.
	 */
201 202 203
	ERROR
}

204
export const enum StateChange {
205 206 207 208 209
	DIRTY,
	SAVING,
	SAVE_ERROR,
	SAVED,
	REVERTED,
210
	ENCODING,
211 212
	CONTENT_CHANGE,
	ORPHANED_CHANGE
213 214 215 216 217
}

export class TextFileModelChangeEvent {
	private _resource: URI;

B
Benjamin Pasero 已提交
218
	constructor(model: ITextFileEditorModel, private _kind: StateChange) {
219 220 221
		this._resource = model.getResource();
	}

B
Benjamin Pasero 已提交
222
	get resource(): URI {
223 224 225
		return this._resource;
	}

B
Benjamin Pasero 已提交
226
	get kind(): StateChange {
227 228 229 230
		return this._kind;
	}
}

I
isidor 已提交
231
export const AutoSaveContext = new RawContextKey<string>('config.files.autoSave', undefined);
232 233 234 235 236 237 238 239 240 241 242 243

export interface ITextFileOperationResult {
	results: IResult[];
}

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

export interface IAutoSaveConfiguration {
M
Matt Bierner 已提交
244
	autoSaveDelay?: number;
245 246 247 248
	autoSaveFocusChange: boolean;
	autoSaveApplicationChange: boolean;
}

249
export const enum AutoSaveMode {
250 251 252 253 254 255 256
	OFF,
	AFTER_SHORT_DELAY,
	AFTER_LONG_DELAY,
	ON_FOCUS_CHANGE,
	ON_WINDOW_CHANGE
}

257
export const enum SaveReason {
258 259 260 261 262 263
	EXPLICIT = 1,
	AUTO = 2,
	FOCUS_CHANGE = 3,
	WINDOW_CHANGE = 4
}

264
export const enum LoadReason {
265 266 267 268 269
	EDITOR = 1,
	REFERENCE = 2,
	OTHER = 3
}

270
interface IBaseTextFileContent extends IBaseStatWithMetadata {
271 272

	/**
273
	 * The encoding of the content if known.
274
	 */
275 276 277 278
	encoding: string;
}

export interface ITextFileContent extends IBaseTextFileContent {
279 280

	/**
281
	 * The content of a text file.
282
	 */
283 284 285 286 287 288 289 290 291
	value: string;
}

export interface ITextFileStreamContent extends IBaseTextFileContent {

	/**
	 * The line grouped content of a text file.
	 */
	value: ITextBufferFactory;
292 293
}

294
export interface IModelLoadOrCreateOptions {
295

296 297 298 299
	/**
	 * Context why the model is being loaded or created.
	 */
	reason?: LoadReason;
300 301 302 303

	/**
	 * The encoding to use when resolving the model text content.
	 */
304
	encoding?: string;
305 306

	/**
307 308 309 310 311 312
	 * 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.
313
	 */
314 315 316
	reload?: {
		async: boolean
	};
317 318 319 320 321

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

324 325
export interface ITextFileEditorModelManager {

B
Benjamin Pasero 已提交
326 327 328
	readonly onModelDisposed: Event<URI>;
	readonly onModelContentChanged: Event<TextFileModelChangeEvent>;
	readonly onModelEncodingChanged: Event<TextFileModelChangeEvent>;
329

B
Benjamin Pasero 已提交
330 331 332 333 334
	readonly onModelDirty: Event<TextFileModelChangeEvent>;
	readonly onModelSaveError: Event<TextFileModelChangeEvent>;
	readonly onModelSaved: Event<TextFileModelChangeEvent>;
	readonly onModelReverted: Event<TextFileModelChangeEvent>;
	readonly onModelOrphanedChanged: Event<TextFileModelChangeEvent>;
335

B
Benjamin Pasero 已提交
336 337 338 339
	readonly onModelsDirty: Event<TextFileModelChangeEvent[]>;
	readonly onModelsSaveError: Event<TextFileModelChangeEvent[]>;
	readonly onModelsSaved: Event<TextFileModelChangeEvent[]>;
	readonly onModelsReverted: Event<TextFileModelChangeEvent[]>;
340

M
Matt Bierner 已提交
341
	get(resource: URI): ITextFileEditorModel | undefined;
342 343 344

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

J
Johannes Rieken 已提交
345
	loadOrCreate(resource: URI, options?: IModelLoadOrCreateOptions): Promise<ITextFileEditorModel>;
346 347

	disposeModel(model: ITextFileEditorModel): void;
348 349
}

350
export interface ISaveOptions {
351
	force?: boolean;
352 353 354
	reason?: SaveReason;
	overwriteReadonly?: boolean;
	overwriteEncoding?: boolean;
355
	skipSaveParticipants?: boolean;
356
	writeElevated?: boolean;
357 358
}

359 360 361 362 363 364 365 366 367 368 369
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;
370 371 372 373 374

	/**
	 * Context why the model is being loaded.
	 */
	reason?: LoadReason;
375 376
}

377 378
export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport {

B
Benjamin Pasero 已提交
379 380
	readonly onDidContentChange: Event<StateChange>;
	readonly onDidStateChange: Event<StateChange>;
381

382 383
	getVersionId(): number;

384 385
	getResource(): URI;

386
	hasState(state: ModelState): boolean;
387

388
	getETag(): string | null;
389

390 391
	updatePreferredEncoding(encoding: string): void;

M
Matt Bierner 已提交
392
	save(options?: ISaveOptions): Promise<void>;
393

J
Johannes Rieken 已提交
394
	load(options?: ILoadOptions): Promise<ITextFileEditorModel>;
B
Benjamin Pasero 已提交
395

J
Johannes Rieken 已提交
396
	revert(soft?: boolean): Promise<void>;
397

398
	createSnapshot(): ITextSnapshot | null;
399

400 401
	isDirty(): boolean;

402 403
	isResolved(): boolean;

404 405 406
	isDisposed(): boolean;
}

407
export interface IResolvedTextFileEditorModel extends ITextFileEditorModel {
408
	readonly textEditorModel: ITextModel;
M
Matt Bierner 已提交
409 410

	createSnapshot(): ITextSnapshot;
411 412
}

413 414 415
export interface IWillMoveEvent {
	oldResource: URI;
	newResource: URI;
416

417
	waitUntil(p: Promise<unknown>): void;
418
}